iOS二维码扫描

作者: 小酒窝_David | 来源:发表于2016-03-27 21:08 被阅读600次

    在iOS7之前,二维码扫描只能用第三库(ZBar、ZXing),我的项目中只用到过ZXing,他们的优劣大家自行百度吧。iOS7之后,苹果推出AVFoundation,在灵敏度和性能上完爆上面的那两个第三方库,就像JSON解析一样,性能上不是一个数量级的,苹果出品,必须经典。

    其实在开发中,我们基本上只关心AVFoundation的AVCaptureSession。这个决定了视频输入每一帧图像质量的大小。

    可以通过设置AVCaptureSession 的sessionPreset 属性来改变视频输入每一帧图像质量的大小。

    另外还有参数AVCaptureSessionPreset320x240、AVCaptureSessionPreset352x288、AVCaptureSessionPreset640x480、AVCaptureSessionPreset960x540、AVCaptureSessionPreset1280x720、AVCaptureSessionPreset1920x1080

    一般来说AVCaptureSessionPresetMedium或AVCaptureSessionPreset640x480就能玩转了。

    但是、但是、但是、我们有个变态的项目,要识别印在手机卡上的条形码或者二维码,那个小啊,

    我们测试说过,只要腾讯、阿里能实现的技术,我们必须实现。

    当我拿着微信、QQ、支付宝扫描的时候,他们的识别度是10次能识别1-2次,跟我写的差不多。

    当我在心中窃喜,想用他们都没实现,咱也不改了吧的时候,项目经理来了句,这个功能必须实现,我无语中。。。

    没办法了,查找资料,还好翻到这篇博客http://blog.cnbluebox.com/blog/2014/08/26/ioser-wei-ma-sao-miao

    那项目我们就来研究一下它AVCaptureMetadataOutput 的 rectOfInterest 属性

    最开始我按照文档说的按照比例值来设置这个属性,如下:

    CGSize size = self.view.bounds.size;

    CGRect cropRect = CGRectMake(40, 100, 240, 240);

    captureOutput.rectOfInterest = CGRectMake(cropRect.origin.x/size.width,

    cropRect.origin.y/size.height,

    cropRect.size.width/size.width,

    cropRect.size.height/size.height);

    但是发现, Ops, 好像不对啊,扫不到了,明显不正确呢,于是猜想: AVCapture输出的图片大小都是横着的,而iPhone的屏幕是竖着的,那么我把它旋转90°呢:

    CGSize size = self.view.bounds.size;

    CGRect cropRect = CGRectMake(40, 100, 240, 240);

    captureOutput.rectOfInterest = CGRectMake(cropRect.origin.y/size.height,

    cropRect.origin.x/size.width,

    cropRect.size.height/size.height,

    cropRect.size.width/size.width);

    OK,貌似对了,在iPhone5上一切工作良好,但是在4s上,或者换了sessionPreset的大小之后,这个框貌似就不那么准确了, 可能发现超出框上下一些也是可以扫描出来的。 再次猜想: 图片的长宽比和手机屏幕不是一样的,这个rectOfInterest是相对于图片大小的比例。比如iPhone4s屏幕大小是 640x960, 而图片输出大小是 1920x1080. 实际的情况可能就是下图中的效果:

    上图中下面的代表iPhone4s屏幕,大小640x960, 上面代表AVCaptureVideoPreviewLayer中预览到的图片位置,在图片输入为1920x1080大小时,实际大小上下会被截取一点的,因为我们AVCaptureVideoPreviewLayer设置的videoGravity是AVLayerVideoGravityResizeAspectFill, 类似于UIView的UIViewContentModeScaleAspectFill效果。

    于是我对大小做了一下修正:

    CGSize size = self.view.bounds.size;

    CGRect cropRect = CGRectMake(40, 100, 240, 240);

    CGFloat p1 = size.height/size.width;

    CGFloat p2 = 1920./1080.;  //使用了1080p的图像输出

    if (p1 < p2) {

    CGFloat fixHeight = bounds.size.width * 1920. / 1080.;

    CGFloat fixPadding = (fixHeight - size.height)/2;

    captureOutput.rectOfInterest = CGRectMake((cropRect.origin.y + fixPadding)/fixHeight,

    cropRect.origin.x/size.width,

    cropRect.size.height/fixHeight,

    cropRect.size.width/size.width);

    } else {

    CGFloat fixWidth = bounds.size.height * 1080. / 1920.;

    CGFloat fixPadding = (fixWidth - size.width)/2;

    captureOutput.rectOfInterest = CGRectMake(cropRect.origin.y/size.height,

    (cropRect.origin.x + fixPadding)/fixWidth,

    cropRect.size.height/size.height,

    cropRect.size.width/fixWidth);

    }

    经过上面的验证,证实了猜想rectOfInterest是基于图像的大小裁剪的。

    参考文献::http://blog.cnbluebox.com/blog/2014/08/26/ioser-wei-ma-sao-miao/

    相关文章

      网友评论

        本文标题:iOS二维码扫描

        本文链接:https://www.haomeiwen.com/subject/ftkjlttx.html