您可以使用机器学习套件识别和解码条形码。
试试看
- 您可以试用示例应用, 查看此 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
对象,如
示例:
let format = .all
let barcodeOptions = BarcodeScannerOptions(formats: format)
支持以下格式:
- code128
- code39
- code93
- codaBar
- dataMatrix
- EAN13
- EAN8
- ITF
- qrCode
- UPCA
- UPCE
- PDF417
- Aztec
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
。let image = VisionImage(image: UIImage)
visionImage.orientation = image.imageOrientationMLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
visionImage.orientation = image.imageOrientation;
如果您使用 CMSampleBuffer
,请按以下步骤操作:
-
指定
CMSampleBuffer
。如需获取图片方向,请执行以下操作:
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
}
}
- (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
对象和方向:let image = VisionImage(buffer: sampleBuffer)
image.orientation = imageOrientation(
deviceOrientation: UIDevice.current.orientation,
cameraPosition: cameraPosition)MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
image.orientation =
[self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
cameraPosition:cameraPosition];
3. 获取 BarcodeScanner 的实例
获取BarcodeScanner
的一个实例:
let barcodeScanner = BarcodeScanner.barcodeScanner()
// Or, to change the default settings:
// let barcodeScanner = BarcodeScanner.barcodeScanner(options: barcodeOptions)
MLKBarcodeScanner *barcodeScanner = [MLKBarcodeScanner barcodeScanner];
// Or, to change the default settings:
// MLKBarcodeScanner *barcodeScanner =
// [MLKBarcodeScanner barcodeScannerWithOptions:options];
4. 处理图片
然后,将图片传递给process()
方法:
barcodeScanner.process(visionImage) { features, error in
guard error == nil, let features = features, !features.isEmpty else {
// Error handling
return
}
// Recognized barcodes
}
[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
对象代表一个
图片中检测到的条形码。对于每个条形码,您可以
输入图像中的边界坐标以及由
条形码。此外,如果条形码扫描器能够确定数据的类型,
您可以获取一个包含已解析数据的对象。
例如:
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
}
}
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 。