在 iOS 上使用 ML Kit 掃描條碼

您可以使用 ML Kit 辨識條碼並加以解碼。

事前準備

  1. 如果尚未將 Firebase 加入應用程式,請按照下列步驟操作: 入門指南中的步驟。
  2. 在 Podfile 中加入 ML Kit 程式庫:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    安裝或更新專案的 Pod 後,請務必開啟 Xcode 專案 .xcworkspace
  3. 在應用程式中匯入 Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

輸入圖片規範

  • 為了讓 ML Kit 準確讀取條碼,輸入圖片必須包含 以充足的像素資料表示條碼

    具體的像素資料規定取決於 條碼及其中編碼的資料量 (因為大部分條碼 支援可變長度酬載)。一般來說,最小的 條碼單位應至少為 2 像素寬 (如果是 2 維代碼,高度為 2 像素)。

    例如,EAN-13 條碼是由 1 號的酒吧和空格組成。 寬 2、3 或 4 個單位,因此在理想情況下,EAN-13 條碼圖片應有長條 顯示寬度至少為 2、4、6 和 8 像素的空間。因為 EAN-13 條碼的總寬為 95 個單位,條碼至少應為 190 像素寬。

    密度格式 (例如 PDF417) 需要更大的像素尺寸 可靠的機器學習套件例如,PDF417 程式碼最多可包含 寬 34 個 17 單位的「words」理想情況下 1156 像素寬。

  • 圖片對焦品質不佳可能會降低掃描準確度。如果不使用 可接受的結果,請嘗試要求使用者重新擷取圖片。

  • 以一般應用程式來說,建議您針對 解析度圖片 (例如 1280x720 或 1920x1080),才能製作條碼 可從遠較遠的相機偵測。

    不過,若是應用程式比較注重延遲狀況,您可以提高 低解析度的圖像,但我們需要 條碼構成大部分的輸入圖片另請參閱 即時效能改善秘訣

1. 設定條碼偵測工具

如果您知道預期會讀取哪些條碼格式,則可加快速度 ,藉此選擇只偵測這些格式。

舉例來說,如果只要偵測 Aztec 代碼和 QR code,請建立 VisionBarcodeDetectorOptions 物件,如 範例:

Swift

let format = VisionBarcodeFormat.all
let barcodeOptions = VisionBarcodeDetectorOptions(formats: format)

支援下列格式:

  • 代碼 128
  • 代碼 39
  • 代碼 93
  • 科達巴
  • EAN13
  • EAN8
  • ITF
  • UPCA
  • UPCE
  • QR code
  • PDF417
  • 阿茲特克
  • DataMatrix

Objective-C

FIRVisionBarcodeDetectorOptions *options =
    [[FIRVisionBarcodeDetectorOptions alloc]
     initWithFormats: FIRVisionBarcodeFormatQRCode | FIRVisionBarcodeFormatAztec];

支援下列格式:

  • 代碼 128 (FIRVisionBarcodeFormatCode128)
  • 代碼 39 (FIRVisionBarcodeFormatCode39)
  • 代碼 93 (FIRVisionBarcodeFormatCode93)
  • 科達巴 (FIRVisionBarcodeFormatCodaBar)
  • EAN-13 (FIRVisionBarcodeFormatEAN13)
  • EAN-8 (FIRVisionBarcodeFormatEAN8)
  • ITF (FIRVisionBarcodeFormatITF)
  • 通用產品代碼 (FIRVisionBarcodeFormatUPCA)
  • UPC-E (FIRVisionBarcodeFormatUPCE)
  • QR code (FIRVisionBarcodeFormatQRCode)
  • PDF417 (FIRVisionBarcodeFormatPDF417)
  • 阿茲特克 (FIRVisionBarcodeFormatAztec)
  • 資料矩陣 (FIRVisionBarcodeFormatDataMatrix)

2. 執行條碼偵測工具

