使用微信能够识别的图片,为何使用zxing却不能识别

背景

最近有个应用须要在服务端解析图片中的二维码,网上查了一下,几乎全是用google zxing的实现。可是测试过程当中发现,这玩意比较坑,不少在微信里长按能识别的图片,使用zxing却识别不出来。 因而乎开始了纠结的过程!!!! 搞不懂为啥网上一直没解决方法~~~~~(虽然不少人在问!! 国外也有人在问!!!!),你们都是不求甚解,只能copy代码?? 最终仍是本身动手吧!!android

 

给张测试图算法

 

 

 

 

过程

  • google一下

google了好久, 在stackoveflow上找到了一个描述!!大概是说“图片不能超过某个大小”, 结果误导了我!!  将2448x3264的图片缩小到了1500x2000的尺寸,结果还真识别出来了。 因而乎我觉得问题解决了,识别时我加了一个超出尺寸缩放的逻辑!! 过了一天,再测试,发现仍是不少图片识别不出来!! 看来歪果仁也不靠谱微信

  • 怀疑色差致使的,因而将图片转成灰阶,将偏黑色的全置成“黑色”,其它的全置为白色,这样就获得了一个“黑白图片”。  失败!!!!

 

    private static BufferedImage toGrayImage(BufferedImage image) {
        BufferedImage result = image;
        if (BufferedImage.TYPE_BYTE_GRAY != image.getType()) {
            BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
            newImage.getGraphics().drawImage(image, 0, 0, null);
            result = newImage;
        }
        Raster raster = result.getRaster();
        DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
        byte[] data = buffer.getData();
        for (int i = 0; i < data.length; i++) {
            byte value = 0;
            if (data[i] < 32) {
                value = -1;
            }
            buffer.setElem(i, value);
        }
        return result;
    }


  •  怀疑是zxing自己算法问题。

https://zxing.org/w/decode.jspx  这个网站能够直接上传图片,再使用zxing提取结果。 发现这个网站也不行!!! 难道真的有问题?    而后尝试使用其它的一些API,结果还真没找出靠谱的API来。app

  • 确认zxing没问题

偶然间下载了一个使用zxing的android app,该app能够调用摄像头扫描二维码。 而这个app扫描电脑上显示的图片是没有问题的, 这间接证实了zxing多是没有 问题的。 有了对的例子参照就好,照着改就好了。 而后看了一下Android调用摄像头扫描的代码,按照里面的参数都调整了一下,仍是失败  !!!! jsp

    • 因而放了一个大招!!!  仿APP的扫描逻辑, 按不一样比例、一块地遍历图片扫描! 有GIS的底子,写这些算法仍是挺快的 ^_^  结果仍是失败!  
    • 接着将android扫描的结果保存成了图片,对比了一下,也没发现因此然来。快要崩溃了!!
    • FINAL:忽然想到,Android里扫描的图片其实和真实的图片是有差异的, Android里是摄像头拍屏幕“获得”的,拍到的结果确定比实际的图片“模糊”!!   

而后我将灰阶处理过的黑白图放大后仔细分析了一下,发现下面的图片其实有不少“杂点”,而手机扫描时,这些“杂点”却被模糊看不出来了。  ,思路出来了!!!! 须要将图片里面影响识别的“杂点”给模糊处理! 再联想到stackoverflow上的一次成功例子,,模糊嘛,将图片缩小不就模糊了。
  工具

 

 

最终处理方法

zxing在识别高清的手机图时,将图片逐步缩小,并扫描!!  就这么简单!!!!! 测试

下面是代码,测试了好几个图片均可以识别的, 过程有些纠结哎!!!网站

 

/**
 * QR 二维码工具。
 * 
 * @author liuyixin
 */
public class QRCodeUtil {
	private static final int MAX_QRCODE_SIXE = 1500;

	public static String readToString(BufferedImage sourceImage) {
		BufferedImage image = toGrayImage(sourceImage);
		if (sourceImage.getWidth() > MAX_QRCODE_SIXE && sourceImage.getHeight() > MAX_QRCODE_SIXE) {// second
			image = resizeToMaxSize(sourceImage);
		}
		String result = readDirectly(image);
		if (StringUtils.isNotBlank(result)) {
			return result;
		}
		int minSize = 170;
		int imgSize = Math.min(image.getWidth(), image.getHeight());
		int level = 1;
		while (imgSize > minSize) {
			BufferedImage newImage = new BufferedImage((int) (image.getWidth() * Math.pow(0.9, level)),
					(int) (image.getHeight() * Math.pow(0.9, level)), image.getType());
			newImage.getGraphics().drawImage(image, 0, 0, newImage.getWidth(), newImage.getHeight(), 0, 0, image.getWidth(),
					image.getHeight(), null);
			result = readDirectly(newImage);
			if (StringUtils.isNotBlank(result)) {
				return result;
			}
			imgSize = Math.min(newImage.getWidth(), newImage.getHeight());
			level++;
		}
		return "";
	}

	/**
	 * 将图片转成灰阶。
	 * 
	 * @param image
	 * @return
	 */
	private static BufferedImage toGrayImage(BufferedImage image) {
		BufferedImage result = image;
		if (BufferedImage.TYPE_BYTE_GRAY != image.getType()) {
			BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
			newImage.getGraphics().drawImage(image, 0, 0, null);
			result = newImage;
		}
		/*黑白处理
Raster raster = result.getRaster();
		DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
		byte[] data = buffer.getData();
		for (int i = 0; i < data.length; i++) {
			byte value = 0;
			if (data[i] < 32) {
				value = -1;
			}
			buffer.setElem(i, value);
		}*/
		return result;
	}

	/**
	 * 图片若过大,则缩放图片。
	 * 
	 * @param image
	 * @return
	 */
	private static BufferedImage resizeToMaxSize(BufferedImage image) {
		int height = MAX_QRCODE_SIXE;
		int width = MAX_QRCODE_SIXE;
		if (image.getWidth() > image.getHeight()) {
			width = (int) (height * (((double) image.getWidth()) / image.getHeight()));
		} else {
			height = (int) (width * (((double) image.getHeight()) / image.getWidth()));
		}
		BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
		newImage.getGraphics().drawImage(image, 0, 0, newImage.getWidth() + 1, newImage.getHeight() + 1, 0, 0, image.getWidth(),
				image.getHeight(), null);
		return newImage;
	}

	private static String readDirectly(BufferedImage image) {
		LuminanceSource source = new BufferedImageLuminanceSource(image);
		Binarizer binarizer = new HybridBinarizer(source);
		BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
		Map<DecodeHintType, Object> hints = new HashMap<DecodeHintType, Object>();
		hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
		try {
			return new MultiFormatReader().decode(binaryBitmap, hints).getText();
		} catch (NotFoundException e) {
			return "";
		}
	}
}
相关文章
相关标签/搜索