转自txx’s blog前言
这篇文章是我们在新发布的礼物说的iOS端开发过程中遇到的一些关于条形码的问题总结而来。

本文记录的问题是:当AVFoundation使用多译码器扫描的时候。二维码是秒杀,但是条形码却经常扫不上。如果去掉二维码的话,条形码扫描又秒杀的问题。

为什么我们没有选用ZXing而是用AVfoundation呢,是因为我说服了老板,iOS7开发,而不再去兼容iOS5/6。所以我们终于可以抛弃效率低下的ZXing,而选择AVFoundation。为什么说ZXing效率低下,我们这里可以说上几句。

ZXing
ZXing 是 Google Code上的一个开源的条形码扫描库,是用java设计的,连Google Glass 都在使用的。但有人为了追求更高效率以及可移植性,出现了c++ port. Github上的Objectivc-C port,其实就是用OC代码封装了一下而已,而且已经停止维护。

ZXing扫描,是拿到摄像头的每一帧,然后对其根据如下公式做灰度化

f(i,j)=0.30R(i,j)+0.59G(i,j)+0.11B(i,j))
之后做全局直方图二值化的方法,最后按照ISO/IEC 18004 规范进行解析。

这样效率非常低,在instrument下面可以看到CPU占用远远高于 AVFoundation。而且全局直方图二值化导致精准度并不高。这个库还会带来一大堆C++的东西,在纯iOS7的工程下,不推荐使用。

AVFoundation 扫码的简单使用

这里说一下,我们礼物说是和passbook一样,同时可以扫描二维码和条形码,真是因为这个特性,导致了我写这篇总结。 先粘一下扫码实现部份,如下。

  • (BOOL)startReading {
    _isReading = YES;
    NSError *error;
    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];

    if (!input) {
    NSLog(@”%@”, [error localizedDescription]);
    return NO;
    }

    _captureSession = [[AVCaptureSession alloc] init];
    // Set the input device on the capture session.
    [_captureSession addInput:input];

    AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
    [_captureSession addOutput:captureMetadataOutput];

    // Create a new serial dispatch queue.
    dispatch_queue_t dispatchQueue;
    dispatchQueue = dispatch_queue_create(“myQueue”, NULL);
    [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];

    if (self.qrcodeFlag)
    [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
    else
    [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObjects:AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeQRCode, nil]];

    _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    [_videoPreviewLayer setFrame:self.view.layer.bounds];
    [self.view.layer addSublayer:_videoPreviewLayer];

    [_captureSession startRunning];

    return YES;
    }

-(void)stopReading{
[_captureSession stopRunning];
_captureSession = nil;
[_videoPreviewLayer removeFromSuperlayer];
}

-(void)captureOutput:(AVCaptureOutput )captureOutput didOutputMetadataObjects:(NSArray )metadataObjects
fromConnection:(AVCaptureConnection *)connection
{
if (!_isReading) return;

if (metadataObjects != nil && [metadataObjects count] > 0) { AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0]; Do Something....
}

}
这个代码也不需要加什么注释,挺简单易懂的。

阐述问题
我们上面说过了:当AVFoundation使用多译码器扫描的时候。二维码是秒杀,但是条形码却经常扫不上。如果去掉二维码的话,条形码扫描又秒杀的问题。

但有趣的事情是,如果我写了个demo,用上述代码的话。却又可以秒杀扫描。这个问题困扰了我一下午,仔细对比了项目中的每一行代码和我demo中的全部。除了demo没有画一个提示框在屏幕上以外,其他地方全都一模一样。

那么为什么导致项目中扫描效率如此之慢呢?

猜想1: UI以及后台线程占用大量CPU时间

结果在 instrument下,不攻自破,cpu占用,内存占用非常非常低。

猜想2:系统架构问题

因为添加了QRCode才导致扫描变慢的,那么就应该是和算法效率有关。多引入了一个每一帧都要工作的译码器,导致条形码扫描效率下降。我的Demo是arm64 v7s v7 系统全支持,而项目是ArmV7。

