Możesz używać ML Kit do rozpoznawania i dekodowania kodów kreskowych.
Wypróbuj
- Przetestuj przykładową aplikację, aby zobaczyć przykładowe użycie tego interfejsu API.
Zanim zaczniesz
- Uwzględnij w podfile te pody ML Kit:
pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
- Gdy zainstalujesz lub zaktualizujesz pody projektu, otwórz projekt Xcode, używając jego
.xcworkspace
. ML Kit jest obsługiwany w Xcode w wersji 12.4 lub nowszej.
Wskazówki dotyczące obrazu wejściowego
-
Aby ML Kit dokładnie odczytywał kody kreskowe, obrazy wejściowe muszą zawierać kody kreskowe reprezentowane przez wystarczającą ilość danych w pikselach.
Konkretne wymagania dotyczące danych pikselowych zależą od typu kodu kreskowego i ilości danych zakodowanych w nim, ponieważ wiele takich kodów obsługuje ładunki o zmiennej wielkości. Zasadniczo najmniejsza istotna jednostka kodu kreskowego powinna mieć co najmniej 2 piksele szerokości, a w przypadku kodów 2-wymiarowych – 2 piksele wysokości.
Na przykład kody kreskowe EAN-13 składają się z pasków i pokoi o szerokości 1, 2, 3 lub 4 jednostek, dzięki czemu obraz z kodem EAN-13 powinien mieć linie o długości co najmniej 2, 4, 6 i 8 pikseli. Kod kreskowy EAN-13 ma łącznie 95 jednostek, dlatego powinien mieć szerokość co najmniej 190 pikseli.
Formaty dengi, takie jak PDF417, potrzebują większych wymiarów pikseli, aby ML Kit mógł je prawidłowo odczytywać. Na przykład kod PDF może zawierać do 34 jednostek o szerokości 17 jednostek w jednym wierszu. Najlepiej, aby szerokość wynosiła co najmniej 1156 pikseli.
-
Słaba ostrość obrazu może mieć wpływ na dokładność skanowania. Jeśli aplikacja nie przynosi oczekiwanych wyników, poproś użytkownika o ponowne przechwycenie obrazu.
-
W przypadku typowych aplikacji zalecamy korzystanie z obrazów w wyższej rozdzielczości, takich jak 1280 x 720 lub 1920 x 1080, które pozwalają na skanowanie kodów kreskowych z większej odległości od aparatu.
Jednak w aplikacjach, w których opóźnienie jest kluczowe, możesz poprawić wydajność, przechwytując obrazy w niższej rozdzielczości, ale wymagając, aby kod kreskowy stanowił większość obrazu wejściowego. Zapoznaj się też ze wskazówkami, jak poprawić skuteczność w czasie rzeczywistym.
1. Skonfiguruj skaner kodów kreskowych
Jeśli wiesz, które formaty kodów kreskowych chcesz odczytać, możesz zwiększyć szybkość skanera kodów kreskowych, konfigurując go tylko do skanowania w tych formatach.Aby na przykład skanować tylko kody Aztec i kody QR, utwórz obiekt BarcodeScannerOptions
w następujący sposób:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
Obsługiwane są te formaty:
- kod128
- kod39
- kod93
- codabar
- macierz danych
- EAN13
- EAN8
- ITF
- kod QR
- Kod UPC
- UPC
- PDF417
- Aztec
Objective-C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
Obsługiwane są te formaty:
- Code-128 (
MLKBarcodeFormatCode128
) - Kod-39 (
MLKBarcodeFormatCode39
) - Code-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ć kod kreskowy na obrazie, przekaż go jakoUIImage
lub CMSampleBufferRef
do metody process()
lub results(in:)
BarcodeScanner
:
Utwórz obiekt VisionImage
za pomocą właściwości UIImage
lub CMSampleBuffer
.
Jeśli używasz UIImage
, wykonaj te czynności:
- Utwórz obiekt
VisionImage
z elementemUIImage
. Pamiętaj o prawidłowej wartości.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 obrazu zawartych w elemencie
CMSampleBuffer
.Aby uzyskać 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ą obiektuCMSampleBuffer
i orientacji: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 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. Przetwórz obraz
Następnie przekaż obraz za pomocą 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 kodów kreskowych zakończy się powodzeniem, 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 jego granicy na obrazie wejściowym oraz nieprzetworzone dane zakodowane w kodzie kreskowym. Jeśli skaner kodów kreskowych potrafi określić typ danych zakodowanych w kodzie kreskowym, możesz uzyskać obiekt zawierający przeanalizowane dane.
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 zwiększania skuteczności w czasie rzeczywistym
Jeśli chcesz skanować kody kreskowe w aplikacji w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, by uzyskać optymalną liczbę klatek na sekundę:
-
Nie przechwytuj danych wejściowych w natywnej rozdzielczości kamery. Na niektórych urządzeniach rejestrowanie danych w rozdzielczości natywnej generuje bardzo duże (ponad 10 megapikseli) zdjęcia, co przekłada się na bardzo małe opóźnienie i niekorzystny wpływ na dokładność. Wystarczy, że poprosisz o rozmiar z kamery, który jest wymagany do skanowania kodów kreskowych (zwykle nie więcej niż 2 megapiksele).
Nie zalecamy jednak stosowania gotowych ustawień sesji przechwytywania (
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
itd.), ponieważ mogą one mapować na nieodpowiednie rozdzielczości na niektórych urządzeniach. Zamiast tego użyj gotowych ustawień, np.AVCaptureSessionPreset1280x720
.Jeśli szybkość skanowania jest ważna, możesz jeszcze bardziej obniżyć rozdzielczość przechwytywania obrazu. Pamiętaj jednak o minimalnych wymaganiach dotyczących kodu kreskowego opisanych powyżej.
Jeżeli próbujesz rozpoznać kody kreskowe z sekwencji strumieniowej transmisji wideo, moduł rozpoznawania może zwracać różne wyniki z każdej klatki. Zaczekaj, aż otrzymasz kolejną serię o tej samej wartości, by mieć pewność, że zwracasz dobry wynik.
Cyfra sumy kontrolnej nie jest obsługiwana w przypadku ITF i CODE-39.
- Aby przetworzyć ramki wideo, użyj synchronicznego interfejsu API detektora
results(in:)
. Wywołaj tę metodę za pomocą funkcjicaptureOutput(_, didOutput:from:)
AVCaptureVideoDataOutputSampleBufferDelegate
, aby synchronicznie uzyskać wyniki z danej klatki filmu. Aby ograniczyć liczbę wywołań wykrywania, zachowajalwaysDiscardsLateVideoFrames
AVCaptureVideoDataOutput
. Jeśli nowa reguła wideo stanie się dostępna podczas działania wzorca do wykrywania treści, zostanie usunięta. - Jeśli używasz danych wyjściowych wzorca do nakładania grafiki na obrazie wejściowym, najpierw pobierz wynik z ML Kit, a następnie wyrenderuj obraz i nakładkę w jednym kroku. Dzięki temu renderowanie każdej klatki będzie renderowane tylko raz dla każdej przetworzonej klatki wejściowej. Przykład znajdziesz w przykładzie updatepreviewOverlayViewWithLastFrame w przykładzie ML Kit.