Możesz używać ML Kit do rozpoznawania i dekodowania kodów kreskowych.
Wypróbuj
- Przyjrzyj się przykładowej aplikacji, aby zobaczyć przykładowe użycie tego interfejsu API.
Zanim zaczniesz
- W pliku Podfile uwzględnij te pody ML Kit:
pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
- Po zainstalowaniu lub zaktualizowaniu podów w projekcie otwórz projekt Xcode, korzystając z jego polecenia
.xcworkspace
. ML Kit obsługuje Xcode w wersji 12.4 lub nowszej.
Zalecenia dotyczące obrazu wejściowego
-
Aby usługa ML Kit mogła dokładnie odczytywać kody kreskowe, obrazy wejściowe muszą zawierać kody kreskowe reprezentowane przez wystarczającą ilość danych pikseli.
Konkretne wymagania dotyczące danych w pikselach zależą zarówno od typu kodu kreskowego, jak i ilości zakodowanych w nim danych, ponieważ wiele takich kodów obsługuje ładunki o zmiennym rozmiarze. Ogólnie najmniejsza znacząca jednostka kodu kreskowego powinna mieć co najmniej 2 piksele szerokości, a dla kodów dwuwymiarowych – 2 piksele wysokości.
Na przykład kody kreskowe EAN-13 składają się ze słupków i spacji o szerokości 1, 2, 3 lub 4 jednostek, dlatego obraz kodu kreskowego EAN-13 powinien mieć co najmniej 2, 4, 6 lub 8 pikseli szerokości. Ponieważ kod kreskowy EAN-13 ma łącznie 95 jednostek, powinien mieć co najmniej 190 pikseli szerokości.
Formaty o większej gęstości, np. PDF417, wymagają większej liczby pikseli, by narzędzie ML Kit mogło je prawidłowo odczytywać. Na przykład kod PDF417 może zawierać w jednym wierszu maksymalnie 34 „słowa” o szerokości 17 jednostek, czyli co najmniej 1156 pikseli szerokości.
-
Słaba ostrość obrazu może obniżyć dokładność skanowania. Jeśli aplikacja nie uzyskuje zadowalających wyników, poproś użytkownika o ponowne wykonanie zdjęcia.
-
W przypadku typowych zastosowań zalecane jest obrazy o wyższej rozdzielczości (np. 1280 x 720 lub 1920 x 1080), dzięki którym kody kreskowe będą skanowane z większej odległości od aparatu.
Jednak w aplikacjach, w których opóźnienia mają kluczowe znaczenie, można poprawić wydajność, robiąc zdjęcia w niższej rozdzielczości, wymagając, aby kod kreskowy zajmował większość obrazu wejściowego. Zobacz też wskazówki dotyczące zwiększania skuteczności w czasie rzeczywistym.
1. Skonfiguruj skaner kodów kreskowych
Jeśli wiesz, które formaty kodów kreskowych zamierzasz odczytać, możesz zwiększyć szybkość skanera kodów kreskowych, konfigurując go do skanowania tylko tych formatów.Aby na przykład zeskanować tylko kod Aztec i kody QR, utwórz obiekt BarcodeScannerOptions
jak w tym przykładzie:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
Obsługiwane są te 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 są te 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. Przygotuj obraz wejściowy
Aby zeskanować kody kreskowe na obrazie, przekaż go jakoUIImage
lub CMSampleBufferRef
do metody process()
lub results(in:)
BarcodeScanner
:
Utwórz obiekt VisionImage
za pomocą UIImage
lub CMSampleBuffer
.
Jeśli używasz urządzenia UIImage
, wykonaj te czynności:
- Utwórz obiekt
VisionImage
za pomocąUIImage
. Pamiętaj, aby podać prawidłową wartość.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 urządzenia CMSampleBuffer
, wykonaj te czynności:
-
Określ orientację danych obrazu w elemencie
CMSampleBuffer
.Aby pobrać orientację:
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
, używając obiektu i orientacjiCMSampleBuffer
: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 aplikacji BarcodeScanner
Pobierz wystąpienieBarcodeScanner
:
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 obrazu
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. Uzyskuj informacje na podstawie kodów kreskowych
Jeśli skanowanie kodu kreskowego się powiedzie, skaner zwróci tablicę obiektówBarcode
. Każdy obiekt Barcode
reprezentuje kod kreskowy wykryty na obrazie. W przypadku każdego kodu kreskowego możesz uzyskać współrzędne ograniczające na obrazie wejściowym, a także nieprzetworzone dane zakodowane przez ten kod. Ponadto, jeśli skaner kodów paskowych rozpoznał typ danych kodowanych za pomocą kodu kreskowego, możesz uzyskać 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 w aplikacji w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:
-
Nie rejestruj danych wejściowych w natywnej rozdzielczości aparatu. Na niektórych urządzeniach nagrywanie danych wejściowych w rozdzielczości natywnej powoduje utworzenie bardzo dużych obrazów (ponad 10 megapikseli), co prowadzi do bardzo małego opóźnienia i braku dokładności. Zamiast tego żądaj z aparatu tylko rozmiaru wymaganego do skanowania kodów kreskowych, czyli zwykle nie więcej niż 2 megapiksele.
Nazwane gotowe ustawienia sesji przechwytywania –
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
itd.) nie są zalecane, ponieważ na niektórych urządzeniach mogą zostać zmapowane na nieodpowiednie rozdzielczości. Zamiast tego użyj określonych gotowych ustawień, takich jakAVCaptureSessionPreset1280x720
.Jeśli szybkość skanowania jest ważna, możesz jeszcze bardziej obniżyć rozdzielczość przechwytywania obrazu. Pamiętaj jednak o minimalnych wymaganiach dotyczących rozmiaru kodu kreskowego wymienionych powyżej.
Jeśli próbujesz rozpoznać kody kreskowe z sekwencji klatek przesyłanych strumieniowo, moduł rozpoznawania może podawać różne wyniki w poszczególnych klatkach. Aby mieć pewność, że uzyskujesz dobry wynik, poczekaj, aż uzyskasz kolejną serię o tej samej wartości.
Cyfra sumy kontrolnej nie jest obsługiwana w przypadku ITF i CODE-39.
- Do przetwarzania klatek wideo użyj synchronicznego interfejsu API
results(in:)
wzorca. Wywołaj tę metodę z funkcjicaptureOutput(_, didOutput:from:)
obiektuAVCaptureVideoDataOutputSampleBufferDelegate
, aby synchronicznie pobierać wyniki z danej klatki wideo. PozostawalwaysDiscardsLateVideoFrames
obiektuAVCaptureVideoDataOutput
jakotrue
, aby ograniczać wywołania do wzorca. Jeśli podczas działania wzorca pojawi się nowa ramka wideo, zostanie ona usunięta. - Jeśli używasz danych wyjściowych wzorca do nakładania grafiki na obraz wejściowy, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu na każdą przetworzoną klatkę wejściową renderujesz się tylko raz. Przykład znajdziesz w sekcji updatePreviewOverlayViewWithLastFrame w przykładowym krótkim wprowadzeniu do ML Kit.