Puedes usar ML Kit para reconocer y decodificar códigos de barras.
Antes de comenzar
- Si aún no agregaste Firebase a tu app, sigue los pasos en la guía de introducción para hacerlo.
- Incluye las bibliotecas del ML Kit en tu Podfile:
pod 'Firebase/MLVision' pod 'Firebase/MLVisionBarcodeModel'
Después de instalar o actualizar los Pods de tu proyecto, asegúrate de abrir el proyecto de Xcode con su.xcworkspace
. - En tu app, importa Firebase:
Swift
import Firebase
Objective-C
@import Firebase;
Lineamientos para imágenes de entrada
-
Para que el Kit de AA reconozca códigos de barras con exactitud, las imágenes de entrada deben contener códigos de barras representados con datos de píxeles suficientes.
Los requisitos específicos de datos de píxeles dependen del tipo de código de barras y de la cantidad de datos codificados en él (ya que la mayoría de los códigos de barras admiten una carga útil de longitud variable). Por lo general, la unidad mínima de significado de un código de barras debe tener al menos 2 píxeles de ancho (y en códigos de 2 dimensiones, también 2 píxeles de altura).
Por ejemplo, los códigos de barras EAN-13 contienen barras y espacios con 1, 2, 3 o 4 unidades de ancho, por lo que una imagen de código de barras EAN-13 tiene, idealmente, barras y espacios de al menos 2, 4, 6 y 8 píxeles de ancho. Debido a que un código de barras EAN-13 tiene un ancho de 95 unidades en total, el código de barras deberá tener al menos 190 píxeles de ancho.
Los formatos más densos, como PDF417, requieren mayores dimensiones de píxeles para que el Kit de AA pueda leerlas de forma confiable. Por ejemplo, un código PDF417 puede tener hasta 34 “palabras” de 17 unidades de ancho en una sola fila, que idealmente tendrá un ancho de 1156 píxeles.
-
Un enfoque de imagen deficiente puede afectar la exactitud del escaneo. Si no obtienes resultados aceptables, intenta pedirle al usuario que vuelva a capturar la imagen.
-
Para aplicaciones típicas, se recomienda proporcionar una imagen de mayor resolución (como 1280 x 720 o 1920 x 1080), lo que hace que los códigos de barras sean detectables a mayor distancia de la cámara.
Sin embargo, en aplicaciones en las que la latencia es fundamental, puedes mejorar el rendimiento si capturas imágenes con una resolución más baja, en las que el código de barras constituya la mayor parte de la imagen de entrada. Consulta también Sugerencias para mejorar el rendimiento en tiempo real.
1. Configura el detector de códigos de barras
Si sabes qué formatos de códigos de barras leerás, puedes configurar el detector de códigos de barras para que solo detecte esos formatos a fin de aumentar su velocidad.Por ejemplo, para detectar solo códigos QR y Aztec, crea un objeto VisionBarcodeDetectorOptions
como el del siguiente ejemplo:
Swift
let format = VisionBarcodeFormat.all let barcodeOptions = VisionBarcodeDetectorOptions(formats: format)
Se admiten los siguientes formatos:
- Code128
- Code39
- Code93
- CodaBar
- EAN13
- EAN8
- ITF
- UPCA
- UPCE
- QRCode
- PDF417
- Aztec
- DataMatrix
Objective-C
FIRVisionBarcodeDetectorOptions *options = [[FIRVisionBarcodeDetectorOptions alloc] initWithFormats: FIRVisionBarcodeFormatQRCode | FIRVisionBarcodeFormatAztec];
Se admiten los siguientes formatos:
- Code 128 (
FIRVisionBarcodeFormatCode128
) - Code 39 (
FIRVisionBarcodeFormatCode39
) - Code 93 (
FIRVisionBarcodeFormatCode93
) - Codabar (
FIRVisionBarcodeFormatCodaBar
) - EAN-13 (
FIRVisionBarcodeFormatEAN13
) - EAN-8 (
FIRVisionBarcodeFormatEAN8
) - ITF (
FIRVisionBarcodeFormatITF
) - UPC-A (
FIRVisionBarcodeFormatUPCA
) - UPC-E (
FIRVisionBarcodeFormatUPCE
) - Código QR (
FIRVisionBarcodeFormatQRCode
) - PDF417 (
FIRVisionBarcodeFormatPDF417
) - Aztec (
FIRVisionBarcodeFormatAztec
) - Data Matrix (
FIRVisionBarcodeFormatDataMatrix
)
2. Ejecuta el detector códigos de barras
Para escanear códigos de barras en una imagen, pasa la imagen como unaUIImage
o una CMSampleBufferRef
al método detect(in:)
de VisionBarcodeDetector
:
- Obtén una instancia de
VisionBarcodeDetector
:Swift
lazy var vision = Vision.vision() let barcodeDetector = vision.barcodeDetector(options: barcodeOptions)
Objective-C
FIRVision *vision = [FIRVision vision]; FIRVisionBarcodeDetector *barcodeDetector = [vision barcodeDetector]; // Or, to change the default settings: // FIRVisionBarcodeDetector *barcodeDetector = // [vision barcodeDetectorWithOptions:options];
-
Crea un objeto
VisionImage
mediante unaUIImage
oCMSampleBufferRef
.Para usar una
UIImage
, debes hacer lo siguiente:- Si es necesario, rota la imagen para que la propiedad
imageOrientation
sea.up
. - Crea un objeto
VisionImage
mediante unaUIImage
que se haya rotado adecuadamente. No especifiques los metadatos de rotación. Se debe usar el valor predeterminado.topLeft
.Swift
let image = VisionImage(image: uiImage)
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
Para usar una
CMSampleBufferRef
, debes hacer lo siguiente:-
Crea un objeto
VisionImageMetadata
que especifique la orientación de los datos de la imagen contenidos en el búferCMSampleBufferRef
.Para obtener la orientación de la imagen, haz lo siguiente:
Swift
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 } }
Objective-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; } }
Luego crea el objeto de metadatos de esta manera:
Swift
let cameraPosition = AVCaptureDevice.Position.back // Set to the capture device you used. let metadata = VisionImageMetadata() metadata.orientation = imageOrientation( deviceOrientation: UIDevice.current.orientation, cameraPosition: cameraPosition )
Objective-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];
- Crea un objeto
VisionImage
a través del objetoCMSampleBufferRef
y los metadatos de rotación:Swift
let image = VisionImage(buffer: sampleBuffer) image.metadata = metadata
Objective-C
FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer]; image.metadata = metadata;
- Si es necesario, rota la imagen para que la propiedad
-
Por último, pasa la imagen al método
detect(in:)
:Swift
barcodeDetector.detect(in: visionImage) { features, error in guard error == nil, let features = features, !features.isEmpty else { // ... return } // ... }
Objective-C
[barcodeDetector detectInImage:image completion:^(NSArray<FIRVisionBarcode *> *barcodes, NSError *error) { if (error != nil) { return; } else if (barcodes != nil) { // Recognized barcodes // ... } }];
3. Obtén información de códigos de barras
Si la operación de reconocimiento de código de barras se ejecuta correctamente, el detector muestra un arreglo de objetosVisionBarcode
. Cada objeto VisionBarcode
representa un código de barras que se detectó en la imagen. Para cada código de barras, puedes obtener las coordenadas de sus límites en la imagen de entrada, junto con los datos sin procesar codificados en el código de barras. Además, si el detector de códigos de barras pudo determinar el tipo de datos codificados en el código de barras, puedes obtener un objeto que contenga los datos analizados.
Por ejemplo:
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 (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; } }
Sugerencias para mejorar el rendimiento en tiempo real
Si quieres escanear códigos de barras en una aplicación en tiempo real, sigue estos lineamientos para lograr la mejor velocidad de fotogramas por segundo:
-
No captures imágenes de entrada con la resolución nativa de la cámara. En algunos dispositivos, la captura en resolución nativa produce imágenes extremadamente grandes (más de 10 megapíxeles), lo que da como resultado una latencia muy pobre y una exactitud baja. En lugar de eso, solicita a la cámara el tamaño requerido para la detección de códigos de barras: por lo general, no más de 2 megapíxeles.
Sin embargo, no se recomiendan los ajustes predeterminados de sesión de captura (
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
, etc.), ya que pueden dar como resultado resoluciones inadecuadas en algunos dispositivos. En su lugar, usa los ajustes predeterminados específicos, comoAVCaptureSessionPreset1280x720
.Si la velocidad de escaneo es importante, puedes reducir aún más la resolución de captura de imagen. Sin embargo, ten en cuenta los requisitos mínimos de tamaño de códigos de barras descritos anteriormente.
- Regula las llamadas al detector. Si hay un fotograma de video nuevo disponible mientras se ejecuta el detector, ignora ese fotograma.
- Si estás usando la salida del detector para superponer gráficos en la imagen de entrada, primero obtén el resultado de la detección de ML Kit y, luego, procesa la imagen y la superposición en un solo paso. De esta manera, procesas la superficie de visualización solo una vez por cada fotograma de entrada. Consulta las clases previewOverlayView y FIRDetectionOverlayView en la app de muestra para ver un ejemplo.