Do rozpoznawania i dekodowania kodów kreskowych możesz używać pakietu ML Kit.
Wypróbuj
- Wypróbuj przykładową aplikację, aby: zobaczysz przykład użycia tego interfejsu API.
Zanim zaczniesz
- W pliku Podfile umieść te pody ML Kit:
pod 'GoogleMLKit/BarcodeScanning', '15.5.0'
- Po zainstalowaniu lub zaktualizowaniu podów projektu otwórz projekt Xcode za pomocą
.xcworkspace
ML Kit jest obsługiwany w Xcode w wersji 12.4 lub nowszej.
Wytyczne dotyczące obrazu wejściowego
-
Aby ML Kit mógł dokładnie odczytywać kody kreskowe, obrazy wejściowe muszą zawierać również kody kreskowe, które są reprezentowane przez wystarczającą ilość danych pikseli.
Konkretne wymagania dotyczące danych pikseli zależą od typu i ilości zakodowanych w nim danych, ponieważ wiele kodów kreskowych obsługują ładunek o zmiennym rozmiarze. Ogólnie rzecz biorąc, najmniej istotne musi mieć co najmniej 2 piksele szerokości, a w przypadku Dwuwymiarowe kody o wysokości 2 pikseli.
Na przykład kody kreskowe EAN-13 składają się z kresek i spacji oznaczonych znakiem 1, 2, 3 lub 4 jednostki szerokości, więc na obrazie z kodem kreskowym EAN-13 powinny być słupki i o szerokości co najmniej 2, 4, 6 lub 8 pikseli. Ponieważ kod EAN-13 Kod kreskowy ma łącznie 95 jednostek szerokości, a kod kreskowy powinien mieć co najmniej 190 jednostek. pikseli szerokości ekranu.
Formaty o większej gęstości, np. PDF417, wymagają większych wymiarów w pikselach ML Kit. Na przykład kod PDF417 może mieć maksymalnie 34 „słowa” o szerokości 17 jednostek w jednym wierszu, czyli przynajmniej 1156 pikseli szerokości.
-
Słaba ostrość obrazu może mieć wpływ na dokładność skanowania. Jeśli aplikacja nie pojawia się akceptowalne, poproś użytkownika o ponowne wykonanie zdjęcia.
-
W typowych zastosowaniach zaleca się podanie wyższej wartości obrazu o rozdzielczości, np. 1280 x 720 lub 1920 x 1080, który tworzy kody kreskowe i można je zeskanować z większej odległości od aparatu.
Jednak w aplikacjach, w których opóźnienia są kluczowe, można poprawić dzięki możliwości robienia zdjęć w niższej rozdzielczości, ale wymagając kod kreskowy stanowi większość zdjęcia wejściowego. Zobacz też Wskazówki, jak zwiększyć skuteczność w czasie rzeczywistym.
1. Konfigurowanie skanera kodów kreskowych
Wiedząc, jakie formaty kodu kreskowego spodziewasz się odczytać, możesz zwiększyć szybkość skanera kodów paskowych przez skonfigurowanie w nim skanowania tylko tych formatów.Aby np. zeskanować tylko kod Aztec i kody QR, utwórz
BarcodeScannerOptions
, taki jak
następujący przykład:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
Obsługiwane formaty:
- code128
- code39
- code93
- codaBar
- dataMatrix
- EAN13
- EAN8
- ITF
- qrCode
- UPCA
- UPCE
- PDF417
- Aztec
Objective-C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
Obsługiwane formaty:
- Kod-128 (
MLKBarcodeFormatCode128
) - Kod-39 (
MLKBarcodeFormatCode39
) - Kod-93 (
MLKBarcodeFormatCode93
) - Codabar (
MLKBarcodeFormatCodaBar
) - Macierz danych (
MLKBarcodeFormatDataMatrix
) - EAN-13 (
MLKBarcodeFormatEAN13
) - EAN-8 (
MLKBarcodeFormatEAN8
) - ITF (
MLKBarcodeFormatITF
) - Kod QR (
MLKBarcodeFormatQRCode
) - UPC-A (
MLKBarcodeFormatUPCA
) - UPC-E (
MLKBarcodeFormatUPCE
) - PDF-417 (
MLKBarcodeFormatPDF417
) - Kod Aztecki (
MLKBarcodeFormatAztec
)
2. Przygotowywanie obrazu wejściowego
Aby skanować kody kreskowe na obrazie, przekaż go w formacieUIImage
lub
CMSampleBufferRef
na: process()
lub results(in:)
BarcodeScanner
:
Utwórz obiekt VisionImage
za pomocą UIImage
lub
CMSampleBuffer
.
Jeśli używasz UIImage
, wykonaj te czynności:
- Utwórz obiekt
VisionImage
za pomocąUIImage
. Pamiętaj, by określić prawidłowy.orientation
.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Jeśli używasz CMSampleBuffer
, wykonaj te czynności:
-
Określ orientację danych zdjęć zawartych w pliku
CMSampleBuffer
Aby sprawdzić orientację obrazu:
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; } }
- Utwórz obiekt
VisionImage
za pomocąCMSampleBuffer
obiekt i orientacja: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. Pobieranie instancji BarcodeScanner
Pobierz instancjęBarcodeScanner
:
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. Przetwarzanie zdjęcia
Następnie przekaż obraz do metodyprocess()
:
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. Uzyskiwanie informacji z kodów kreskowych
Jeśli skanowanie kodu się powiedzie, skaner zwróci tablicęBarcode
obiektów. Każdy obiekt Barcode
reprezentuje
kodu kreskowego wykrytego na zdjęciu. Dla każdego kodu kreskowego można sprawdzić jego wartość
współrzędnych ograniczających w obrazie wejściowym, jak i nieprzetworzonych danych zakodowanych przez
kodu kreskowego. Ponadto, jeśli skaner kodów kreskowych był w stanie określić typ danych
zakodowanym kodem kreskowym, otrzymasz obiekt zawierający przeanalizowane dane.
Na przykład:
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; } }
Wskazówki dotyczące poprawy skuteczności w czasie rzeczywistym
Jeśli chcesz skanować kody kreskowe za pomocą aplikacji działającej w czasie rzeczywistym, postępuj zgodnie z tymi wytycznych dotyczących uzyskiwania najlepszej liczby klatek na sekundę:
-
Nie rejestruj danych wejściowych w rozdzielczości natywnej kamery. Na niektórych urządzeniach przechwytywanie danych wejściowych w rozdzielczości natywnej zapewnia bardzo duże w megapikselach), co skutkuje bardzo małym opóźnieniem bez dokładności. Zamiast tego żądaj od kamery tylko wymaganego rozmiaru dla skanowania kodów kreskowych, które mają zwykle nie więcej niż 2 megapiksele.
Gotowe ustawienia sesji nagrywania nazwanych:
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
itp.) — nie są jednak zalecane, ponieważ mogą odpowiadać w nieodpowiednich rozdzielczościach na niektórych urządzeniach. Zamiast tego użyj określonych gotowych ustawień, na przykładAVCaptureSessionPreset1280x720
.Jeśli szybkość skanowania jest ważna, możesz zmniejszyć zakres skanowania i ich rozwiązania. Należy jednak pamiętać o minimalnym rozmiarze kodu kreskowego. opisane powyżej.
Jeśli próbujesz rozpoznać kody kreskowe z sekwencji transmisji, klatek wideo, moduł rozpoznawania może generować różne wyniki ramki. Zaczekaj, aż otrzymasz kolejną serię daje Ci pewność, że zwracasz dobry wynik.
Cyfra kontrolna nie jest obsługiwana w przypadku ITF i CODE-39.
- Do przetwarzania klatek wideo używaj synchronicznego interfejsu API
results(in:)
detektora. Zadzwoń do nas tę metodę zAVCaptureVideoDataOutputSampleBufferDelegate
.captureOutput(_, didOutput:from:)
, aby synchronicznie pobierać wyniki dotyczące danego filmu ramki. ZachowajAVCaptureVideoDataOutput
:alwaysDiscardsLateVideoFrames
jakotrue
, aby ograniczyć wywołania detektora. Jeśli nowy gdy klatka wideo jest dostępna, gdy jest uruchomiony detektor, zostanie usunięta. - Jeśli użyjesz danych wyjściowych detektora do nakładania grafiki na obrazu wejściowego, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładanie nakładek w jednym kroku. W ten sposób renderowanie na powierzchni tylko raz na każdą przetworzoną ramkę wejściową. Zobacz updatePreviewOverlayViewWithLastFrame. znajdziesz na przykład w krótkim wprowadzeniu do korzystania z ML Kit.