您可以使用机器学习套件识别和解码条形码。
试试看
- 您可以试用示例应用, 查看此 API 的用法示例。
准备工作
- 在 Podfile 中添加以下机器学习套件 Pod:
pod 'GoogleMLKit/BarcodeScanning', '15.5.0'
- 安装或更新项目的 Pod 之后,使用 Xcode 项目的
.xcworkspace
。Xcode 12.4 或更高版本支持机器学习套件。
输入图片准则
-
为了使机器学习套件准确读取条形码,输入图片必须包含 用足够像素数据表示的条形码。
具体的像素数据要求取决于 因为很多条形码中的内容都与条形码之间 支持可变大小的载荷一般来说,最小的 条形码的单元宽度应至少为 2 像素,并且 二维代码,高 2 像素。
例如,EAN-13 条形码由条形和空格组成,分别为 1、 宽度为 2、3 或 4 个单位,因此理想情况下,EAN-13 条形码图片应具有 宽度至少为 2、4、6 和 8 像素的空间。因为有一个 EAN-13 条形码总共为 95 个单位,条形码应至少为 190 像素宽。
更密集的格式(如 PDF417)需要更大的像素尺寸才能 机器学习套件可靠地读取这些数据。例如,一个 PDF417 代码最多可包含 34 个 17 个单位的宽“单词”最好是至少 宽度为 1156 像素。
-
图片聚焦不良会影响扫描准确性。如果您的应用没有 可以要求用户重新拍摄图片。
-
对于典型应用,建议为 例如 1280x720 或 1920x1080, 距离摄像头较远的屏幕可扫描。
不过,在对延迟至关重要的应用中,您可以 以较低分辨率捕获图片,但要求 条形码构成了输入图片的大部分。另请参阅 提高实时性能的相关提示。
1. 配置条形码扫描器
如果您知道要读取哪些格式的条形码,就可以提高 方法是将条形码扫描器配置为仅扫描这些格式。例如,要仅扫描 Aztec 码和 QR 码,请构建
BarcodeScannerOptions
对象,如
示例:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
支持以下格式:
- code128
- code39
- code93
- codaBar
- dataMatrix
- EAN13
- EAN8
- ITF
- qrCode
- UPCA
- UPCE
- PDF417
- Aztec
Objective-C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
支持以下格式:
- Code-128 (
MLKBarcodeFormatCode128
) - Code-39 (
MLKBarcodeFormatCode39
) - Code-93 (
MLKBarcodeFormatCode93
) - Codabar(
MLKBarcodeFormatCodaBar
) - 数据矩阵 (
MLKBarcodeFormatDataMatrix
) - EAN-13(
MLKBarcodeFormatEAN13
) - EAN-8(
MLKBarcodeFormatEAN8
) - ITF (
MLKBarcodeFormatITF
) - 二维码 (
MLKBarcodeFormatQRCode
) - UPC-A (
MLKBarcodeFormatUPCA
) - UPC-E (
MLKBarcodeFormatUPCE
) - PDF-417(
MLKBarcodeFormatPDF417
) - 阿兹特克代码 (
MLKBarcodeFormatAztec
)
2. 准备输入图片
如需扫描图片中的条形码,请将图片作为UIImage
或
CMSampleBufferRef
到 BarcodeScanner
的 process()
或 results(in:)
方法:
使用 UIImage
或VisionImage
CMSampleBuffer
。
如果您使用 UIImage
,请按以下步骤操作:
- 使用
UIImage
创建一个VisionImage
对象。请务必指定正确的.orientation
。Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
如果您使用 CMSampleBuffer
,请按以下步骤操作:
-
指定
CMSampleBuffer
。如需获取图片方向,请执行以下操作:
Swift
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> UIImage.Orientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftMirrored : .right case .landscapeLeft: return cameraPosition == .front ? .downMirrored : .up case .portraitUpsideDown: return cameraPosition == .front ? .rightMirrored : .left case .landscapeRight: return cameraPosition == .front ? .upMirrored : .down case .faceDown, .faceUp, .unknown: return .up } }
Objective-C
- (UIImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored : UIImageOrientationRight; case UIDeviceOrientationLandscapeLeft: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored : UIImageOrientationUp; case UIDeviceOrientationPortraitUpsideDown: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored : UIImageOrientationLeft; case UIDeviceOrientationLandscapeRight: return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored : UIImageOrientationDown; case UIDeviceOrientationUnknown: case UIDeviceOrientationFaceUp: case UIDeviceOrientationFaceDown: return UIImageOrientationUp; } }
- 使用
VisionImage
CMSampleBuffer
对象和方向:Swift
let image = VisionImage(buffer: sampleBuffer) image.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition)
Objective-C
MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer]; image.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
3. 获取 BarcodeScanner 的实例
获取BarcodeScanner
的一个实例:
Swift
let barcodeScanner = BarcodeScanner.barcodeScanner() // Or, to change the default settings: // let barcodeScanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)
Objective-C
MLKBarcodeScanner *barcodeScanner = [MLKBarcodeScanner barcodeScanner]; // Or, to change the default settings: // MLKBarcodeScanner *barcodeScanner = // [MLKBarcodeScanner barcodeScannerWithOptions:options];
4. 处理图片
然后,将图片传递给process()
方法:
Swift
barcodeScanner.process(visionImage) { features, error in guard error == nil, let features = features, !features.isEmpty else { // Error handling return } // Recognized barcodes }
Objective-C
[barcodeScanner processImage:image completion:^(NSArray<MLKBarcode *> *_Nullable barcodes, NSError *_Nullable error) { if (error != nil) { // Error handling return; } if (barcodes.count > 0) { // Recognized barcodes } }];
5. 从条形码中获取信息
如果条形码扫描操作成功,扫描器会返回一个数组,Barcode
对象。每个 Barcode
对象代表一个
图片中检测到的条形码。对于每个条形码,您可以
输入图像中的边界坐标以及由
条形码。此外,如果条形码扫描器能够确定数据的类型,
您可以获取一个包含已解析数据的对象。
例如:
Swift
for barcode in barcodes { let corners = barcode.cornerPoints let displayValue = barcode.displayValue let rawValue = barcode.rawValue let valueType = barcode.valueType switch valueType { case .wiFi: let ssid = barcode.wifi?.ssid let password = barcode.wifi?.password let encryptionType = barcode.wifi?.type case .URL: let title = barcode.url!.title let url = barcode.url!.url default: // See API reference for all supported value types } }
Objective-C
for (MLKBarcode *barcode in barcodes) { NSArray *corners = barcode.cornerPoints; NSString *displayValue = barcode.displayValue; NSString *rawValue = barcode.rawValue; MLKBarcodeValueType valueType = barcode.valueType; switch (valueType) { case MLKBarcodeValueTypeWiFi: ssid = barcode.wifi.ssid; password = barcode.wifi.password; encryptionType = barcode.wifi.type; break; case MLKBarcodeValueTypeURL: url = barcode.URL.url; title = barcode.URL.title; break; // ... default: break; } }
提高实时性能的相关提示
如果要在实时应用中扫描条形码,请按以下说明操作 实现最佳帧速率的准则:
-
请勿以相机的原始分辨率捕获输入内容。在某些设备上 以原始分辨率捕获输入会产生极大的(超过 10 而这导致非常糟糕的延迟时间,对 准确率。正确做法是,仅从相机中请求所需的尺寸 通常不超过 200 万像素。
已命名的拍摄会话预设:
AVCaptureSessionPresetDefault
、AVCaptureSessionPresetLow
、AVCaptureSessionPresetMedium
、 等)(因此不推荐使用),因为它们可能会映射到 分辨率不合适。您可以改用特定预设值 例如AVCaptureSessionPreset1280x720
。如果扫描速度很重要,您可以进一步降低图片拍摄速度 分辨率。不过,请注意最小条形码尺寸要求 。
如果您要尝试从一系列流式视频中识别条形码 识别器在不同视频帧之间生成不同的结果 帧。您应该等到收到同一系列的 值以确保您会返回良好的结果。
ITF 和 CODE-39 不支持校验和数字。
- 如需处理视频帧,请使用检测器的
results(in:)
同步 API。致电 此方法(可从 获取)AVCaptureVideoDataOutputSampleBufferDelegate
的captureOutput(_, didOutput:from:)
函数,用于同步获取指定视频的结果 帧。保留AVCaptureVideoDataOutput
的alwaysDiscardsLateVideoFrames
作为true
,以限制对检测器的调用。如果新的 视频帧在检测器运行时可用,则会丢失。 - 如果您使用检测器的输出在图像上叠加显示 输入图片,首先从机器学习套件获取结果, 和叠加层。通过这种方式,您可以在显示屏上呈现 只对每个已处理的输入帧运行一次。请参阅 updatePreviewOverlayViewWithLastFrame 。