Dragon
  非凡社群营销服务平台专注于社群管理,社群裂变,多群同步直播,企业微信SCRM系统。欢迎合作咨询;客服微信11112751

二维码扫描优化

2021-03-11 09:01 25 微信机器人

前言

zxing 是一款跨平台的基于 Java 实现的处理一维或二维条码的库。支持多种格式,一维条码支持 UPC-A,UPC-E,EAN-8,Code 39,Code 93 等格式,二维条码支持 QR Code,Data Matrix,PDF 417,MaxiCode 等格式。

上述的二维条码指的是较宽泛的二维条码,而不是 QR Code 表示的二维码。

原本 Lark 直接集成了 zxing 实现扫一扫功能。由于 Lark 的特殊业务需求,因此并不需要支持到这么多格式,只需要支持 QR Code,因此我们对 zxing 内部进行定制,使得 zxing 只支持 QR Code。这样既可以减少 zxing 库的大小,也可以加快 zxing 处理一帧数据的速度。

优化主要包含两方面:(1)扫描性能(2)交互体验。

扫描性能优化包括:

  • 去除 zxing 额外支持的格式。
  • 删除 zxing 冗余代码。
  • 将处理相机帧从串行改为并行。

交互体验优化包括:

  • 自动放大。
  • 双击放大。
  • 重力传感器聚焦。
  • 手势调整焦距。

1. 去除 zxing 额外支持的格式

MultiFormatReader 的 decodeWithState()是使用方的入口方法,内部调用了 decodeInternal(),输入是相机的一帧数据,如果抛了 NotFoundException,则表示没找到二维码;如果返回了 Result,则表示找到了二维码,并解析完成。代码如下:

二维码扫描优化

其中,readers 变量是一个数组,数组的大小表示支持的条码格式个数,zxing 原本因为支持很多格式,因此这个数组长度比较长。当拿到相机的一帧数据后,需要去检测是否是所有支持格式的某一个格式,每一种格式的检测都需要花费一些时间,因此这个遍历对于 Lark 是不必要的。如果将 zxing 内部定制成只支持 QR Code 格式,那么就免去了额外的格式检测。

2. 删除 zxing 冗余代码

我们主要从几方面删除冗余代码:

  • 删除 zxing 除了二维码之外的格式的相关代码,zxing 对每种格式的相关代码都放在各自的目录中,因此我们只需要把这些格式对应的目录删除即可,比如 aztec、maxicode 等。
  • 删除二维码的 encode 相关代码,即"qrcode/encoder"目录。
  • 删除 decode 后文本的解析相关类(比如地址、通讯录、邮件等解析类),只保留 URI、URL、Text。

通过以上方式,zxing 文件数量从 263 个缩减到 67 个,库大小从 1.8M 缩减到 451K,效果非常明显。

3. 将处理相机帧从串行改为并行

原本 Lark 扫一扫的逻辑是串行的,如下图:

二维码扫描优化

每次从 onPreviewFrame()中获取一帧数据,然后调用 zxing 的 decode 解析二维码,如果成功,则返回;如果失败,则调用 setOneShotPreviewCallback()重新调用一次 onPreviewFrame()。

缺点是如果处理一帧数据时间很长,会阻碍下一帧的处理,比如上一帧是没有二维码的,而下一帧是有二维码的,如果上一帧处理时间较长,那么虽然用户对准了二维码,但是实际处理的还是上一帧,因此不太合理。

我们将串行处理改成并行处理,一旦从 onPreviewFrame()获取一帧数据,将 decode 任务丢进线程池,并立即调用 setOneShotPreviewCallback()获取下一帧数据。一旦某个任务检测到二维码,立即将 isSuccess 变量置为 true,忽略其他任务。这样能够大大加快二维码检测的速度。

4. 自动放大

当二维码很小很远时,自动放大能大大加快检测二维码的速度。

QRCodeReader 的 decode()是二维码检测的主方法,分为两步:(1)大致判断是否存在二维码;(2)解码。

二维码扫描优化

第一步只是检测是否存在二维码,比如去寻找是否存在 Position Detection Pattern,Timing Pattern,Alignment Pattern。如果检测到了,则返回 DetectorResult,内部包含了定位点的位置信息;如果没检测到,则抛出 NotFoundException。如果二维码很小,即使第一步检测存在二维码,但是第二步解码也可能会失败。由于我们在第一步已经能够知道二维码的大小,因此根据 DetectorResult 返回的二维码定位点信息计算出二维码的大致宽度,然后判断二维码大小在扫码框中是否足够小,如果足够小,则放大一定焦距:如果小于十分之一,则放大到最大焦距;如果小于等于六分之一,则放大到最大焦距的一半。

具体二维码的原理参见: 。

我们实现了 zoomCamera(),如果判断需要放大,则返回 true,如果不需要放大,则返回 false。代码如下:

二维码扫描优化

我们在第一步和第二步中间插入该方法,如果需要放大,则不执行第二步;如果二维码已经足够大,则执行第二步。代码如下:

二维码扫描优化

5. 双击放大

原本 Lark 的二维码扫描中没有调整焦距的功能,这个对于一些特定场景下会不太方便,因此这里加入了双击放大的功能能够对焦距进行粗略的调整。利用 GestureDetector 的 onDoubleTap()回调捕捉用户双击事件,并在 CameraPreview 中的 onTouchEvent()中添加 mGestureDetector.onTouchEvent()。实现如下:

二维码扫描优化

6. 重力传感器聚焦

重力传感器能够捕捉用户手机的运动状态,当检测到用户手机停止时,触发对焦逻辑。我们通过实现 SensorEventListener 接口,并重写 onSensorChanged()监听手机的运动状态。

7. 手势调整焦距

为了更精细化的让用户调整焦距,我们提供了手势来缩放焦距。通过在 onTouchEvent()中获取用户两个手指的距离是越来越近还是越来越远来调整焦距。代码如下:

二维码扫描优化

优化结果

经过上述优化,不仅增加了用户体验,而且还大幅增加了二维码扫描速度。 测试手机:坚果 Pro,4G 内存,Android 7.1.1。

二维码扫描优化

上图表示了从打开相机到二维码解码成功的耗时,可以看出,整体时间提升了 300%+。

二维码扫描优化

上图表示检测失败时的耗时指的是当相机帧中没有二维码时检测的时间,检测失败耗时的减少有助于更快地处理相机帧数据,当包含二维码的帧出现时更快地处理它;上图中看出,耗时减少 300%+。

二维码扫描优化

上图表示检测成功时的耗时指的是当相机帧中有二维码时检测+解码的时间;上图中看出,耗时减少 150%+。

「点点赞赏,手留余香」

还没有人赞赏,快来当第一个赞赏的人吧!

非凡建群宝给非凡建群宝打赏
×
予人玫瑰,手有余香
  • 2
  • 5
  • 10
  • 20
  • 50
2
支付

本文来自投稿,不代表微信机器人立场,版权归原作者所有,欢迎分享本文,转载请保留出处!

2021-03-11

2021-03-11

×
Tips:非凡社群营销服务平台专注于社群管理,社群裂变,多群同步直播,企业微信SCRM系统。欢迎合作咨询;客服微信11112751