Escanea códigos de barras con el Kit de AA en iOS

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

Puedes usar el Kit de AA para reconocer y decodificar códigos de barras.

Probarlo

Antes de comenzar

  1. Incluye los siguientes pods de ML Kit en tu Podfile:
    pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
    
  2. Después de instalar o actualizar los pods de tu proyecto, abre el proyecto de Xcode con su .xcworkspace. El Kit de AA es compatible con Xcode 12.4 o versiones posteriores.

Lineamientos para ingresar imágenes

  • Para que el Kit de AA lea 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, ya que muchos códigos de barras admiten una carga útil de tamaño variable. En general, la unidad más pequeña y significativa del código de barras debe tener al menos 2 píxeles de ancho, y en el caso de los códigos bidimensionales, debe tener 2 píxeles de alto.

    Por ejemplo, los códigos de barras EAN-13 están compuestos por 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 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 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 Kit de AA pueda leerlos de manera 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 tu app no obtiene resultados aceptables, pídele 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 se puedan escanear a una distancia mayor desde la cámara.

    Sin embargo, en las 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 requieren 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. Cómo configurar el escáner de código de barras

Si sabes qué formatos de códigos de barras leerás, puedes mejorar la velocidad del escáner de código de barras si lo configuras para que solo analice esos formatos.

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:

  • código128
  • código39
  • código93
  • CodaBar
  • DataMatrix
  • EAN13
  • EAN8
  • TIF
  • Código QR
  • 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)
  • TFT (MLKBarcodeFormatITF)
  • Código QR (MLKBarcodeFormatQRCode)
  • UPC-A (MLKBarcodeFormatUPCA)
  • UPC-E (MLKBarcodeFormatUPCE)
  • PDF‐417 (MLKBarcodeFormatPDF417)
  • Código azteca (MLKBarcodeFormatAztec)

2. Prepara la imagen de entrada

Para escanear códigos de barras en una imagen, pasa la imagen como una UIImage o una CMSampleBufferRef al método process() o results(in:) de la BarcodeScanner:

Crea un objeto VisionImage con un UIImage o CMSampleBuffer.

Si usas un UIImage, sigue estos pasos:

  • Crea un objeto VisionImage con el UIImage. Asegúrate de especificar la .orientation correcta.

    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 se encuentran en 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 objeto y la orientación 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. Obtener una instancia de BarcodeScanner

Obtén una instancia de 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. Procesa la imagen

Luego, pasa la imagen al método 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. Obtén información de códigos de barras

Si la operación de escaneo de códigos de barras se realiza correctamente, el escáner muestra un arreglo de objetos Barcode. 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 sus 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 por segundo:

  • No captures imágenes de entrada con la resolución nativa de la cámara. En algunos dispositivos, la captura de entrada con resolución nativa produce imágenes extremadamente grandes (más de 10 megapíxeles), lo que genera una latencia muy deficiente, sin que ello represente un beneficio para la exactitud. En su lugar, solicita a la cámara el tamaño requerido para el escaneo del código 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 dar como resultado resoluciones inadecuadas en algunos dispositivos. En su lugar, usa los ajustes predeterminados específicos, como AVCaptureSessionPreset1280x720.

    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.

    Si intentas reconocer códigos de barras de una secuencia de transmisión de fotogramas de video, es posible que el reconocedor genere resultados diferentes de un fotograma a otro. Debes esperar hasta obtener una serie consecutiva del mismo valor para asegurarte de estar mostrando un buen resultado.

    El dígito de suma de verificación no es compatible con ITF ni con CODE-39.

  • Para procesar fotogramas de video, usa la API síncrona results(in:) del detector. Llama a este método desde la función captureOutput(_, didOutput:from:) de AVCaptureVideoDataOutputSampleBufferDelegate para obtener resultados de manera síncrona desde el marco de video determinado. Mantén el alwaysDiscardsLateVideoFrames de AVCaptureVideoDataOutput como true para regular 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 Kit de AA y, luego, procesa la imagen y la superposición en un solo paso. De esta manera, procesas en la superficie de visualización solo una vez por cada fotograma de entrada procesado. Consulta la updatePreviewOverlayViewWithLastFrame en la muestra de inicio rápido del Kit de AA para ver un ejemplo.