Barcodes mit ML Kit unter iOS scannen

Mit ML Kit können Sie Barcodes erkennen und decodieren.

Testen

  • Probieren Sie die Beispiel-App aus, um sich ein Anwendungsbeispiel dieser API anzusehen.

Hinweis

  1. Fügen Sie die folgenden ML Kit-Pods in Ihre Podfile ein:
    pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
    
  2. Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, öffnen Sie das Xcode-Projekt mit dessen .xcworkspace. ML Kit wird ab Xcode Version 12.4 unterstützt.

Richtlinien für Eingabebilder

  • Damit ML Kit Barcodes richtig lesen kann, müssen Eingabebilder Barcodes enthalten, die durch genügend Pixeldaten dargestellt werden.

    Die spezifischen Anforderungen an Pixeldaten hängen sowohl vom Barcodetyp als auch von der Menge der codierten Daten ab, da viele Barcodes eine Nutzlast mit variabler Größe unterstützen. Im Allgemeinen sollte die kleinste Einheit eines Barcodes mindestens 2 Pixel breit sein. Bei zweidimensionalen Codes sollte sie mindestens 2 Pixel hoch sein.

    EAN-13-Barcodes bestehen beispielsweise aus Balken und Leerzeichen, die 1, 2, 3 oder 4 Einheiten breit sind. Ein EAN-13-Barcode-Bild hat also idealerweise Balken und Leerzeichen, die mindestens 2, 4, 6 und 8 Pixel breit sind. Da ein EAN-13-Barcode insgesamt 95 Einheiten hat, sollte er mindestens 190 Pixel breit sein.

    Kompaktere Formate wie PDF417 erfordern größere Pixelabmessungen, damit ML Kit sie zuverlässig lesen kann. Ein PDF417-Code kann beispielsweise bis zu 34 Wörter vom Typ „17 Einheiten“ in einer einzelnen Zeile enthalten, die idealerweise mindestens 1.156 Pixel breit sind.

  • Ein schlechter Bildfokus kann die Scangenauigkeit beeinträchtigen. Wenn deine App keine akzeptablen Ergebnisse liefert, bitte den Nutzer, das Bild noch einmal aufzunehmen.

  • Für typische Anwendungen wird empfohlen, ein Bild mit höherer Auflösung wie 1280 x 720 oder 1920 x 1080 bereitzustellen. Dadurch lassen sich Barcodes aus größerer Entfernung von der Kamera scannen.

    In Anwendungen, in denen die Latenz entscheidend ist, können Sie die Leistung jedoch verbessern, indem Sie Bilder mit einer geringeren Auflösung erfassen. Dabei muss jedoch der Barcode den Großteil des Eingabebilds ausmachen. Weitere Informationen finden Sie unter Tipps zur Verbesserung der Echtzeitleistung.

1. Barcode-Scanner konfigurieren

Wenn Sie wissen, welche Barcode-Formate Sie lesen möchten, können Sie den Barcode-Scanner schneller machen, indem Sie ihn so konfigurieren, dass nur diese Formate gescannt werden.

Wenn Sie beispielsweise nur Azteken- und QR-Codes scannen möchten, erstellen Sie ein BarcodeScannerOptions-Objekt wie im folgenden Beispiel:

Swift

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

Die folgenden Formate werden unterstützt:

  • Code128
  • Code 39
  • Code 93
  • CodaBar
  • DataMatrix
  • EAN13
  • EAN8
  • IT-Team
  • QR-Code
  • UPCA
  • UPC
  • PDF417
  • Aztec

Objective-C

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

Die folgenden Formate werden unterstützt:

  • Code-128 (MLKBarcodeFormatCode128)
  • Code-39 (MLKBarcodeFormatCode39)
  • Code-93 (MLKBarcodeFormatCode93)
  • Codabar (MLKBarcodeFormatCodaBar)
  • Data Matrix (MLKBarcodeFormatDataMatrix)
  • EAN-13 (MLKBarcodeFormatEAN13)
  • EAN-8 (MLKBarcodeFormatEAN8)
  • ITF (MLKBarcodeFormatITF)
  • QR-Code (MLKBarcodeFormatQRCode)
  • UPC-A (MLKBarcodeFormatUPCA)
  • UPC-E (MLKBarcodeFormatUPCE)
  • PDF-417 (MLKBarcodeFormatPDF417)
  • Aztekischer Code (MLKBarcodeFormatAztec)

2. Eingabebild vorbereiten

