Scannen Sie Barcodes mit ML Kit auf iOS

Mit dem ML Kit können Sie Barcodes erkennen und dekodieren.

Bevor Sie beginnen

  1. Wenn Sie Firebase noch nicht zu Ihrer App hinzugefügt haben, befolgen Sie dazu die Schritte im Leitfaden „Erste Schritte“ .
  2. Fügen Sie die ML-Kit-Bibliotheken in Ihre Pod-Datei ein:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    Nachdem Sie die Pods Ihres Projekts installiert oder aktualisiert haben, stellen Sie sicher, dass Sie Ihr Xcode-Projekt mit seinem .xcworkspace öffnen.
  3. Importieren Sie Firebase in Ihre App:

    Schnell

    import Firebase

    Ziel c

    @import Firebase;

Geben Sie Bildrichtlinien ein

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

    Die spezifischen Pixeldatenanforderungen hängen sowohl von der Art des Barcodes als auch von der darin codierten Datenmenge ab (da die meisten Barcodes eine Nutzlast variabler Länge unterstützen). Im Allgemeinen sollte die kleinste aussagekräftige Einheit des Barcodes mindestens 2 Pixel breit (und bei 2-dimensionalen Codes 2 Pixel hoch) sein.

    EAN-13-Barcodes bestehen beispielsweise aus Strichen und Zwischenräumen mit einer Breite von 1, 2, 3 oder 4 Einheiten. Daher weist ein EAN-13-Barcodebild idealerweise Striche und Zwischenräume mit einer Breite von mindestens 2, 4, 6 und auf 8 Pixel breit. Da ein EAN-13-Barcode insgesamt 95 Einheiten breit ist, sollte der Barcode mindestens 190 Pixel breit sein.

    Dichtere Formate wie PDF417 benötigen größere Pixelabmessungen, damit ML Kit sie zuverlässig lesen kann. Beispielsweise kann ein PDF417-Code bis zu 34 „Wörter“ mit einer Breite von 17 Einheiten in einer einzelnen Zeile enthalten, die idealerweise mindestens 1156 Pixel breit wäre.

  • Eine schlechte Bildschärfe kann die Scangenauigkeit beeinträchtigen. Wenn Sie keine akzeptablen Ergebnisse erhalten, bitten Sie den Benutzer, das Bild erneut aufzunehmen.

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

    Bei Anwendungen, bei denen die Latenz entscheidend ist, können Sie die Leistung jedoch verbessern, indem Sie Bilder mit einer niedrigeren Auflösung erfassen, aber verlangen, dass der Barcode den Großteil des Eingabebilds ausmacht. Siehe auch Tipps zur Verbesserung der Echtzeitleistung .

1. Konfigurieren Sie den Barcode-Detektor

Wenn Sie wissen, welche Barcode-Formate Sie voraussichtlich lesen werden, können Sie die Geschwindigkeit des Barcode-Detektors verbessern, indem Sie ihn so konfigurieren, dass er nur diese Formate erkennt.

Um beispielsweise nur Aztec-Code und QR-Codes zu erkennen, erstellen Sie ein VisionBarcodeDetectorOptions Objekt wie im folgenden Beispiel:

Schnell

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

Folgende Formate werden unterstützt:

  • Code128
  • Code39
  • Code93
  • CodaBar
  • EAN13
  • EAN8
  • ITF
  • UPCA
  • UPCE
  • QR-Code
  • PDF417
  • aztekisch
  • Datenmatrix

Ziel c

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

Folgende 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 )
  • Aztec ( FIRVisionBarcodeFormatAztec )
  • Datenmatrix ( FIRVisionBarcodeFormatDataMatrix )

2. Starten Sie den Barcode-Detektor

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

  1. Holen Sie sich eine Instanz von VisionBarcodeDetector :

    Schnell

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

    Ziel 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 seine imageOrientation Eigenschaft .up hat.
    2. Erstellen Sie ein VisionImage Objekt mit dem korrekt gedrehten UIImage . Geben Sie keine Rotationsmetadaten an – der Standardwert .topLeft muss verwendet werden.

      Schnell

      let image = VisionImage(image: uiImage)

      Ziel c

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

    So verwenden Sie ein CMSampleBufferRef :

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

      So erhalten Sie die Bildausrichtung:

      Schnell

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

      Ziel 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:

      Schnell

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

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

      Schnell

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

      Ziel c

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

    Schnell

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

    Ziel c

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

3. Erhalten Sie Informationen aus Barcodes

Wenn die Barcode-Erkennung erfolgreich ist, 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 seine Grenzkoordinaten im Eingabebild sowie die vom Barcode codierten Rohdaten abrufen. Wenn der Barcode-Detektor außerdem die Art der durch den Barcode codierten Daten ermitteln konnte, können Sie ein Objekt erhalten, das analysierte Daten enthält.

Zum Beispiel:

Schnell

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

Ziel 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, befolgen Sie diese Richtlinien, um die besten Bildraten zu erzielen:

  • Erfassen Sie Eingaben nicht mit der nativen Auflösung der Kamera. Auf einigen Geräten führt die Erfassung von Eingaben mit der nativen Auflösung zu extrem großen Bildern (10+ Megapixel), was zu einer sehr geringen Latenz ohne Vorteile für die Genauigkeit führt. Fordern Sie stattdessen von der Kamera nur die Größe an, die für die Barcode-Erkennung erforderlich ist: in der Regel nicht mehr als 2 Megapixel.

    Die benannten Voreinstellungen für Aufnahmesitzungen AVCaptureSessionPresetDefault , AVCaptureSessionPresetLow , AVCaptureSessionPresetMedium usw.) werden jedoch nicht empfohlen, da sie auf einigen Geräten ungeeigneten Auflösungen zugeordnet werden können. Verwenden Sie stattdessen die spezifischen Voreinstellungen wie 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.

  • Gasrufe an den Detektor. Wenn ein neues Videobild verfügbar wird, während der Detektor läuft, löschen Sie das Bild.
  • Wenn Sie die Ausgabe des Detektors verwenden, um Grafiken auf dem Eingabebild zu überlagern, rufen Sie zunächst das Ergebnis vom ML Kit ab und rendern Sie dann das Bild und überlagern Sie es in einem einzigen Schritt. Auf diese Weise rendern Sie für jeden Eingaberahmen nur einmal auf der Anzeigeoberfläche. Ein Beispiel finden Sie in den Klassen „previewOverlayView “ und „FIRDetectionOverlayView“ in der Showcase-Beispiel-App.