你可以使用機器學習套件辨識及解碼條碼。
立即體驗
- 請試用範例應用程式,查看這個 API 的使用範例。
事前準備
- 在 Podfile 中加入下列機器學習套件 Pod:
pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
- 安裝或更新專案的 Pod 後,使用
.xcworkspace
開啟 Xcode 專案。Xcode 12.4 以上版本支援機器學習套件。
輸入圖片規範
-
為了讓機器學習套件能準確讀取條碼,輸入圖片必須包含用來代表充足像素資料的條碼。
許多像素資料需求都取決於條碼類型和其中編碼的資料量,因為許多條碼都支援可變大小酬載。一般而言,條碼最小的有意義的單位至少應為 2 像素的寬度,而二維代碼的高度應為 2 像素。
舉例來說,EAN-13 條碼是由 1、2、3 或 4 個單位寬的長條和空格所組成,因此 EAN-13 條碼圖片的長條和空格至少應為 2、4、6 和 8 像素寬度。由於 EAN-13 條碼的總寬度為 95 單位,所以條碼至少應為 190 像素寬。
PDF417 等 Denser 格式需要較大的像素尺寸,機器學習套件才能穩定讀取。舉例來說,PDF 417 程式碼的單一資料列最多可包含 34 個 17 單位寬的「字詞」,理想情況下寬度至少為 1156 像素。
-
圖片焦點不佳可能會影響掃描準確度。如果您的應用程式無法取得可接受的結果,請要求使用者擷取圖片。
-
如果是一般應用程式,則建議提供解析度更高的圖片,例如 1280x720 或 1920x1080,讓掃描碼範圍較遠的相機也能掃描。
不過,在延遲時間極長的應用程式中,您可以採用較低解析度拍攝圖片,藉此提升效能,但要求條碼會佔大部分的輸入圖像。另請參閱改善即時效能的提示。
1. 設定條碼掃描器
如果您知道預期的閱讀格式,您可以將條碼掃描器設定為僅掃描這些格式,藉此提升條碼掃描器的速度。舉例來說,如果只要掃描 Aztec 程式碼和 QR 圖碼,請建構 BarcodeScannerOptions
物件,如下列範例所示:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
系統支援以下格式:
- 代碼 128
- 代碼 39
- 代碼 93
- CodaBar
- 資料矩陣
- EAN13
- EAN8
- 義大利
- qrCode (兌換代碼)
- UPCA
- 上衣
- PDF417
- Aztec
Objective-C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
系統支援以下格式:
- 代碼 128 (
MLKBarcodeFormatCode128
) - 代碼 39 (
MLKBarcodeFormatCode39
) - 代碼 93 (
MLKBarcodeFormatCode93
) - 科達巴 (
MLKBarcodeFormatCodaBar
) - 資料矩陣 (
MLKBarcodeFormatDataMatrix
) - EAN-13 (
MLKBarcodeFormatEAN13
) - EAN-8 (
MLKBarcodeFormatEAN8
) - ITF (
MLKBarcodeFormatITF
) - QR 圖碼 (
MLKBarcodeFormatQRCode
) - UPC-A (
MLKBarcodeFormatUPCA
) - UPC-E (
MLKBarcodeFormatUPCE
) - PDF-417 (
MLKBarcodeFormatPDF417
) - Aztec 代碼 (
MLKBarcodeFormatAztec
)
2. 準備輸入圖片
如要掃描圖片中的條碼,請將圖片以UIImage
或 CMSampleBufferRef
的形式傳送至 BarcodeScanner
的 process()
或 results(in:)
方法:
使用 UIImage
或 CMSampleBuffer
建立 VisionImage
物件。
如果您使用 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; } }
- 使用
CMSampleBuffer
物件和方向建立VisionImage
物件: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; } }
改善即時成效的訣竅
如果您想在即時應用程式中掃描條碼,請按照下列指南設定最佳影格速率:
-
請不要以攝影機的原始解析度擷取輸入。在某些裝置上,以原生解析度擷取輸入會產生非常大 (1000 萬像素以上) 的圖片,因此延遲時間很短,而且對準確率沒有幫助。而是要求從相機執行條碼掃描所需的大小 (通常不超過 200 萬像素)。
不過,我們不建議使用已擷取的擷取工作階段預設設定,例如
AVCaptureSessionPresetDefault
、AVCaptureSessionPresetLow
、AVCaptureSessionPresetMedium
等,因為這些是對應至某些裝置的不適當解析度。請改用特定預設 (例如AVCaptureSessionPreset1280x720
)。如果掃描速度很重要,您可以進一步降低圖片拍攝解析度。但請注意,上述條碼大小下限下限。
如果您嘗試辨識一系列串流影格的條碼,辨識器可能會產生不同的影格結果。您應等到出現相同值的連續連續序列後,才能夠傳回正確的結果。
ITF 和 CODE-39 不支援總和檢查碼。
- 如要處理影格,請使用偵測工具的
results(in:)
同步 API。從AVCaptureVideoDataOutputSampleBufferDelegate
的captureOutput(_, didOutput:from:)
函式呼叫此方法,即可同步取得特定影片影格的結果。將AVCaptureVideoDataOutput
的alwaysDiscardsLateVideoFrames
保留為true
,以限制對偵測工具的呼叫。假如在偵測器執行期間有新的視訊畫面可用,系統就會捨棄該影格。 - 如果您使用偵測工具的輸出內容,為輸入圖片上的圖像重疊,請先透過 ML Kit 取得結果,然後透過單一步驟算繪圖像和疊加層。如此一來,每個處理的輸入影格只會轉譯一次到顯示途徑一次。如需範例,請參閱 ML Kit 快速入門導覽課程範例中的 updatePreviewOverlayViewWithLastFrame。