С помощью ML Kit можно распознавать и декодировать штрихкоды.
Попробовать
- Попробуйте поработать с примером приложения, чтобы понять, как использовать этот API.
Подготовка
- Добавьте в Podfile следующие контейнеры ML Kit:
pod 'GoogleMLKit/BarcodeScanning', '8.0.0'
- После установки или обновления Pods откройте проект Xcode, используя файл
.xcworkspace. ML Kit поддерживается в Xcode версии 12.4 и более поздних.
Требования к исходным изображениям
-
Чтобы ML Kit мог точно считывать штрихкоды, на входных изображениях они должны быть представлены достаточным количеством пикселей.
Требования к пикселям зависят от типа штрихкода и объема закодированных в нем данных, поскольку многие штрихкоды поддерживают полезную нагрузку переменного размера. Как правило, ширина самого узкого элемента штрихкода должна составлять не менее двух пикселей, а высота – не менее двух пикселей (для двумерных кодов).
Например, штрихкод EAN-13 состоит из полос и пробелов шириной 1, 2, 3 или 4 единицы, поэтому в идеале ширина полос и пробелов в изображении штрихкода EAN-13 должна составлять не менее 2, 4, 6 и 8 пикселей. Поскольку штрихкод EAN-13 имеет ширину 95 единиц, его ширина должна составлять не менее 190 пикселей.
Для более плотных форматов, таких как PDF417, требуются большие размеры пикселей, чтобы ML Kit мог их надежно считывать. Например, код PDF417 может содержать до 34 "слов" шириной 17 единиц в одной строке, что в идеале должно быть не менее 1156 пикселей в ширину.
-
Плохая фокусировка изображения может повлиять на точность сканирования. Если приложение не получает приемлемых результатов, попросите пользователя сделать снимок ещё раз.
-
Для типичных приложений рекомендуется использовать изображения с более высоким разрешением, например 1280 x 720 или 1920 x 1080, чтобы штрихкоды можно было сканировать с большего расстояния от камеры.
Однако в приложениях, где важна задержка, можно повысить производительность, захватывая изображения с более низким разрешением, но требуя, чтобы штрихкод занимал большую часть входного изображения. Также ознакомьтесь с советами по повышению эффективности в реальном времени.
1. Настройте сканер штрихкодов
Если вы знаете, какие форматы штрихкодов вам нужны, вы можете ускорить работу сканера, настроив его на сканирование только этих форматов.Например, чтобы сканировать только коды Aztec и QR-коды, создайте объект BarcodeScannerOptions, как показано в следующем примере:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
Поддерживаются следующие форматы:
- code128
- code39
- code93
- codaBar
- dataMatrix
- EAN 13
- EAN 8
- ITF
- qrCode
- UPCA
- UPCE
- PDF417
- Aztec
Objective-C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
Поддерживаются следующие форматы:
- Code-128 (
MLKBarcodeFormatCode128) - Code-39 (
MLKBarcodeFormatCode39) - Code-93 (
MLKBarcodeFormatCode93) - Codabar (
MLKBarcodeFormatCodaBar) - Data Matrix (
MLKBarcodeFormatDataMatrix) - EAN-13 (
MLKBarcodeFormatEAN13) - EAN-8 (
MLKBarcodeFormatEAN8) - ITF (
MLKBarcodeFormatITF) - QR-код (
MLKBarcodeFormatQRCode) - UPC-A (
MLKBarcodeFormatUPCA) - UPC-E (
MLKBarcodeFormatUPCE) - PDF-417 (
MLKBarcodeFormatPDF417) - Код Aztec (
MLKBarcodeFormatAztec)
2. Подготовьте исходное изображение
Чтобы отсканировать штрихкоды на изображении, передайте изображение в видеUIImage или CMSampleBufferRef в метод process() или results(in:) класса BarcodeScanner:
Создайте объект VisionImage, используя UIImage или CMSampleBuffer.
Если вы используете UIImage, выполните следующие действия:
- Создайте объект
VisionImageсUIImage. Убедитесь, что вы указали правильное значение параметра.orientation.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Если вы используете CMSampleBuffer, выполните следующие действия:
-
Укажите ориентацию данных изображения, содержащихся в элементе
CMSampleBuffer.Чтобы получить ориентацию изображения:
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; } }
- Создайте объект
VisionImage, используя объектCMSampleBufferи ориентацию: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
Получите экземпляр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. Обработка изображения
Затем передайте изображение методуprocess():
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. Как получать информацию из штрихкодов
Если сканирование штрихкода прошло успешно, сканер возвращает массив объектовBarcode. Каждый объект Barcode представляет собой штрихкод, обнаруженный на изображении. Для каждого штрихкода можно получить его координаты на входном изображении, а также первичные данные, закодированные в штрихкоде. Кроме того, если сканер штрихкодов смог определить тип данных, закодированных в штрихкоде, вы можете получить объект, содержащий обработанные данные.
Пример:
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; } }
Советы по повышению эффективности в реальном времени
Если вы хотите сканировать штрих-коды в приложении реального времени, следуйте этим рекомендациям, чтобы добиться наилучшей частоты кадров:
-
Не снимайте видео в исходном разрешении камеры. На некоторых устройствах при съемке в собственном разрешении получаются очень большие изображения (более 10 мегапикселей), что приводит к очень большой задержке без какого-либо улучшения точности. Вместо этого запрашивайте у камеры только тот размер, который необходим для сканирования штрихкодов. Обычно это не более двух мегапикселей.
Использовать именованные предустановки сеанса съемки (
AVCaptureSessionPresetDefault,AVCaptureSessionPresetLow,AVCaptureSessionPresetMediumи т. д.) не рекомендуется, поскольку на некоторых устройствах они могут быть сопоставлены с неподходящим разрешением. Вместо этого используйте определенные настройки, напримерAVCaptureSessionPreset1280x720.Если скорость сканирования важна, вы можете дополнительно снизить разрешение фотосъемки. Однако учитывайте минимальные требования к размеру штрихкода, указанные выше.
Если вы пытаетесь распознать штрихкоды на последовательности кадров потокового видео, распознаватель может выдавать разные результаты для разных кадров. Чтобы быть уверенными в результате, дождитесь, пока не получите несколько одинаковых значений подряд.
Контрольная цифра не поддерживается для ITF и CODE-39.
- Для обработки кадров видео используйте синхронный API детектора
results(in:). Вызовите этот метод из функцииcaptureOutput(_, didOutput:from:)объектаAVCaptureVideoDataOutputSampleBufferDelegate, чтобы синхронно получить результаты для заданного кадра видео. Установите для параметраAVCaptureVideoDataOutputзначениеalwaysDiscardsLateVideoFrames, чтобы ограничить количество вызовов детектора.trueЕсли во время работы детектора станет доступен новый кадр видео, он будет пропущен. - Если вы используете выходные данные детектора для наложения графики на входное изображение, сначала получите результат из ML Kit, а затем визуализируйте изображение и наложение за один шаг. Это позволит вам выполнять рендеринг на поверхности экрана только один раз для каждого обработанного входного кадра. Пример можно найти в разделе updatePreviewOverlayViewWithLastFrame в руководстве по быстрому началу работы с ML Kit.