Puedes usar ML Kit para reconocer y decodificar códigos de barras.
Probar
- Prueba la app de ejemplo para ver un ejemplo de uso de esta API.
Antes de comenzar
- Incluye los siguientes pods del ML Kit en tu Podfile:
pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
- Después de instalar o actualizar los Pods de tu proyecto, abre el proyecto de Xcode con su
.xcworkspace
. El ML Kit es compatible con Xcode 12.4 o versiones posteriores.
Lineamientos para imágenes de entrada
-
Para que el Kit de AA lea códigos de barras con precisión, las imágenes de entrada deben contener códigos de barras representados con datos de píxeles suficientes.
Los requisitos específicos de los datos de píxeles dependen del tipo de código de barras y de la cantidad de datos codificados en él, ya que muchos códigos de barras admiten una carga útil de tamaño variable. En general, la unidad más pequeña de significado del código de barras debe tener al menos 2 píxeles de ancho y, para los códigos de 2 dimensiones, 2 píxeles de alto.
Por ejemplo, los códigos de barras EAN-13 se componen de barras y espacios de 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 2, 4, 6 y 8 píxeles de ancho. Como un código de barras EAN-13 tiene 95 unidades de ancho en total, este debe tener al menos 190 píxeles de ancho.
Los formatos más densos, como PDF417, necesitan mayores dimensiones de píxeles para que el ML Kit pueda leerlos 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ían 1,156 píxeles de ancho.
-
Un enfoque de imagen deficiente puede afectar la precisión del escaneo. Si tu app no obtiene resultados aceptables, pídele al usuario que vuelva a capturar la imagen.
-
En aplicaciones típicas, se recomienda proporcionar una imagen de mayor resolución, como 1280 x 720 o 1920 x 1080, que permite que los códigos de barras se puedan escanear a mayor distancia de la cámara.
Sin embargo, en aplicaciones en las que la latencia es crítica, puedes mejorar el rendimiento si capturas imágenes con una resolución más baja, pero que requieran 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 escáner de código de barras
Si sabes qué formatos de códigos de barras leerás, puedes configurar el escáner de código de barras para que solo escanee esos formatos a fin de mejorar su velocidad.Por ejemplo, para escanear solo códigos QR y Aztec, crea un objeto BarcodeScannerOptions
como el del siguiente ejemplo:
Swift
let format = .all let barcodeOptions = BarcodeScannerOptions(formats: format)
Se admiten los siguientes formatos:
- code128
- code39
- code93
- codaBar
- dataMatrix
- EAN13
- EAN8
- ITF
- qrCode
- UPCA
- UPCE
- PDF417
- azteca
Objective‑C
MLKBarcodeScannerOptions *options = [[MLKBarcodeScannerOptions alloc] initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];
Se admiten los siguientes formatos:
- Código-128 (
MLKBarcodeFormatCode128
) - Código-39 (
MLKBarcodeFormatCode39
) - Código-93 (
MLKBarcodeFormatCode93
) - Codabar (
MLKBarcodeFormatCodaBar
) - Data Matrix (
MLKBarcodeFormatDataMatrix
) - EAN-13 (
MLKBarcodeFormatEAN13
) - EAN-8 (
MLKBarcodeFormatEAN8
) - ITF (
MLKBarcodeFormatITF
) - Código QR (
MLKBarcodeFormatQRCode
) - UPC-A (
MLKBarcodeFormatUPCA
) - UPC‐E (
MLKBarcodeFormatUPCE
) - PDF-417 (
MLKBarcodeFormatPDF417
) - Código Aztec (
MLKBarcodeFormatAztec
)
2. Prepara la imagen de entrada
Para escanear códigos de barras en una imagen, pasa la imagen como unaUIImage
o una CMSampleBufferRef
al método process()
o results(in:)
de BarcodeScanner
:
Crea un objeto VisionImage
mediante una UIImage
o CMSampleBuffer
.
Si usas un UIImage
, sigue estos pasos:
- Crea un objeto
VisionImage
con laUIImage
. Asegúrate de especificar el.orientation
correcto.Swift
let image = VisionImage(image: UIImage) visionImage.orientation = image.imageOrientation
Objective‑C
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image]; visionImage.orientation = image.imageOrientation;
Si usas un CMSampleBuffer
, sigue estos pasos:
-
Especifica la orientación de los datos de imagen que contiene
CMSampleBuffer
.Para obtener la orientación de la imagen, haz lo siguiente:
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; } }
- Crea un objeto
VisionImage
con el objetoCMSampleBuffer
y la orientación: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. Cómo obtener una instancia de BarcodeScanner
Obtén una instancia 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. Procesa la imagen
Por último, pasa la imagen al 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. Obtén información de códigos de barras
Si la operación de escaneo de códigos de barras se ejecuta correctamente, el escáner mostrará un array de objetosBarcode
. Cada objeto Barcode
representa un código de barras que se detectó en la imagen. Para cada código de barras, puedes obtener las coordenadas de los límites en la imagen de entrada, así como los datos sin procesar codificados en el código de barras. Además, si el escáner de código 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 (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; } }
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:
-
No captures entradas con la resolución nativa de la cámara. En algunos dispositivos, la captura de entradas en la resolución nativa produce imágenes extremadamente grandes (más de 10 megapíxeles), lo que genera una latencia muy baja y no beneficia la precisión. En su lugar, solo solicita a la cámara el tamaño necesario para el escaneo de códigos de barras, que no suele tener más de 2 megapíxeles.
Sin embargo, no se recomiendan los ajustes predeterminados de sesión de captura nombrados (
AVCaptureSessionPresetDefault
,AVCaptureSessionPresetLow
,AVCaptureSessionPresetMedium
, etc.), ya que pueden asignarse a 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 imágenes. Sin embargo, ten en cuenta los requisitos mínimos de tamaño de códigos de barras descritos anteriormente.
Si intentas reconocer códigos de barras de una secuencia de fotogramas de video en streaming, el reconocedor podría producir resultados diferentes de fotograma a fotograma. Debes esperar hasta obtener una serie consecutiva del mismo valor para estar seguro de mostrar un buen resultado.
El dígito de la suma de comprobación no es compatible con ITF y CODE-39.
- Para procesar fotogramas de video, usa la API síncrona
results(in:)
del detector. Llama a este método desde la funcióncaptureOutput(_, didOutput:from:)
deAVCaptureVideoDataOutputSampleBufferDelegate
para obtener resultados de un fotograma de video determinado de manera síncrona. Mantén elalwaysDiscardsLateVideoFrames
deAVCaptureVideoDataOutput
comotrue
para limitar las llamadas al detector. Si hay un fotograma de video nuevo disponible mientras se ejecuta el detector, se descartará. - Si usas la salida del detector para superponer gráficos en la imagen de entrada, primero obtén el resultado del ML Kit y, luego, procesa la imagen y la superposición en un solo paso. De esta manera, renderizas en la superficie de visualización solo una vez por cada fotograma de entrada procesado. Consulta updatePreviewOverlayViewWithLastFrame en la muestra de inicio rápido del Kit de AA para ver un ejemplo.