É possível usar o Kit de ML para reconhecer e decodificar códigos de barras.
Faça um teste
- Teste o app de exemplo para um exemplo de uso dessa API.
Antes de começar
- Inclua os seguintes pods do kit de ML no seu Podfile:
pod 'GoogleMLKit/BarcodeScanning', '15.5.0'
- Depois de instalar ou atualizar os pods do seu projeto, abra o projeto Xcode usando o
.xcworkspace
: O Kit de ML é compatível com a versão 12.4 ou mais recente do Xcode.
Diretrizes de imagens de entrada
-
Para que o Kit de ML leia códigos de barras com precisão, as imagens de entrada precisam conter em códigos de barras que sejam representados por dados de pixel suficientes.
Os requisitos específicos de dados de pixel dependem do tipo de código de barras e a quantidade de dados codificados nele, já que muitos dão suporte a um payload de tamanho variável. Em geral, os menores valores a unidade do código de barras deve ter pelo menos 2 pixels de largura e, por Códigos bidimensionais com 2 pixels de altura.
Por exemplo, os códigos de barras EAN-13 são compostos de barras e espaços que são 1, 2, 3 ou 4 unidades de largura, de modo que uma imagem de código de barras EAN-13 tenha barras e espaços com pelo menos 2, 4, 6 e 8 pixels de largura. Como um EAN-13 o código de barras tem 95 unidades no total, ele deve ter pelo menos 190 pixels de largura.
Formatos mais densos, como PDF417, precisam de dimensões em pixels maiores para o kit de ML para lê-los de maneira confiável. Por exemplo, um código PDF417 pode ter até 34 "palavras" de 17 unidades em uma única linha, o que idealmente seria pelo menos 1.156 pixels de largura.
-
Uma imagem com foco inadequado pode afetar a precisão da verificação. Se o app não estiver recebendo resultados aceitáveis, peça ao usuário para recapturar a imagem.
-
Para aplicativos típicos, recomenda-se fornecer uma maior imagem de alta resolução, como 1280 x 720 ou 1920 x 1080, que faz códigos de barras possa ser lido a uma distância maior da câmera.
No entanto, em aplicativos em que a latência é crítica, é possível melhorar desempenho capturando imagens com resolução mais baixa, mas exigindo que o código de barras constitui a maior parte da imagem de entrada. Consulte também Dicas para melhorar o desempenho em tempo real.
1. Configurar o leitor de código de barras
Se souber quais formatos de código de barras espera ler, você poderá aumentar a velocidade do leitor de código de barras configurando-o para ler apenas esses formatos.Por exemplo, para ler apenas códigos Aztec e QR, crie uma
objeto BarcodeScannerOptions
, como no
exemplo a seguir:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
Os seguintes formatos são compatíveis:
- code128
- code39
- code93
- codaBar
- dataMatrix
- EAN13
- EAN8
- ITF
- qrCode
- UPCA
- UPCE
- PDF417
- Aztec
Objective-C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
Os seguintes formatos são compatíveis:
- Código-128 (
MLKBarcodeFormatCode128
) - Código 39 (
MLKBarcodeFormatCode39
) - Código 93 (
MLKBarcodeFormatCode93
) - Codabar (
MLKBarcodeFormatCodaBar
) - Matriz de dados (
MLKBarcodeFormatDataMatrix
) - EAN-13 (
MLKBarcodeFormatEAN13
) - EAN-8 (
MLKBarcodeFormatEAN8
) - ITF (
MLKBarcodeFormatITF
) - QR code (
MLKBarcodeFormatQRCode
) - UPC-A (
MLKBarcodeFormatUPCA
) - UPC-E (
MLKBarcodeFormatUPCE
) - PDF-417 (
MLKBarcodeFormatPDF417
) - Código Aztec (
MLKBarcodeFormatAztec
)
2. Preparar a imagem de entrada
Para ler códigos de barras em uma imagem, transmita a imagem comoUIImage
ou
CMSampleBufferRef
para o process()
ou results(in:)
do BarcodeScanner
:
Crie um objeto VisionImage
usando um UIImage
ou um
CMSampleBuffer
.
Se você usa um UIImage
, siga estas etapas:
- Crie um objeto
VisionImage
com oUIImage
. Especifique o.orientation
correto.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective-C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Se você usa um CMSampleBuffer
, siga estas etapas:
-
Especifique a orientação dos dados da imagem contidos no
CMSampleBuffer
:Para saber qual é a orientação da imagem:
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; } }
- Crie um objeto
VisionImage
usando o Objeto e orientaçãoCMSampleBuffer
: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. Acessar uma instância do BarcodeScanner
Receba uma instância deBarcodeScanner
:
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. Processar a imagem
Em seguida, transmita a imagem para o métodoprocess()
:
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. Receber informações de códigos de barras
Se a operação de leitura do código de barras for bem-sucedida, o leitor retornará uma matriz de ObjetosBarcode
. Cada objeto Barcode
representa uma
código de barras detectado na imagem. Para cada código de barras, você encontra
coordenadas delimitadoras na imagem de entrada, bem como os dados brutos codificados pelo
código de barras. Além disso, se o leitor de código de barras tiver conseguido determinar o tipo de dados
codificado pelo código de barras, você pode obter um objeto que contém dados analisados.
Exemplo:
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; } }
Dicas para melhorar o desempenho em tempo real
Se você quiser ler códigos de barras em um aplicativo em tempo real, siga estas diretrizes para obter as melhores taxas de quadros:
-
Não capture a entrada na resolução nativa da câmera. Em alguns dispositivos, a captura de entradas na resolução nativa produz volumes extremamente grandes (10+ megapixels), o que resulta em uma latência muito baixa, sem nenhum benefício para precisão. Em vez disso, solicite apenas o tamanho necessário da câmera. para leitura de código de barras, que normalmente não tem mais de 2 megapixels.
As predefinições da sessão de captura nomeada,
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
entre outras), não são recomendadas, já que podem ser mapeadas e resoluções inadequadas em alguns dispositivos. Em vez disso, use as predefinições específicas comoAVCaptureSessionPreset1280x720
.Se a velocidade de leitura for importante, diminua ainda mais a captura da imagem e resolução. No entanto, lembre-se dos requisitos mínimos de tamanho de código de barras descritos acima.
Se você estiver tentando reconhecer códigos de barras de uma sequência de streaming quadros de vídeo, o reconhecedor pode produzir resultados diferentes de quadro a frame. Aguarde até receber uma série consecutiva do mesmo para ter certeza de que está retornando um bom resultado.
O dígito da soma de verificação não é compatível com ITF e CODE-39.
- Para processar frames de vídeo, use a API síncrona
results(in:)
do detector. Ligação esse método daAVCaptureVideoDataOutputSampleBufferDelegate
captureOutput(_, didOutput:from:)
para receber resultados do vídeo fornecido de forma síncrona frame. Manter deAVCaptureVideoDataOutput
alwaysDiscardsLateVideoFrames
comotrue
para limitar as chamadas ao detector. Se um novo frame de vídeo ficar disponível enquanto o detector estiver em execução, ele será descartado. - Se você usar a saída do detector para sobrepor elementos gráficos a imagem de entrada, primeiro acesse o resultado do Kit de ML e, em seguida, renderize a imagem e sobreposição em uma única etapa. Ao fazer isso, você renderiza a superfície de exibição apenas uma vez para cada frame de entrada processado. Veja a classe updatePreviewOverlayViewWithLastFrame na amostra do guia de início rápido do Kit de ML.