Um Barcodes in einem Bild zu scannen, übergeben Sie das Bild als UIImage oder CMSampleBufferRef an die Methode process() oder results(in:) von BarcodeScanner:

Erstellen Sie ein VisionImage-Objekt mit einem UIImage oder einem CMSampleBuffer.

Wenn Sie UIImage verwenden, gehen Sie so vor:

  • Erstellen Sie ein VisionImage-Objekt mit UIImage. Achten Sie darauf, die richtige .orientation anzugeben.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Wenn Sie CMSampleBuffer verwenden, gehen Sie so vor:

  • Gib die Ausrichtung der Bilddaten an, die in CMSampleBuffer enthalten sind.

    So erhalten Sie die Bildausrichtung:

    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;
      }
    }
          
  • Erstellen Sie ein VisionImage-Objekt mit dem Objekt CMSampleBuffer und der Ausrichtung:

    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-Instanz abrufen

Rufen Sie eine Instanz von BarcodeScanner ab:

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. Bild verarbeiten

Übergeben Sie dann das Bild an die Methode 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. Informationen von Barcodes abrufen

Wenn der Barcode-Scanvorgang erfolgreich ist, gibt der Scanner ein Array von Barcode-Objekten zurück. Jedes Barcode-Objekt stellt einen Barcode dar, der im Bild erkannt wurde. Für jeden Barcode können Sie seine Begrenzungskoordinaten im Eingabebild sowie die durch den Barcode codierten Rohdaten abrufen. Wenn der Barcode-Scanner den vom Barcode codierten Datentyp ermitteln konnte, können Sie ein Objekt abrufen, das geparste Daten enthält.

Beispiel:

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;
   }
 }

Tipps zur Verbesserung der Echtzeitleistung

Wenn Sie Barcodes in einer Echtzeitanwendung scannen möchten, beachten Sie die folgenden Richtlinien, um die besten Framerates zu erzielen:

  • Nehmen Sie bei der nativen Auflösung der Kamera keine Eingaben auf. Auf einigen Geräten liefert die Aufnahme von Eingaben mit nativer Auflösung extrem große Bilder (mehr als 10 Megapixel). Das führt zu einer sehr geringen Latenz ohne Genauigkeitsverlust. Fordern Sie stattdessen nur die Größe der Kamera an, die für das Scannen von Barcodes erforderlich ist. Diese beträgt normalerweise nicht mehr als 2 Megapixel.

    Die benannten Voreinstellungen für die Aufnahmesitzung (AVCaptureSessionPresetDefault, AVCaptureSessionPresetLow, AVCaptureSessionPresetMedium usw.) werden jedoch nicht empfohlen, da sie sich auf manchen Geräten als ungeeignet für Auflösungen erweisen können. Verwende stattdessen die jeweiligen Voreinstellungen, z. B. AVCaptureSessionPreset1280x720.

    Wenn die Scangeschwindigkeit wichtig ist, können Sie die Auflösung der Bildaufnahme weiter verringern. Beachten Sie jedoch die oben aufgeführten Mindestanforderungen an den Barcode.

    Wenn Sie versuchen, Barcodes aus einer Reihe von gestreamten Videoframes zu erkennen, kann die Erkennung von Frame zu Frame unterschiedliche Ergebnisse liefern. Sie sollten warten, bis Sie eine aufeinanderfolgende Reihe desselben Werts erhalten, damit Sie sicher sind, dass Sie ein gutes Ergebnis zurückgeben.

    Die Prüfziffer wird für ITF und CODE-39 nicht unterstützt.

  • Verwenden Sie zur Verarbeitung von Videoframes die synchrone API des Detektors results(in:). Rufen Sie diese Methode über die captureOutput(_, didOutput:from:)-Funktion der AVCaptureVideoDataOutputSampleBufferDelegate auf, um synchron Ergebnisse aus dem angegebenen Videoframe zu erhalten. Behalten Sie alwaysDiscardsLateVideoFrames von AVCaptureVideoDataOutput als true bei, um Aufrufe an den Detektor zu drosseln. Wenn während der Ausführung des Detektors ein neuer Videoframe verfügbar ist, wird er verworfen.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf dem Eingabebild einzublenden, rufen Sie zuerst das Ergebnis aus ML Kit ab und rendern dann das Bild und das Overlay in einem einzigen Schritt. Dadurch wird die Anzeige für jeden verarbeiteten Eingabeframe nur einmal auf der Anzeigeoberfläche gerendert. Ein Beispiel findest du in der Kurzanleitung zu updatePreviewOverlayViewWithLastFrame.