Barcodes mit ML Kit unter iOS scannen

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

Hinweis

  1. Wenn Sie Firebase Ihrer App noch nicht hinzugefügt haben, folgen Sie der Anleitung im Einstiegsleitfaden.
  2. Fügen Sie die ML Kit-Bibliotheken in Ihre Podfile ein:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, öffnen Sie Ihr Xcode-Projekt mit der .xcworkspace.
  3. Importieren Sie Firebase in Ihre App:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

Richtlinien für Eingabebilder

  • Damit ML Kit Barcodes korrekt lesen kann, müssen die Eingabebilder Barcodes enthalten, die durch ausreichende Pixeldaten dargestellt werden.

    Die spezifischen Anforderungen an die Pixeldaten hängen sowohl vom Barcodetyp als auch von der Menge der darin codierten Daten ab, da die meisten Barcodes eine Nutzlast mit variabler Länge unterstützen. Im Allgemeinen sollte die kleinste aussagekräftige Einheit des Barcodes mindestens 2 Pixel breit (und bei zweidimensionalen Codes 2 Pixel hoch) sein.

    EAN-13-Barcodes bestehen beispielsweise aus Balken und Leerräumen, die 1, 2, 3 oder 4 Einheiten breit sind. Ein EAN-13-Barcodebild sollte daher idealerweise Balken und Leerräume mit einer Breite von mindestens 2, 4, 6 und 8 Pixeln haben. Da ein EAN-13-Barcode insgesamt 95 Einheiten breit ist, sollte er mindestens 190 Pixel breit sein.

    Für dichtere Formate wie PDF417 sind größere Pixelabmessungen erforderlich, damit ML Kit sie zuverlässig lesen kann. Ein PDF417-Code kann beispielsweise bis zu 34 „Wörter“ mit 17 Einheiten in einer einzigen Zeile enthalten, die idealerweise mindestens 1.156 Pixel breit sein sollte.

  • Ein unscharfer Bildfokus kann die Scangenauigkeit beeinträchtigen. Wenn Sie keine zufriedenstellenden Ergebnisse erhalten, bitten Sie den Nutzer, das Bild noch einmal aufzunehmen.

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

    Bei Anwendungen, bei denen die Latenz entscheidend ist, können Sie die Leistung jedoch verbessern, indem Sie Bilder mit niedrigerer Auflösung aufnehmen. Der Barcode muss dabei jedoch den Großteil des Eingabebilds ausmachen. Weitere Informationen finden Sie unter Tipps zur Verbesserung der Echtzeitleistung.

1. Barcode-Erkennung konfigurieren

Wenn Sie wissen, welche Barcodeformate gelesen werden sollen, können Sie die Geschwindigkeit des Barcode-Detektors verbessern, indem Sie ihn so konfigurieren, dass nur diese Formate erkannt werden.

Wenn Sie beispielsweise nur Aztec-Code und QR-Codes erkennen möchten, erstellen Sie ein VisionBarcodeDetectorOptions-Objekt wie im folgenden Beispiel:

Swift

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

Die folgenden Formate werden unterstützt:

  • Code128
  • Code39
  • Code93
  • CodaBar
  • EAN13
  • EAN8
  • ITF
  • UPCA
  • UPCE
  • QR-Code
  • PDF417
  • Azteken
  • DataMatrix

Objective-C

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

Die folgenden Formate werden unterstützt:

  • Code 128 (FIRVisionBarcodeFormatCode128)
  • Code 39 (FIRVisionBarcodeFormatCode39)
  • Code 93 (FIRVisionBarcodeFormatCode93)
  • Codabar (FIRVisionBarcodeFormatCodaBar)
  • EAN-13 (FIRVisionBarcodeFormatEAN13)
  • EAN-8 (FIRVisionBarcodeFormatEAN8)
  • ITF (FIRVisionBarcodeFormatITF)
  • UPC-A (FIRVisionBarcodeFormatUPCA)
  • UPC-E (FIRVisionBarcodeFormatUPCE)
  • QR-Code (FIRVisionBarcodeFormatQRCode)
  • PDF417 (FIRVisionBarcodeFormatPDF417)
  • Azteken (FIRVisionBarcodeFormatAztec)
  • Data Matrix (FIRVisionBarcodeFormatDataMatrix)

2. Barcode-Detektor ausführen

Wenn Sie Barcodes in einem Bild scannen möchten, übergeben Sie das Bild als UIImage oder CMSampleBufferRef an die detect(in:)-Methode der VisionBarcodeDetector:

  1. Instanz von VisionBarcodeDetector abrufen:

    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. Erstellen Sie ein VisionImage-Objekt mit einem UIImage oder einem CMSampleBufferRef.

    So verwenden Sie ein UIImage:

    1. Drehen Sie das Bild bei Bedarf so, dass die Property imageOrientation auf .up festgelegt ist.
    2. Erstellen Sie ein VisionImage-Objekt mit dem korrekt gedrehten UIImage. Geben Sie keine Metadaten für die Drehung an. Es muss der Standardwert .topLeft verwendet werden.

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    So verwenden Sie ein CMSampleBufferRef:

    1. Erstellen Sie ein VisionImageMetadata-Objekt, das die Ausrichtung der Bilddaten im CMSampleBufferRef-Puffer angibt.

      So rufen Sie die Bildausrichtung auf:

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

      Erstellen Sie dann das Metadatenobjekt:

      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. Erstelle ein VisionImage-Objekt mit dem CMSampleBufferRef-Objekt und den Rotationsmetadaten:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Übergeben Sie dann das Bild an die detect(in:)-Methode:

    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. Informationen aus Barcodes abrufen

Wenn die Barcodeerkennung erfolgreich war, gibt der Detektor ein Array von VisionBarcode-Objekten zurück. Jedes VisionBarcode-Objekt stellt einen Barcode dar, der im Bild erkannt wurde. Für jeden Barcode können Sie die Begrenzungskoordinaten im Eingabebild sowie die vom Barcode codierten Rohdaten abrufen. Wenn der Barcode-Detektor den Typ der vom Barcode codierten Daten ermitteln konnte, können Sie auch 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 (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;
   }
 }

Tipps zur Verbesserung der Echtzeitleistung

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

  • Erfassen Sie die Eingabe nicht mit der nativen Auflösung der Kamera. Auf einigen Geräten führt die Erfassung der Eingabe in der nativen Auflösung zu extrem großen Bildern (mehr als 10 Megapixel), was zu einer sehr schlechten Latenz führt, ohne dass die Genauigkeit verbessert wird. Fordere stattdessen nur die Größe von der Kamera an, die für die Barcodeerkennung erforderlich ist: in der Regel nicht mehr als 2 Megapixel.

    Die benannten Presets für Aufnahmesitzungen (AVCaptureSessionPresetDefault, AVCaptureSessionPresetLow, AVCaptureSessionPresetMedium usw.) werden jedoch nicht empfohlen, da sie auf einigen Geräten zu ungeeigneten Auflösungen führen können. Verwenden Sie stattdessen die speziellen Voreinstellungen wie AVCaptureSessionPreset1280x720.

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

  • Aufrufe an den Detektor drosseln Wenn während der Laufzeit des Detektors ein neuer Videoframe verfügbar wird, legen Sie ihn ab.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf das Eingabebild zu legen, rufen Sie zuerst das Ergebnis aus ML Kit ab und rendern Sie dann das Bild und das Overlay in einem einzigen Schritt. So wird für jeden Eingabeframe nur einmal auf die Displayoberfläche gerendert. Sehen Sie sich die Klassen previewOverlayView und FIRDetectionOverlayView in der Beispiel-App an.