iOS关二维码那些事

在 iOS7 以前,在iOS中实现二维码和条形码扫描,我们所知的有,两大开源组件ZBar与ZXing. 这两大组件我们都有用过,这里总结下各自的缺点:

  • ZBar

ZBar在扫描的灵敏度上,和内存的使用上相对于ZXing上都是较优的,但是对于 “圆角二维码” 的扫描确很困难。如:

  • ZXing

ZXing
是 Google Code上的一个开源的条形码扫描库,是用java设计的,连Google Glass
都在使用的。但有人为了追求更高效率以及可移植性,出现了c++ port. Github上的Objectivc-C
port,其实就是用OC代码封装了一下而已,而且已经停止维护。这样效率非常低,在instrument下面可以看到CPU和内存疯涨,在内存小的机器
上很容易崩溃。

  • AVFoundation

AVFoundation无论在扫描灵敏度和性能上来说都是最优的,所以毫无疑问我们应该切换到AVFoundation,需要兼容iOS 6或之前的版本可以用zbar或zxing代替。

下面介绍本文的重点,无论你是用以上哪一种或其他的解决方案,都需要知道下面两点。

1. 图片很小的二维码


前测试提了一个bug,说有二维码扫不了,拿到二维码一看,是个很小的二维码,边长不到1cm,于是就修改了 sessionPreset 为
1080p 的,当时用的是ZXing,
当把图片质量改清楚时,也造成了性能的下降,基本打开扫描界面就会报memoryWarning,但是也确实解决了小二维码扫描的问题。

AVCaptureSession 可以设置 sessionPreset 属性,这个决定了视频输入每一帧图像质量的大小。

  • AVCaptureSessionPreset320x240
  • AVCaptureSessionPreset352x288
  • AVCaptureSessionPreset640x480
  • AVCaptureSessionPreset960x540
  • AVCaptureSessionPreset1280x720
  • AVCaptureSessionPreset1920x1080


上列举了部分的属性值,分别代表输入图片质量大小,一般来说AVCaptureSessionPreset640x480就够使用,但是如果要保证较小的
二维码图片能快速扫描,最好设置高些,如AVCaptureSessionPreset1920x1080(就是我们常说的1080p).

2. scanCrop

另一个提升扫描速度和性能的就是设置解析的范围,在zbar和zxing中就是scanCrop, AVFoundation中设置 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是基于图像的大小裁剪的。

3. 小结

scanCrop对于扫描来说是比较重要的,试想图片截小点来解析是不是理论上就会更快了呢。网络上貌似很难搜到关于scanCrop的详解,希望对看到的人有帮助。

时间: 2024-10-10 18:14:36

iOS关二维码那些事的相关文章

iOS开发-二维码扫描和应用跳转

iOS开发-二维码扫描和应用跳转 序言 前面我们已经调到过怎么制作二维码,在我们能够生成二维码之后,如何对二维码进行扫描呢? 在iOS7之前,大部分应用中使用的二维码扫描是第三方的扫描框架,例如ZXing或者ZBar.使用时集成麻烦,出错也不方便调试.在iOS7之后,苹果自身提供了二维码的扫描功能,从效率上来说,原生的二维码远高于这些第三方框架.本文讲解如何使用原生框架实现二维码扫描功能,并且进行扫描后的项目跳转.ps:本期的源代码会在文章结尾给出链接 扫描相关类 二维码扫描需要获取摄像头并读取

iOS之二维码的制作与扫描

IOS之二维码的制作与扫描     二维码SDK的Dome“QRCode”中制作libqrencode库文件,扫描ZBarSDK库文件1.制作二维码  /*字符转二维码导入 libqrencode文件添加  #import "QRCodeGenerator.h"@property (strong , nonatomic) UIImageView* qRImageView;- (void)viewDidLoad{    [super viewDidLoad];    self.qRIma

iOS 花式二维码生成和二维码识别

iOS 原生的二维码识别非常之棒,反正比 ZXing 和 ZBar 效果都好些,所以以后打算尽量用原生的二维码识别,然后最近把原生的二维码生成也顺便做了一遍,并且在原有基础上加了一些样式参数,封了一个小库方便以后使用. 项目地址:https://github.com/EyreFree/EFQRCode EFQRCode 是一个用 Swift 编写的用来生成和识别二维码的库,它基于系统二维码生成与识别进行开发. 生成:利用输入的水印图/图标等资源生成各种艺术二维码: 识别:识别率比 iOS 原生二

二维码扫描(iOS原生二维码扫描)

一.关于二维码扫描的第三方库有很多:例如比较常用的两个 1.ZBar SDK ZBar为我们提供了两种使用方式,一种是直接调用ZBar提供的ZBarReaderViewController打开一个扫描界面,另一种方式是使用ZBar提供的可以嵌在其他视图中的ZBarReaderView,实际项目中我们更可能会使用第二种方式,这可以让我们对界面做更多的定制,详细的百度查找相关文档来看. 2.ZXing(Github镜像地址)是一个开源的条码生成和扫描库(开源协议为Apache2.0).它不但支持众多

猫猫学iOS之二维码学习,快速打开相机读取二维码

猫猫分享,必须精品 原创文章,欢迎转载.转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243 上一篇文章写了怎么生成二维码,这儿就说说怎么读取吧,反正也很简单,iOS封装的太强大了 步骤呢就是这样: 读取二维码需要导入AVFoundation框架#import <AVFoundation/AVFoundation.h> 1:利用摄像头识别二维码中的内容(模拟器不行). 2:输入(摄像头). 3:由会话将摄像头采集到的二维码图像转换成字符串数据. 4:输

猫猫学iOS之二维码学习,快速生成二维码

猫猫分享,必须精品 原创文章,欢迎转载.转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243 二维码是一项项目中可能会用到的,iOS打开相机索取二维码的速度可不是Android能比的...(Android扫描二维码要来回来回晃...) 简单不多说,如何把一段资料(网址呀,字符串)变成二维码,直接上代码 步骤: 导入CoreImage框架 #import <CoreImage/CoreImage.h> 通过滤镜CIFilter生成二维码 #import

qt for ios扫描二维码功能实现

问题: 公司项目考虑到跨平台一直都是用qt做,由于项目需求,项目上要增加一个二维码扫描功能,在安卓可以用QVideoProbe实现抓取摄像头视频帧,用QZxing解码图片,从而实现二维码扫描,但是在ios上,QVideProbe并不支持,所以只好选择其他抓取视频帧的方法,考虑使用OPencv实现抓取视频帧,但是在查看ios文档时,ios7 以上直接支持二维码扫描功能,所以放弃使用opencv抓取 + zxing解码的方法.从而采取ios官方提供的二维码解码功能. 实现: 由于我们项目ui一直是用

iOS 系统二维码扫描(可限制扫描区域)

使用 AVFoundation系统库来进行二维码扫描并且限制扫描二维码的范围.(因为默认的是全屏扫描) -(void)beginCode { //1.摄像头设备 AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; /* // Media types AVMediaTypeVideo AVMediaTypeAudio AVMediaTypeText AVMediaTypeC

iOS开发 二维码生成

基于libqrencode的二维码生成 + (void)drawQRCode:(QRcode *)code context:(CGContextRef)ctx size:(CGFloat)size { unsigned char *data = 0; int width; data = code->data; width = code->width; float zoom = (double)size / (code->width + 2.0 * qr_margin); CGRect r