ScanMaster

More: Author   ReportBugs   
Tags:

二维码扫码优化

说明

在介绍二维码的优化前,可以参考二维码基础原理了解二维码识别的相关知识。 作者相关博客Android 二维码扫描优化

Contents 目录

概述

随着二维码的流行,几乎所有手持设备都支持二维码的扫描识别。对于大部分普通的情景下,使用 zxing 和 zbar 就可以很好的完成二维码的识别,但是如果碰到一些特殊的情景,zxing 和 zbar 的识别率并不高。这些特殊的情景包括:

  1. 二维码是灰色的
  2. 大角度斜扫二维码
  3. 由光源引发的摄像头干扰,比如手机扫描屏幕上的二维码会出现条纹或者噪点

普通优化

在介绍难点优化之前,先介绍网上常见的优化点。这些优化点同样被使用在了作者的项目中,具体包括:

解码优化

  1. 减少解码格式
  2. 解码算法优化
  3. 减少解码数据
  4. 解码库 Zbar 与 Zxing 融合

优化相机设置

  1. 选择最佳预览尺寸/图片尺寸
  2. 设置适合的相机放大倍数
  3. 调整聚焦时间
  4. 设置自动对焦区域
  5. 调整合理扫描区域

以上普通优化均参考自智能设备上的二维码解码优化, 不过作者在实现过程中,对该链接所对应的项目实现做了一些修改,修改点包括:

  1. 旋转 android 后置摄像头 preview 数据时,根据 yuv NV21 数据的特点进行旋转
  2. 摄像头预览数据中,对应预览框的数据的截取,并非通过 PlanarYUVLuminanceSource 创建时提供的 rect 进行截取。而是通过 opencv,将 yuv 数据转换成 rgb 之后,在进行截取
  3. 摄像头最佳预览尺寸选取时,按照设备屏宽,屏高最接近的方式选取,并没有通过屏幕宽高比进行筛选。因为部分 android 手机,屏幕的宽高比和摄像头所支持最接近的 size 的宽高比并不一致(ps:比如 nexus 4,屏幕宽高为 720/1280, 但是摄像头支持的最接近屏幕宽高比的 preview size,都要少几个像素,印象中,好像是 716/1276, 具体多少记不清了)
  4. 支持用户双指对摄像头进行缩放,并未采用链接引用项目的 zoom 策略
  5. 添加 zbar 结合 zxing 一起检测的代码

难点

整个二维码扫描识别过程中,个人认为最关键的一步在于图片的二值化处理。所谓二值化,可以简单理解为给定一个阈值,低于阈值的像素标记为白色,高于阈值的像素标记为黑色。一旦进行二值化后,图片形成黑白两色图,再利用二维码原理进行定位查询并识别解码并不困难。因此能否对一个图片进行正确的二值化极大影响二维码识别率。而以下特殊情况很大程度上会干扰扫描过程中二值化过程:

灰色二维码

如上图,某些二维码是灰色的,或者由于光照的情况下色调比较淡。灰色二维码识别难度在于背景往往比二维码的灰点色度更黑,当用手机对这类灰色二维码进行扫描时,总是或多或少会有一些非二维码的背景显示在扫描框中,而这部分背景由于色调比灰点深,这会造成 zxing,或者 zbar 二值化过程中选择阈值受到干扰,从而无法识别二维码

大角度对二维码进行扫描识别

在这种情况下如果是纯黑色的二维码影响不会太大,但如果是灰色的二维码,就非常容易受到光照的印象。 由于是斜着扫二维码,那么对于摄像头来说,二维码的两边所带来的亮度是不同的。

如上图例子,如果是从左侧进行扫描二维码,那么左边由于距离摄像头更近,因此更亮,而右边由于距离摄像头更远,会比较暗,此时整个预览框进行二值化时,非常容易造成右边暗的部分,全部超过阈值而被判断为黑色,进而极大影响二维码的识别

由光源引发的摄像头干扰,比如手机扫描屏幕上的二维码会出现条纹或者噪点

如果二维码位于电脑屏幕中,或者位于其他投影设备里,或者当时处于白炽灯等灯光照耀的情况下,进行扫描,摄像头有时候会受到光源频率的干扰,从而形成条纹状。而某些情况下,当摄像头 zoom 到一定程度是,形成的早点也会对二维码识别造成极大干扰,如下图所示作者遇到的情况:

这类情况,如果二维码是黑色的还好,如果二维码是灰色的,则条纹会对二维码的识别起到很大的干扰,如上边右侧图像所示

优化

针对上述难点,作者尝试通过 opencv 对相机的 preview 数据进行预处理,从而提升二维码的扫描识别,作者进行过的尝试如下:

尝试 1:通过 opencv 方法进行预览数据的降噪

作者本想通过 opencv 的各种降噪滤波算法(例如 mediaBlur 等),去光照算法(例如 RGB 归一化等)等对 camera 预览数据进行处理。可能是作者对于 opencv 算法理解还不足,也可能是其他原因,测试下来效果都不太好。最好作者选择 mediaBlur 作为降噪算法进行保留,对于一些椒盐噪点的去除还挺有帮助

尝试 2:缩小二值化阈值计算范围

考虑到灰色二维码之所以难以识别是因为背景的色调过暗,拉低了二值化阈值的计算,导致整个二维码的难以识别。因此作者将二值化阈值的计算区域缩小到预览框的 2/5,然后再通过计算的阈值对整个预览区域的数据进行二值化。这个效果对于灰色二维码的识别提升很大。可惜的是,只对正面扫描的情况下有用,一旦斜着超过一定角度扫描灰色二维码,往往识别不出。

尝试 3:分块对预览区进行二值化

考虑到斜扫二维码不好识别因为矩形预览区域各个部分的亮度不统一,因此作者下一步尝试是,将矩形预览框再次分成 4 个块,每个块取其靠近中心部分的 1/5 区域进行阈值计算,最后分块进行二值化后,拼接而成。具体如下示意图所示

之所以分块进行计算阈值,是考虑到不同区域的亮度是不同的,如果整体进行计算的话,会丢失部分有效信息。而之所以选取靠近中心的小部分进行阈值化计算,是因为用户行为通常会将二维码对准预览框的中心,因此中心部分,包含有效亮度信息更为精确,减少背景亮度对整体二值化的影响。这一步尝试之后,大大提升了特殊情景二维码的识别概率。至此,opencv 预处理部分到此结束了。

项目说明

项目分成 3 个 module

  • app app module 提供 demo activity

  • library_qrscan 二维码扫码核心功能,集成 zxing,zbar,opencv 预处理等功能

  • library_opencv 该 module 作为隐藏 module,setting 配置并没有 include 它,是方便调试 opencv 功能。该 module 可以用于生成 libProcessing.so,集成在 library_qrscan module 中。如果用户想使用该 module,请按照以下做法:

    1. 打开 setting 中配置,include 该 module
    2. 下载 opencv for android 版本到本地目录,并解压
    3. 修改 library_opencv/src/main/jni/Android.mk 中 12 行 include 对应本地 opencv 的 mk 路径
    4. 删除 library_qrscan/libs/armeabi-v7a/libProcessing.so
Apps
About Me
GitHub: Trinea
Facebook: Dev Tools