Barcodes mit ML Kit unter iOS scannen

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

  • Probieren Sie die Beispiel-App aus, um ein Beispiel für die Verwendung dieser API zu sehen.

Hinweis

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

Richtlinien für Eingabebilder

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

    Die spezifischen Pixeldatenanforderungen hängen sowohl vom Barcodetyp als auch von der Datenmenge ab, die in ihm codiert ist, da viele Barcodes eine Nutzlast mit variabler Größe unterstützen. Im Allgemeinen sollte die kleinste aussagekräftige Einheit des Barcodes mindestens 2 Pixel breit und für zweidimensionale Codes 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-Barcodebild 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.

    Dichtere Formate wie PDF417 benötigen größere Pixelabmessungen, damit das ML Kit sie zuverlässig lesen kann. Ein PDF417-Code kann beispielsweise bis zu 34 breite 17-Einheiten-Wörter in einer einzigen Zeile enthalten, die idealerweise mindestens 1.156 Pixel breit sind.

  • Ein schlechter Bildfokus kann die Genauigkeit des Scans beeinträchtigen. Wenn deine App keine akzeptablen Ergebnisse liefert, bitte den Nutzer, das Bild neu aufzunehmen.

  • Für typische Anwendungen wird empfohlen, ein Bild mit höherer Auflösung bereitzustellen, z. B. 1280 × 720 oder 1920 × 1080. Dadurch können Barcodes aus größerer Entfernung von der Kamera gescannt werden.

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

1. Barcode-Scanner konfigurieren

Wenn Sie wissen, welche Barcodeformate Sie lesen möchten, können Sie die Geschwindigkeit des Barcodescanners verbessern, indem Sie den Scan 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
  • Code39
  • Code93
  • CodaBar
  • DataMatrix
  • EAN13
  • EAN8
  • Logo: ITF
  • QR-Code
  • UPCA-Nummer
  • 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

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

Erstelle ein VisionImage-Objekt mit einem UIImage oder einem CMSampleBuffer.

Wenn Sie UIImage verwenden, gehen Sie so vor:

  • Erstellen Sie ein VisionImage-Objekt mit UIImage. Gib die richtige .orientation an.

    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;
      }
    }
          
  • Erstelle ein VisionImage-Objekt mit dem CMSampleBuffer-Objekt 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. Instanz von BarcodeScanner 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 das Bild dann 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 Koordinaten 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 mit geparsten Daten abrufen.

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 den Eingang mit der nativen Auflösung der Kamera nicht auf. Auf einigen Geräten liefert die Aufnahme der Eingabe mit nativer Auflösung extrem große Bilder (über 10 Megapixel). Das führt zu einer sehr schlechten Latenz, ohne dass die Genauigkeit beeinträchtigt wird. Fordern Sie stattdessen nur die für den Barcodescan erforderliche Größe von der Kamera an, die normalerweise nicht mehr als 2 Megapixel beträgt.

    Die benannten Vorgaben für die Erfassungssitzung – AVCaptureSessionPresetDefault, AVCaptureSessionPresetLow, AVCaptureSessionPresetMedium usw.) werden jedoch nicht empfohlen, da sie sich auf einigen Geräten auf ungeeignete Auflösungen zuordnen können. Verwende stattdessen die spezifischen Voreinstellungen, z. B. AVCaptureSessionPreset1280x720.

    Wenn die Scangeschwindigkeit wichtig ist, können Sie die Auflösung der Bildaufnahme weiter verringern. Beachten Sie jedoch die oben genannten Mindestanforderungen an die Barcodegröße.

    Wenn Sie versuchen, Barcodes aus einer Sequenz von Streaming-Videoframes zu erkennen, kann die Erkennung unterschiedliche Ergebnisse von Frame zu Frame liefern. Sie sollten warten, bis Sie eine aufeinanderfolgende Serie desselben Werts erhalten, um sicher zu sein, 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 results(in:) des Detektors. Rufe diese Methode aus der Funktion AVCaptureVideoDataOutputSampleBufferDelegate captureOutput(_, didOutput:from:) auf, um synchron Ergebnisse aus dem angegebenen Videoframe zu erhalten. Behalten Sie AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames bei true, um Aufrufe an den Detektor zu drosseln. Wenn während der Ausführung des Detektors ein neuer Videoframe verfügbar ist, wird er gelöscht.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf dem Eingabebild einzublenden, rufen Sie zuerst das Ergebnis aus ML Kit ab und rendern Sie dann das Bild und das Overlay in einem einzigen Schritt. Dadurch wird die Darstellung für jeden verarbeiteten Eingabeframe nur einmal auf der Anzeigeoberfläche gerendert. Ein Beispiel findest du im Beispiel zu updateVorschauOverlayViewWithLastFrame im ML Kit-Kurzanleitungsbeispiel.