ML Kit を使用してバーコードをスキャンする(iOS)

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

ML Kit を使用すると、バーコードを認識してデコードできます。

始める前に

  1. Podfile に次の ML Kit Pod を含めます。
    pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
    
  2. プロジェクトの Pod をインストールまたは更新した後に、.xcworkspace を使用して Xcode プロジェクトを開きます。ML Kit は、Xcode バージョン 12.4 以降でサポートされています。

入力画像に関するガイドライン

  • ML Kit でバーコードを正確に読み取るには、入力画像に、十分なピクセルデータによって表されるバーコードが含まれている必要があります。

    多くのバーコードは可変サイズのペイロードをサポートしているため、特定のピクセルデータの要件は、バーコードの種類とバーコード内でエンコードされるデータの量によって異なります。一般に、バーコードの最小の単位は 2 ピクセル以上で、2 次元コードの場合は高さが 2 ピクセルである必要があります。

    たとえば、EAN-13 バーコードは幅 1、2、3、または 4 ユニットのバーとスペースで構成されているため、EAN-13 バーコードの画像は少なくとも幅 2、4、6、8 ピクセルのバーとスペースを含むことが理想的です。EAN-13 バーコードの幅は合計 95 単位であるため、バーコードの幅は 190 ピクセル以上にする必要があります。

    PDF417 などの高密度形式は、ML Kit が正確に読み取れるようにするために、より大きなピクセルサイズを必要とします。たとえば、PDF417 コードには、1 行に最大 34 個の 17 ユニットの「単語」を含めることができます。これは、幅が 1,156 ピクセル以上であることが理想的です。

  • 画像がぼやけていると、スキャンの精度に影響する可能性があります。アプリが想定どおりの結果が得られない場合は、ユーザーに画像をキャプチャし直すよう求めます。

  • 一般的なアプリケーションでは、1280x720 や 1920x1080 などの高解像度の画像を使用して、カメラから離れた場所からバーコードをスキャンすることをおすすめします。

    ただし、レイテンシが重要なアプリケーションでは、低解像度で画像をキャプチャすることでパフォーマンスを改善できますが、バーコードで入力画像の大部分を構成する必要があります。リアルタイムのパフォーマンスを改善するためのヒントもご覧ください。

1. バーコード スキャナの設定

読み取りが想定されているバーコード形式がわかっている場合は、その形式のみをスキャンするように構成することで、バーコード スキャナの速度を向上させることができます。

たとえば、Aztec コードと QR コードのみをスキャンするには、次の例のように BarcodeScannerOptions オブジェクトをビルドします。

Swift

let format = .all
let barcodeOptions = BarcodeScannerOptions(formats: format)
  

次の形式がサポートされています。

  • コード 128
  • コード 39
  • コード 93
  • CodaBar
  • dataMatrix
  • EAN13
  • EAN8
  • ITF
  • QR コード
  • UPCA
  • 上へ
  • PDF417
  • Aztec

Objective-C

MLKBarcodeScannerOptions *options =
  [[MLKBarcodeScannerOptions alloc]
   initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];

次の形式がサポートされています。

  • Code-128(MLKBarcodeFormatCode128
  • Code-39(MLKBarcodeFormatCode39
  • Code-93(MLKBarcodeFormatCode93
  • コダバー(MLKBarcodeFormatCodaBar
  • データ マトリックス(MLKBarcodeFormatDataMatrix
  • EAN-13(MLKBarcodeFormatEAN13
  • EAN-8(MLKBarcodeFormatEAN8
  • ITF(MLKBarcodeFormatITF
  • QR コード(MLKBarcodeFormatQRCode
  • UPC-A(MLKBarcodeFormatUPCA
  • UPC-E(MLKBarcodeFormatUPCE
  • PDF-417(MLKBarcodeFormatPDF417
  • アズテック コード(MLKBarcodeFormatAztec

2. 入力画像を準備する

画像内のバーコードをスキャンするには、画像を UIImage または CMSampleBufferRef として BarcodeScannerprocess() または 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;
   }
 }

リアルタイムのパフォーマンスを改善するためのヒント

リアルタイムのアプリケーションでバーコードをスキャンする場合は、適切なフレームレートを得るために次のガイドラインに従ってください。

  • カメラのネイティブ解像度で入力をキャプチャしないでください。一部のデバイスでは、ネイティブ解像度で入力をキャプチャすると非常に大きな(10 メガピクセル以上)画像が生成されるため、レイテンシが極めて低く、精度が向上することはありません。代わりに、バーコード スキャンに必要なサイズ(通常は 2 メガピクセル以下)のみをカメラにリクエストしてください。

    ただし、名前付きキャプチャ セッションのプリセット(AVCaptureSessionPresetDefaultAVCaptureSessionPresetLowAVCaptureSessionPresetMedium など)は、一部のデバイスで不適切な解像度にマッピングできるため、おすすめしません。代わりに、AVCaptureSessionPreset1280x720 などの特定のプリセットを使用してください。

    スキャン速度が重要な場合は、画像キャプチャ解像度をさらに下げることができます。ただし、前述の最小バーコード サイズの要件に注意してください。

    ストリーミング動画フレームのシーケンスからバーコードを認識しようとすると、認識機能によってフレームごとに異なる結果が生成されることがあります。同じ値が連続して表示されるまで待ってから、良い結果が返されることを確認してください。

    ITF と CODE-39 では、チェックサムの数字はサポートされていません。

  • 動画フレームを処理するには、検出機能の results(in:) 同期 API を使用します。AVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, didOutput:from:) 関数からこのメソッドを呼び出して、指定された動画フレームから同期的に結果を取得します。AVCaptureVideoDataOutputalwaysDiscardsLateVideoFramestrue のままにして、検出機能の呼び出しを絞り込みます。検出器の実行中に新しい動画フレームが使用可能になると、そのフレームは破棄されます。
  • 検出器の出力を使用して入力画像の上にグラフィックスをオーバーレイする場合は、まず ML Kit から検出結果を取得し、画像とオーバーレイを 1 つのステップでレンダリングします。これにより、処理済みの入力フレームごとにディスプレイ サーフェスへのレンダリングが 1 回だけ行われます。例については、ML Kit クイックスタート サンプルの updatePreviewOverlayViewWithLastFrame をご覧ください。