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
- Fügen Sie die folgenden ML Kit-Pods in Ihre Podfile ein:
pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
- 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 alsUIImage
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 mitUIImage
. 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 ObjektCMSampleBuffer
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 vonBarcodeScanner
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 Methodeprocess()
:
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 vonBarcode
-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 diecaptureOutput(_, didOutput:from:)
-Funktion derAVCaptureVideoDataOutputSampleBufferDelegate
auf, um synchron Ergebnisse aus dem angegebenen Videoframe zu erhalten. Behalten SiealwaysDiscardsLateVideoFrames
vonAVCaptureVideoDataOutput
alstrue
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.