我与二维码的故事,是从一张扫不出来的二维码开始的。
如下图:
这是一张我们的app,无法识别的二维码
上面的这张二维码,我们的Android APP很难扫描出来。
我试了 微信、华为浏览器、ios 客户端等大厂app,不管是正着扫,歪着扫、躺着扫,跪着扫。。。。不管怎么扫基本都能一次成功。
我们二维码解析使用的是ZXing。我试了demo也是一样的情况。看来如果想要解决这个问题,需要去阅读甚至修改Google大佬们的代码,这件事情我本来是不敢去尝试的。
幸亏关键时刻,我想起来我大哥——江湖上鼎鼎有名的 瑞幸--雷彦祖 所过的一句话:
遇到技术难题就不去解决,到最后只能
雷彦祖 语录1
看来是时候展示真正的技术了。
一 物理相机采集图像数据
首先先来看看,当我们使用摄像头扫描二维码的时候,究竟在发生了些什么事情。二维码的解析数据是从相机反馈回来的:
初始化打开摄像头
摄像头通过聚焦等操作,不断将预览数据以YUV的格式反馈给ZXing.
回调返回摄像头的预览数据。
二 ZXing接盘YUV数据,进行解析操作
开始解析
拿到YUV数据之后,首先做两件事:
第一件就是把图像旋转90度,这个是因为android摄像头默认方向是横屏的,与用户习惯不符。
第二件事,就是根据YUV图像创建亮度源。
构建亮度图
走到这,如果想要看的懂后续流程,需要引入一个图像方面的概念了。
什么是YUV格式:
YUV格式 分辨是 Y 明亮度,U 色度 V浓度。
这种格式有两个好吃:方便切换且节省带宽, 因此无线电视一般都采用这种格式。
当数据色彩数据(UV)移除时,就是完整的黑白影像,不需要做什么特殊的处理。
在android 平台上一般采用的YUV420格式。以此为例: 一帧一像素RGB格式,需要占用3字节带宽。而 YUV420 只需要1.5字节长度的带宽。
与大家熟悉的ARGB等格式不同,YUV420格式的储存方式是这样的(多个连续的Y像素,公用一组UV像素):
YUV420格式
我们这里探究的是二维码的识别过程,对于YUV有所了解就可以了。如果想要知道更多的内容具体可以查看这篇MSDN文档:
https://msdn.microsoft.com/en-us/library/aa904813
雷彦祖 语录2
三 对YUV格式的图像进行二值化操作
大家都看的出来,二维码上真正有意义的内容是那些黑色的符号部分,所以我们需要对捕捉到的图像,进行二值化操作。
二
所谓的二值化,就是把在我们捕捉到的图像上拆成两部分,一部分是白的,另外一部分是黑的。
整个图像上的所有像素 要进行分类:非黑即白。
当我们在晚上扫描二维码的时候,因为整体灰度值都很低,黑色的二维码像素很有可能被当做白色数据扔掉,也就是光源不足时,二维码扫描失败的主要原因。
ZXing自带的二值化解析器有两种,我们采用的是相对保守,对低端设备支持较好的GlobalHistogramBinarizer解析器。
</