这个想法挺异想天开的。觉得可能是Arm64的指令集效率比armv7快得多导致的。我还去问巧哥,armv7和arm64在密集运算的时候效率差多少,会不会比较明显。

但重新配置了一下,还是错误的。

插曲
我发现把屏幕横过来扫描效率比竖过来高多了。于是怀疑是不是 Capture 的方向问题。

猜想3: 摄像头方向问题导致解碼效率低

这个猜想,我没有去证实,因为太麻烦了。要给Session 添加一个新的output 来输出每一帧,而且还是个CMBuffer,还要手动转码。不过后面证实这个也是错的。

猜想4:摄像头参数问题

当初看AVCam 写拍照模块的时候,记得摄像头有很多参数,ZXing 也有一个文件位叫做精确解碼,牺牲效率换精确度。于是就在想会不会苹果家的也要设置参数。

于是就坏怀这个问题去看文档去了,结果歪打正着的发现了正确原因。 这是记录在苹果的FAQ中的,并没在AVFoundation 的 Reference 中。具体编号为:Technical Note TN2325

正确原因
就是描述问题里面说到的,demo和工程里面的唯一区别,多了个surfaceLayer。如下图:

为了正确解释这个有趣的问题,我们要解释一下条形码扫描原理。

上面有提过二维码是通过全局直方图二值化后,按照ISO标准解碼,实际上是,按照1:1:3:1:1去寻找那三个寻像图形,就是标志性的大方块。然后圈出二维码大小再去解碼的。也就是说,再没设定边界的情况下全屏都可以。

而条形码完全不同,他是在Detect Center那个点,画一个无限延伸的米字型,然后去判断每一条在线能否解析出条形码所需要的0101010序列。而iOS默认的Center是 Layer 的 Center。

我们再回过头来看工程中的 SurfaceLayer,其实他提示给用户的那个框,已经远离了Center。所以我们竖着扫描的时候,那条水平的扫描线是没有贯穿条形码的,所以扫不上他。

于是乎要根据设备,iPhone4 iPhone5 通过AVCaptureDeviceFormat和AVCaptureSessionPreset 重新设置一下AVCaptureMetadataOutput rectOfInterest,结果问题就解决了。

为什么去掉二维码就没事了呢?

还在那篇FAQ中,有那么一个表格。

可见,当我们没有二维码的时候,他会有个additional存在。用更加优秀且稍微耗时的算法去优化扫描精准度。

总结
1.当我们遇到问题的时候,不光要记得看 苹果的 guide 和 reference,还要记得看以下 sample code,tech note, FAQ。

2.说不好有意外收获 为什么条形码扫描仪上往往会有一条红线,这并不是为了拟物化,而是告诉用户一定要用这条线对准条形码,否则会有扫不上的可能性。

3.正如福尔摩斯所说:抛开所有不可能的,剩下的,不管多么令人匪夷所思,那都是事实。两套代码仅有UI不一样,效果不同,其实就是UI引导用户错误的使用了扫描仪。