如要掃描圖片中的條碼,請以 UIImageCMSampleBufferRefVisionBarcodeDetectordetect(in:) 方法:

  1. 取得 VisionBarcodeDetector 的執行個體:

    Swift

    lazy var vision = Vision.vision()
    
    let barcodeDetector = vision.barcodeDetector(options: barcodeOptions)
    

    Objective-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionBarcodeDetector *barcodeDetector = [vision barcodeDetector];
    // Or, to change the default settings:
    // FIRVisionBarcodeDetector *barcodeDetector =
    //     [vision barcodeDetectorWithOptions:options];
    
  2. 使用 UIImageVisionImage CMSampleBufferRef

    如何使用 UIImage

    1. 視需要旋轉圖片,使其 imageOrientation 屬性為 .up
    2. 使用正確旋轉的做法建立 VisionImage 物件 UIImage。請勿指定任何輪替中繼資料 (預設值) 值 (.topLeft),則必須使用。

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    如何使用 CMSampleBufferRef

    1. 建立 VisionImageMetadata 物件,以指定 包含的圖片資料方向 CMSampleBufferRef 緩衝區。

      如何取得圖片方向:

      Swift

      func imageOrientation(
          deviceOrientation: UIDeviceOrientation,
          cameraPosition: AVCaptureDevice.Position
          ) -> VisionDetectorImageOrientation {
          switch deviceOrientation {
          case .portrait:
              return cameraPosition == .front ? .leftTop : .rightTop
          case .landscapeLeft:
              return cameraPosition == .front ? .bottomLeft : .topLeft
          case .portraitUpsideDown:
              return cameraPosition == .front ? .rightBottom : .leftBottom
          case .landscapeRight:
              return cameraPosition == .front ? .topRight : .bottomRight
          case .faceDown, .faceUp, .unknown:
              return .leftTop
          }
      }

      Objective-C

      - (FIRVisionDetectorImageOrientation)
          imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                                 cameraPosition:(AVCaptureDevicePosition)cameraPosition {
        switch (deviceOrientation) {
          case UIDeviceOrientationPortrait:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationLeftTop;
            } else {
              return FIRVisionDetectorImageOrientationRightTop;
            }
          case UIDeviceOrientationLandscapeLeft:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationBottomLeft;
            } else {
              return FIRVisionDetectorImageOrientationTopLeft;
            }
          case UIDeviceOrientationPortraitUpsideDown:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationRightBottom;
            } else {
              return FIRVisionDetectorImageOrientationLeftBottom;
            }
          case UIDeviceOrientationLandscapeRight:
            if (cameraPosition == AVCaptureDevicePositionFront) {
              return FIRVisionDetectorImageOrientationTopRight;
            } else {
              return FIRVisionDetectorImageOrientationBottomRight;
            }
          default:
            return FIRVisionDetectorImageOrientationTopLeft;
        }
      }

      然後,建立中繼資料物件:

      Swift

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Objective-C

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. 請使用VisionImage CMSampleBufferRef 物件和輪替中繼資料:

      Swift

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. 接著,將圖片傳遞至 detect(in:) 方法:

    Swift

    barcodeDetector.detect(in: visionImage) { features, error in
      guard error == nil, let features = features, !features.isEmpty else {
        // ...
        return
      }
    
      // ...
    }
    

    Objective-C

    [barcodeDetector detectInImage:image
                        completion:^(NSArray<FIRVisionBarcode *> *barcodes,
                                     NSError *error) {
      if (error != nil) {
        return;
      } else if (barcodes != nil) {
        // Recognized barcodes
        // ...
      }
    }];
    

3. 透過條碼取得資訊

如果條碼辨識作業成功,偵測工具會傳回 VisionBarcode 物件。每個 VisionBarcode 物件都代表 在圖片中偵測到的條碼針對每個條碼 輸入圖像中的邊界座標,以及由 條碼此外,如果條碼偵測工具可以判斷資料類型 您可以取得包含剖析資料的物件。

例如:

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 (FIRVisionBarcode *barcode in barcodes) {
   NSArray *corners = barcode.cornerPoints;

   NSString *displayValue = barcode.displayValue;
   NSString *rawValue = barcode.rawValue;

   FIRVisionBarcodeValueType valueType = barcode.valueType;
   switch (valueType) {
     case FIRVisionBarcodeValueTypeWiFi:
       // ssid = barcode.wifi.ssid;
       // password = barcode.wifi.password;
       // encryptionType = barcode.wifi.type;
       break;
     case FIRVisionBarcodeValueTypeURL:
       // url = barcode.URL.url;
       // title = barcode.URL.title;
       break;
     // ...
     default:
       break;
   }
 }

即時效能改善訣竅

如要在即時應用程式中掃描條碼,請按照下列指示操作: 實現最佳影格速率:

  • 請勿以相機原始解析度擷取輸入內容。在部分裝置上, 以原生解析度擷取輸入內容會產生極大檔案 (10+ 才能確保延遲時間極短,而且 準確度。請改為只從必要的相機要求大小 通常不超過 200 萬像素。

    已命名的擷取工作階段預設設定:AVCaptureSessionPresetDefaultAVCaptureSessionPresetLowAVCaptureSessionPresetMedium、 等) 並不會使用,不過它們可以對應至 解析度不適用於部分裝置。請改用我們 例如 AVCaptureSessionPreset1280x720

    如果掃描速度很重要,可以進一步降低圖片拍攝速度 解析度。但請注意,條碼大小下限規定 即可。

  • 限制對偵測工具的呼叫。如果新的影片影格 因此請在偵測器執行時捨棄影格。
  • 使用偵測工具的輸出內容將圖像重疊 先從 ML Kit 取得結果,然後算繪圖片 並疊加單一步驟這麼一來,您的應用程式就會算繪到顯示途徑 每個輸入影格只能建立一次請參閱 previewOverlayViewFIRDetectionOverlayView 例如,在展示範例應用程式中使用類別。