Swift - 使用AVFoundation实现条形码扫描(附:拉近镜头改善读取)
(本文代码已升级至Swift3)
2,拉近镜头,改善条形码读取效果

1,条形码(一维码)的扫描读取
原来写过一篇文章,介绍如何使用摄像头扫描读取二维码:Swift - 二维码QRCode的读取(从图片读取 ,或通过摄像头扫描)要通过摄像头读取条形码,只需要将原来二维码读取代码中 metadataObjectTypes 做如下修改即可:
self.output.metadataObjectTypes = [AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeCode39Code,AVMetadataObjectTypeCode93Code]
2,拉近镜头,改善条形码读取效果
有网友反应,如果条码太小的时候(比如iwatch上支付宝的生成的小条码)就会识别不出来。
解决办法是:像支付宝、QQ一样,通过代码拉近镜头焦距,放大内容区域让机器更好的识别。
下面左图是原始大小,右图将画面放大了1.5倍:


import UIKit import AVFoundation class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate, UIAlertViewDelegate{ var scanRectView:UIView! var device:AVCaptureDevice! var input:AVCaptureDeviceInput! var output:AVCaptureMetadataOutput! var session:AVCaptureSession! var preview:AVCaptureVideoPreviewLayer! override func viewDidLoad() { super.viewDidLoad() fromCamera() } //通过摄像头扫描 func fromCamera() { do{ self.device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) self.input = try AVCaptureDeviceInput(device: device) self.output = AVCaptureMetadataOutput() output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main) self.session = AVCaptureSession() if UIScreen.main.bounds.size.height<500 { self.session.sessionPreset = AVCaptureSessionPreset640x480 }else{ self.session.sessionPreset = AVCaptureSessionPresetHigh } self.session.addInput(self.input) self.session.addOutput(self.output) self.output.metadataObjectTypes = [AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeCode39Code,AVMetadataObjectTypeCode93Code] //计算中间可探测区域 let windowSize = UIScreen.main.bounds.size; let scanSize = CGSize(width:windowSize.width*3/4, height:windowSize.width*3/4) var scanRect = CGRect(x:(windowSize.width-scanSize.width)/2, y:(windowSize.height-scanSize.height)/2, width:scanSize.width, height:scanSize.height) //计算rectOfInterest 注意x,y交换位置 scanRect = CGRect(x:scanRect.origin.y/windowSize.height, y:scanRect.origin.x/windowSize.width, width:scanRect.size.height/windowSize.height, height:scanRect.size.width/windowSize.width) //设置可探测区域 self.output.rectOfInterest = scanRect self.preview = AVCaptureVideoPreviewLayer(session:self.session) self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill self.preview.frame = UIScreen.main.bounds self.view.layer.insertSublayer(self.preview, at:0) //添加中间的探测区域绿框 self.scanRectView = UIView(); self.view.addSubview(self.scanRectView) self.scanRectView.frame = CGRect(x:0, y:0, width:scanSize.width, height:scanSize.height) self.scanRectView.center = CGPoint(x:UIScreen.main.bounds.midX, y:UIScreen.main.bounds.midY) self.scanRectView.layer.borderColor = UIColor.green.cgColor self.scanRectView.layer.borderWidth = 1 //开始捕获 self.session.startRunning() //放大 do { try self.device!.lockForConfiguration() } catch _ { NSLog("Error: lockForConfiguration."); } self.device!.videoZoomFactor = 1.5 self.device!.unlockForConfiguration() }catch _ as NSError{ //打印错误消息 let alertController = UIAlertController(title: "提醒", message: "请在iPhone的\"设置-隐私-相机\"选项中,允许本程序访问您的相机", preferredStyle: .alert) let cancelAction = UIAlertAction(title: "确定", style: .cancel, handler: nil) alertController.addAction(cancelAction) self.present(alertController, animated: true, completion: nil) } } //摄像头捕获 func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) { var stringValue:String? if metadataObjects.count > 0 { let metadataObject = metadataObjects[0] as! AVMetadataMachineReadableCodeObject stringValue = metadataObject.stringValue if stringValue != nil{ self.session.stopRunning() } } self.session.stopRunning() //输出结果 let alertController = UIAlertController(title: "二维码", message: stringValue,preferredStyle: .alert) let okAction = UIAlertAction(title: "确定", style: .default, handler: { action in //继续扫描 self.session.startRunning() }) alertController.addAction(okAction) self.present(alertController, animated: true, completion: nil) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
航哥,为什么我的条形码只能扫码带数字的, 带字母的就扫描不出来。
爱死你了站长T.T 调了两天放大功能都不起作用,看了你的代码才知道是self.device!.videoZoomFactor = 1.5位置放错了导致的,我放到了session.startRunning前面,太感谢了