iOS 条形码不好扫的原因。相关推荐

  1. 那些 IT 界的神翻译,原来我学不好编程的原因就在这

    近日博主 ruanyf 在网上发布了一条关于套接字"socket"的解释,引发了网友对于那些 IT 界的神翻译的讨论: 突然想到,socket就是插座.服务器的socket,就是服 ...

  2. fir.im Log Guru 正式开源,快速找到 iOS 应用无法安装的原因

    很开心的宣布 Log Guru 正式开源! Log Guru,是 fir.im 开发团队创造的小轮子,用在 Mac 电脑上的日志获取,Github 地址:FIRHQ/LogGuru. Log Guru ...

  3. adhoc包无法安装_关于iOS 应用安装失败的原因找到了

    原标题:关于iOS 应用安装失败的原因找到了 iOS 的内测应用在安装时,很多人都遇到过安装失败的情况,安装失败的原因比较多,下面我们将一些常见原因总结如下,方便开发者进行排查. 启动应用时,出现提示 ...

  4. iOS程序闪退的原因以及处理办法

    iOS程序闪退是一种比较常见的现象.闪退的情况很多,造成程序闪退的原因也很多. ================================启动时闪退======================= ...

  5. 苹果键盘怎么手写_别再说iOS键盘不好用了,这些技巧都不知道,iPhone白买了!...

    iPhone技巧分享:很多苹果用户抱怨iOS键盘不好用,并选择下载第三方输入法软件,其实并不是iPhone自带的键盘不好用,只是很多苹果用户没有发现iOS键盘隐藏的小技巧,具体有哪些呢?我们一起来看一 ...

  6. iOS 页面的卡顿的原因以及如何解决. 如何优化app的启动速度

    1.死锁: 主线程拿到锁A, 需要获取锁B, 而同时子线程拿了锁B, 需要锁A, 这时主线程等待锁B的释放, 子线程等待锁A的释放, 相互等待. 2.抢锁: 主线程需要访问DB, 而这时某个子线程往D ...

  7. iOS App 审核被拒的原因搜罗

    本文转载至 http://ju.outofmemory.cn/entry/108500 iOS app 审核 1.程序有重大bug,程序不能启动,或者中途退出.  2.绕过苹果的付费渠道,我们之前游戏 ...

  8. iOS 应用启动慢的原因找到了!

    一款应用首先带给用户的就是启动体验,时间越短则体验越好,苹果更是建议应用第一个加载时间不宜超过 400 毫秒,可是据说 Swift 引用类型对应用的大小及启动速度有影响,这具体是怎么回事? 作者 | ...

  9. IOS条形码扫描技术实现

    在我们开发ios应用时,尤其是电子商务类应用,时常遇到条形码扫描的业务需求,幸运的已经有开源的SDK供我们使用──条形码的SDK for ios,下面介绍一下这个开源的SDK的使用方法: 免费的条形码 ...

最新文章

  1. 【开发环境】Ubuntu 中使用 VSCode 开发 C/C++ ③ ( 创建工程目录 | 添加 C++ 源代码 | 代码自动提示 )
  2. 记录一次 Arthas 使用
  3. 某业务自助开通账户问题排查
  4. 过滤html文本中的多余属性
  5. 作者:张志恒(1990-),男,兰州大学资源环境学院硕士生。
  6. 4.4 核对矩阵的维数
  7. 微服务架构:统一身份认证和授权技术解决方案
  8. 为Eclipse安装ADT插件
  9. 什么是ipo表,ipo图,hipo图
  10. php laypage,LayUI分页和LayUI laypage分页区别详解
  11. 【python】词云图制作
  12. [附源码]java毕业设计宾馆客房管理系统
  13. Mac 下拷贝文件到移动硬盘
  14. uni-app ucharts无法显示
  15. nginx常用配置集锦(持续更新中。。。)
  16. Sum of the Line UPC5222 (容斥)
  17. 【番杰的小技巧笔记】查看windows许可证到期时间
  18. (洛谷)1309 瑞士轮+(代码)
  19. 数据层面降低NLU误召-构造误召语料
  20. 青龙毛毛快手极速版0407修复版

热门文章

  1. ipad上的ish配置ssh
  2. JAVA 数组的静态初始化
  3. sql sum,group by 分组求和后在求总和,with rollup,with cube的区别
  4. fiddler限制网速,自定义限制网速
  5. 草图大师sketchup2013中文版
  6. 怎样把flv转换成mp4,4种方法轻松学
  7. 【洛谷_P1094】纪念品分组
  8. vue脚手架导入jquery
  9. @ceph之mds文件系统
  10. 随着互联网的发展使得很多传统行业正在发生革命性的转变