二维码扫描优化


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冗余代码。code

  • 将处理相机帧从串行改成并行。orm

交互体验优化包括:cdn

  • 自动放大。blog

  • 双击放大。

  • 重力传感器聚焦。

  • 手势调整焦距。


去除zxing额外支持的格式

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

其中,readers变量是一个数组,数组的大小表示支持的条码格式个数,zxing本来由于支持不少格式,所以这个数组长度比较长。当拿到相机的一帧数据后,须要去检测是不是全部支持格式的某一个格式,每一种格式的检测都须要花费一些时间,所以这个遍历对于Lark是没必要要的。若是将zxing内部定制成只支持QR Code格式,那么就免去了额外的格式检测。


删除zxing冗余代码

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

  • 删除zxing除了二维码以外的格式的相关代码,zxing对每种格式的相关代码都放在各自的目录中,所以咱们只须要把这些格式对应的目录删除便可,好比aztec、maxicode等。

  • 删除二维码的encode相关代码,即"qrcode/encoder"目录。

  • 删除decode后文本的解析相关类(好比地址、通信录、邮件等解析类),只保留URI、URL、Text。

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


将处理相机帧从串行改成并行

本来Lark扫一扫的逻辑是串行的,以下图:

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

缺点是若是处理一帧数据时间很长,会阻碍下一帧的处理,好比上一帧是没有二维码的,而下一帧是有二维码的,若是上一帧处理时间较长,那么虽然用户对准了二维码,可是实际处理的仍是上一帧,所以不太合理。

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


自动放大

当二维码很小很远时,自动放大能大大加快检测二维码的速度。QRCodeReader的decode( ) 是二维码检测的主方法,分为两步:(1)大体判断是否存在二维码;(2)解码。

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

具体二维码的原理参见:二维码的生成细节和原理(见原文连接)

咱们实现了zoomCamera( ),若是判断须要放大,则返回true,若是不须要放大,则返回false。代码以下:

咱们在第一步和第二步中间插入该方法,若是须要放大,则不执行第二步;若是二维码已经足够大,则执行第二步。代码以下:


双击放大

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


重力传感器聚焦

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


手势调整焦距

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

优化结果

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


上图表示了从打开相机到二维码解码成功的耗时,能够看出,总体时间提高了300%+ 。

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

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

相关文章
相关标签/搜索