2021SC@SDUSC
本篇博客将用在博客(三)-(八)中学习到的知识,通过实例更深入的理解解码步骤,并对2021SC@SDUSC-Zxing(二)中提到的问题及新发现的问题进行解答。
解码实例
1.LuminanceSource
第一步,将图片传入LuminanceSource,获取灰度图片。
测试代码如下:
@Test
public void testBufferedImageLuminanceSource() throws IOException {
InputStream ins=new FileInputStream("D:/ZxingImage/mess2.jpg");
BufferedImage image = ImageIO.read(ins);
//获取图像的宽高信息
System.out.println("width:"+image.getWidth()+",heigth:"+image.getHeight());
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
//这里修改了BufferedImageLuminanceSource原来封装好的属性权限,这样是非常不规范的,仅为更直观的了解输出中间结果使用。
BufferedImage imageout=source.getImage();
File file = new File("D://ZxingImage//BufferedImageLuminanceSource_out.jpg");
if(!file.exists()){
//文件不存在则创建
file.createNewFile();
}
ImageIO.write(imageout,"JPEG",file);
System.out.println("二维码生成成功");
}
通过这一步,我们成功获得了一个灰度图片。
后台输出,第一行是原图信息,第二行是输出图像信息:
2.Binarizer
第二步,将灰度图片传入Binarizer,对图像进行去噪处理、获得阈值、像素值(亮度数据)转换为1位数据(二值化处理)。
转为1位数据:
当前展示的后台输出的部分大概在图像的这个位置,在后台输出中找二维码部分不好找(从上面的图中我们也可以看到图片被放大到了原来的345%),但是这个图片也已经能说明问题了:
测试代码如下:
@Test
public void testBufferedImageLuminanceSource() throws IOException, NotFoundException {
InputStream ins=new FileInputStream("D:/ZxingImage/mess2.jpg");
BufferedImage image = ImageIO.read(ins);
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
HybridBinarizer binarizer = new HybridBinarizer(source);
System.out.println("BlackMatrix:\n"+binarizer.getBlackMatrix()+"\nWidth:"+binarizer.getWidth()+"\nheight:"+binarizer.getHeight());
}
后台输出:
至于输出为什么是“ ”和“X”,BitMatrix的toString是这样的,表示只会有这两种输出:
@Override
public String toString() {
return toString("X ", " ");
}
而选择“ ”、“X”的哪一个,逻辑如下:
//为true表示黑色
public boolean get(int x, int y) {
int offset = y * rowSize + (x / 32);
return ((bits[offset] >>> (x & 0x1f)) & 1) != 0;
}
接着,这个语句给获取请求的位赋值,如果是黑色,就是setString,反之unsetString,然后通过参数的方式将“X”与setString关联,“ ”与unsetString关联。
result.append(get(x, y) ? setString : unsetString);
Zxing中去噪完成后,没有获取图像,因为去噪的图像对我们解码没有什么帮助,去完噪紧接着就转为1位数据图像了。阈值也是,只是一个中间步骤,代码逻辑在2021SC@SDUSC-Zxing(五):解码关键类详解-Binarizer中已讲解。
3.BinaryBitmap
第三步,对上一步获得的位数据进行进一步维护。
可以看出,BinaryBitmap和LuminanceSource的方法在功能上其实有很多重叠(如是否能旋转、是否能裁剪),但是正如2021SC@SDUSC-Zxing(三):解码相关代码中流程图展示的那样,LuminanceSource操作的是图片,BinaryBitmap操作的是1位数据而非图片。要注意的是,在这一步我们还没有进行裁剪和旋转等操作。
测试代码如下:
@Test
public void testBufferedImageLuminanceSource() throws IOException, NotFoundException {
InputStream ins=new FileInputStream("D:/ZxingImage/mess2.jpg");
BufferedImage image = ImageIO.read(ins);
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
HybridBinarizer binarizer = new HybridBinarizer(source);
BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
System.out.println("BlackMatrix:\n"+binaryBitmap.getBlackMatrix()+"Width:"+binaryBitmap.getWidth()+"\nheight:"+binaryBitmap.getHeight());
}
后台输出:
4.Reader
第四步,通过Reader开始解码。
前几步的操作都是为了这一步做准备,这一步是解码的重中之重。
测试代码:
@Test
public void testBufferedImageLuminanceSource() throws IOException, NotFoundException, ChecksumException, FormatException {
InputStream ins=new FileInputStream("D:/ZxingImage/mess2.jpg");
BufferedImage image = ImageIO.read(ins);
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
HybridBinarizer binarizer = new HybridBinarizer(source);
BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer);
QRCodeReader reader = new QRCodeReader();
//这里为了演示也是把QRCodeReader的private方法extractPureBits设置成public了
BitMatrix bt= reader.extractPureBits(binaryBitmap.getBlackMatrix());
System.out.println("reader:"+bt+"\nw:"+bt.getWidth()+"\nh:"+bt.getHeight());
System.out.println("解码结果:"+reader.decode(binaryBitmap));
}
这里我们没有用2021SC@SDUSC-Zxing(二):Zxing运行(Springboot)解码demo中提到的MultiFormatReader,因为这个类它尝试解码库支持的所有条形码格式,而我们现在知道解码的是QR码,因此就直接用QR码的解码器了。具体介绍可以看2021SC@SDUSC-Zxing(七):解码关键类详解-Reader
后台输出,显然这个宽高是被裁剪过的,但也不是生成demo中设置的300 * 300。通过查看“X”、“ ”阵列图片,也可以发现图片被旋转了。为什么大小不是 300 * 300?因为这个宽高已经可以满足Zxing的裁剪需求了,因此没有继续裁剪。
通过这个555*555的输出可以容易的找到二维码:
2021SC@SDUSC-Zxing(二):Zxing运行(Springboot)生成二维码时设置的大小
下图为未经放缩的原图像素点位置,红点是二维码四个顶点,绿点是输出的四个定位点。可以看出原图中的大小依旧是300 * 300(手动标注存在误差)。
5.Result
第五步,输出解码结果。
这一步在第四步的输出中已经体现,在代码中的实现为:
Result result = reader.decode(binaryBitmap, hints);
String content = result.getText();
Result中会存放定位点的信息,这个信息会传给安卓端,这也是为什么最开始的扫码图像会在对应位置有绿色的方块
欢迎提出宝贵意见,感谢观看!
参考: ZxingAPI