Вы можете использовать ML Kit для распознавания и декодирования штрих-кодов.
Прежде чем начать
- Если вы еще не добавили Firebase в свое приложение, сделайте это, выполнив действия, описанные в руководстве по началу работы .
- Включите библиотеки ML Kit в свой подфайл:
pod 'Firebase/MLVision' pod 'Firebase/MLVisionBarcodeModel'
После установки или обновления модулей вашего проекта обязательно откройте проект Xcode, используя его.xcworkspace
. - Импортируйте Firebase в свое приложение:
Быстрый
import Firebase
Цель-C
@import Firebase;
Рекомендации по входному изображению
Чтобы ML Kit мог точно считывать штрих-коды, входные изображения должны содержать штрих-коды, представленные достаточным количеством пиксельных данных.
Требования к конкретным пиксельным данным зависят как от типа штрих-кода, так и от объема данных, которые в нем закодированы (поскольку большинство штрих-кодов поддерживают полезную нагрузку переменной длины). Как правило, наименьшая значимая единица штрих-кода должна иметь ширину не менее 2 пикселей (а для двумерных кодов — высоту 2 пикселя).
Например, штрих-коды EAN-13 состоят из полос и пробелов шириной 1, 2, 3 или 4 единицы, поэтому изображение штрих-кода EAN-13 в идеале содержит полосы и пробелы длиной не менее 2, 4, 6 и более. Ширина 8 пикселей. Поскольку общая ширина штрих-кода EAN-13 составляет 95 единиц, ширина штрих-кода должна быть не менее 190 пикселей.
Более плотные форматы, такие как PDF417, требуют большего размера в пикселях, чтобы ML Kit мог их надежно читать. Например, код PDF417 может содержать до 34 «слов» шириной 17 единиц в одной строке, которая в идеале должна иметь ширину не менее 1156 пикселей.
Плохая фокусировка изображения может снизить точность сканирования. Если вы не получили приемлемых результатов, попробуйте попросить пользователя повторно сделать снимок.
Для типичных приложений рекомендуется предоставлять изображение с более высоким разрешением (например, 1280x720 или 1920x1080), что позволяет обнаруживать штрих-коды на большем расстоянии от камеры.
Однако в приложениях, где задержка имеет решающее значение, вы можете повысить производительность, захватывая изображения с более низким разрешением, но требуя, чтобы штрих-код составлял большую часть входного изображения. Также см . Советы по повышению производительности в реальном времени .
1. Настройте детектор штрих-кода
Если вы знаете, какие форматы штрих-кодов вы собираетесь считывать, вы можете повысить скорость детектора штрих-кодов, настроив его на обнаружение только этих форматов. Например, чтобы обнаружить только ацтекский код и QR-коды, создайте объект VisionBarcodeDetectorOptions
, как показано в следующем примере:
Быстрый
let format = VisionBarcodeFormat.all let barcodeOptions = VisionBarcodeDetectorOptions(formats: format)
Поддерживаются следующие форматы:
- Код128
- Код39
- Код93
- КодаБар
- EAN13
- EAN8
- МФТ
- УПКА
- УПЦЭ
- QRCод
- PDF417
- ацтекский
- DataMatrix
Цель-C
FIRVisionBarcodeDetectorOptions *options = [[FIRVisionBarcodeDetectorOptions alloc] initWithFormats: FIRVisionBarcodeFormatQRCode | FIRVisionBarcodeFormatAztec];
Поддерживаются следующие форматы:
- Код 128 (
FIRVisionBarcodeFormatCode128
) - Код 39 (
FIRVisionBarcodeFormatCode39
) - Код 93 (
FIRVisionBarcodeFormatCode93
) - Кодабар (
FIRVisionBarcodeFormatCodaBar
) - EAN-13 (
FIRVisionBarcodeFormatEAN13
) - EAN-8 (
FIRVisionBarcodeFormatEAN8
) - ITF (
FIRVisionBarcodeFormatITF
) - UPC-A (
FIRVisionBarcodeFormatUPCA
) - UPC-E (
FIRVisionBarcodeFormatUPCE
) - QR-код (
FIRVisionBarcodeFormatQRCode
) - PDF417 (
FIRVisionBarcodeFormatPDF417
) - Ацтекский (
FIRVisionBarcodeFormatAztec
) - Матрица данных (
FIRVisionBarcodeFormatDataMatrix
)
2. Запустите детектор штрих-кода
Чтобы сканировать штрих-коды в изображении, передайте изображение какUIImage
или CMSampleBufferRef
в метод detect(in:)
VisionBarcodeDetector
:- Получите экземпляр
VisionBarcodeDetector
:Быстрый
lazy var vision = Vision.vision() let barcodeDetector = vision.barcodeDetector(options: barcodeOptions)
Цель-C
FIRVision *vision = [FIRVision vision]; FIRVisionBarcodeDetector *barcodeDetector = [vision barcodeDetector]; // Or, to change the default settings: // FIRVisionBarcodeDetector *barcodeDetector = // [vision barcodeDetectorWithOptions:options];
Создайте объект
VisionImage
используяUIImage
илиCMSampleBufferRef
.Чтобы использовать
UIImage
:- При необходимости поверните изображение так, чтобы его свойство
imageOrientation
имело значение.up
. - Создайте объект
VisionImage
используя правильно повернутыйUIImage
. Не указывайте метаданные вращения — необходимо использовать значение по умолчанию.topLeft
.Быстрый
let image = VisionImage(image: uiImage)
Цель-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Чтобы использовать
CMSampleBufferRef
:Создайте объект
VisionImageMetadata
, который задает ориентацию данных изображения, содержащихся в буфереCMSampleBufferRef
.Чтобы получить ориентацию изображения:
Быстрый
func imageOrientation( deviceOrientation: UIDeviceOrientation, cameraPosition: AVCaptureDevice.Position ) -> VisionDetectorImageOrientation { switch deviceOrientation { case .portrait: return cameraPosition == .front ? .leftTop : .rightTop case .landscapeLeft: return cameraPosition == .front ? .bottomLeft : .topLeft case .portraitUpsideDown: return cameraPosition == .front ? .rightBottom : .leftBottom case .landscapeRight: return cameraPosition == .front ? .topRight : .bottomRight case .faceDown, .faceUp, .unknown: return .leftTop } }
Цель-C
- (FIRVisionDetectorImageOrientation) imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation cameraPosition:(AVCaptureDevicePosition)cameraPosition { switch (deviceOrientation) { case UIDeviceOrientationPortrait: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationLeftTop; } else { return FIRVisionDetectorImageOrientationRightTop; } case UIDeviceOrientationLandscapeLeft: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationBottomLeft; } else { return FIRVisionDetectorImageOrientationTopLeft; } case UIDeviceOrientationPortraitUpsideDown: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationRightBottom; } else { return FIRVisionDetectorImageOrientationLeftBottom; } case UIDeviceOrientationLandscapeRight: if (cameraPosition == AVCaptureDevicePositionFront) { return FIRVisionDetectorImageOrientationTopRight; } else { return FIRVisionDetectorImageOrientationBottomRight; } default: return FIRVisionDetectorImageOrientationTopLeft; } }
Затем создайте объект метаданных:
Быстрый
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Цель-C
FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init]; AVCaptureDevicePosition cameraPosition = AVCaptureDevicePositionBack; // Set to the capture device you used. metadata.orientation = [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation cameraPosition:cameraPosition];
- Создайте объект
VisionImage
используя объектCMSampleBufferRef
и метаданные вращения:Быстрый
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Цель-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- При необходимости поверните изображение так, чтобы его свойство
- Затем передайте изображение методу
detect(in:)
:Быстрый
barcodeDetector.detect(in: visionImage) { features, error in guard error == nil, let features = features, !features.isEmpty else { // ... return } // ... }
Цель-C
[barcodeDetector detectInImage:image completion:^(NSArray<FIRVisionBarcode *> *barcodes, NSError *error) { if (error != nil) { return; } else if (barcodes != nil) { // Recognized barcodes // ... } }];
3. Получите информацию из штрих-кодов
Если операция распознавания штрих-кода прошла успешно, детектор возвращает массив объектовVisionBarcode
. Каждый объект VisionBarcode
представляет штрих-код, обнаруженный на изображении. Для каждого штрих-кода вы можете получить его ограничивающие координаты во входном изображении, а также необработанные данные, закодированные штрих-кодом. Также, если детектор штрих-кода смог определить тип данных, закодированных штрих-кодом, можно получить объект, содержащий разобранные данные.Например:
Быстрый
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 } }
Цель-C
for (FIRVisionBarcode *barcode in barcodes) { NSArray *corners = barcode.cornerPoints; NSString *displayValue = barcode.displayValue; NSString *rawValue = barcode.rawValue; FIRVisionBarcodeValueType valueType = barcode.valueType; switch (valueType) { case FIRVisionBarcodeValueTypeWiFi: // ssid = barcode.wifi.ssid; // password = barcode.wifi.password; // encryptionType = barcode.wifi.type; break; case FIRVisionBarcodeValueTypeURL: // url = barcode.URL.url; // title = barcode.URL.title; break; // ... default: break; } }
Советы по повышению производительности в реальном времени
Если вы хотите сканировать штрих-коды в приложении реального времени, следуйте этим рекомендациям для достижения наилучшей частоты кадров:
Не записывайте входные данные с собственным разрешением камеры. На некоторых устройствах при захвате входных данных с собственным разрешением создаются чрезвычайно большие (10+ мегапикселей) изображения, что приводит к очень низкой задержке без какого-либо улучшения точности. Вместо этого запрашивайте у камеры только тот размер, который необходим для обнаружения штрих-кода: обычно не более 2 мегапикселей.
Однако именованные предустановки сеанса захвата —
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
и т. д.) — не рекомендуются, поскольку они могут соответствовать неподходящим разрешениям на некоторых устройствах. Вместо этого используйте определенные пресеты, такие какAVCaptureSessionPreset1280x720
.Если скорость сканирования важна, вы можете еще больше снизить разрешение захвата изображения. Однако помните о требованиях к минимальному размеру штрих-кода, изложенных выше.
- Дроссель вызывает детектор. Если новый видеокадр становится доступным во время работы детектора, удалите этот кадр.
- Если вы используете выходные данные детектора для наложения графики на входное изображение, сначала получите результат из ML Kit, затем визуализируйте изображение и наложите его за один шаг. При этом вы выполняете рендеринг на поверхность дисплея только один раз для каждого входного кадра. Пример см. в классах PreviewOverlayView и FIRDetectionOverlayView в демонстрационном примере приложения.