Escanear códigos de barras con ML Kit en iOS

Puede utilizar ML Kit para reconocer y decodificar códigos de barras.

Antes de que empieces

  1. Si aún no has agregado Firebase a tu aplicación, hazlo siguiendo los pasos de la guía de introducción .
  2. Incluya las bibliotecas del kit ML en su Podfile:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    Después de instalar o actualizar los Pods de su proyecto, asegúrese de abrir su proyecto Xcode usando su .xcworkspace .
  3. En tu aplicación, importa Firebase:

    Rápido

    import Firebase

    C objetivo

    @import Firebase;

Pautas de imagen de entrada

  • Para que ML Kit lea códigos de barras con precisión, las imágenes de entrada deben contener códigos de barras representados por suficientes datos de píxeles.

    Los requisitos de datos de píxeles específicos dependen tanto del tipo de código de barras como 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). En general, la unidad significativa más pequeña del código de barras debe tener al menos 2 píxeles de ancho (y para códigos bidimensionales, 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 idealmente tiene barras y espacios de al menos 2, 4, 6 y 4 unidades. 8 píxeles de ancho. Debido a que un código de barras EAN-13 tiene 95 unidades de ancho 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 ML Kit los lea 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ía al menos 1156 píxeles de ancho.

  • Un enfoque deficiente de la imagen puede afectar la precisión del escaneo. Si no obtiene resultados aceptables, intente pedirle al usuario que vuelva a capturar la imagen.

  • Para aplicaciones típicas, se recomienda proporcionar una imagen de mayor resolución (como 1280x720 o 1920x1080), lo que hace que los códigos de barras sean detectables desde una distancia mayor de la cámara.

    Sin embargo, en aplicaciones donde la latencia es crítica, puede mejorar el rendimiento capturando imágenes con una resolución más baja, pero exigiendo que el código de barras constituya la mayor parte de la imagen de entrada. Consulte también Sugerencias para mejorar el rendimiento en tiempo real .

1. Configurar el detector de códigos de barras

Si sabe qué formatos de códigos de barras espera leer, puede mejorar la velocidad del detector de códigos de barras configurándolo para que solo detecte esos formatos.

Por ejemplo, para detectar solo códigos Aztec y códigos QR, cree un objeto VisionBarcodeDetectorOptions como en el siguiente ejemplo:

Rápido

let format = VisionBarcodeFormat.all
let barcodeOptions = VisionBarcodeDetectorOptions(formats: format)

Se admiten los siguientes formatos:

  • Código 128
  • Código39
  • Código93
  • CodaBar
  • EAN13
  • EAN8
  • ITF
  • UPCA
  • UPCE
  • Código QR
  • PDF417
  • azteca
  • Matriz de datos

C objetivo

FIRVisionBarcodeDetectorOptions *options =
    [[FIRVisionBarcodeDetectorOptions alloc]
     initWithFormats: FIRVisionBarcodeFormatQRCode | FIRVisionBarcodeFormatAztec];

Se admiten los siguientes formatos:

  • Código 128 ( FIRVisionBarcodeFormatCode128 )
  • Código 39 ( FIRVisionBarcodeFormatCode39 )
  • Código 93 ( FIRVisionBarcodeFormatCode93 )
  • Codabar ( FIRVisionBarcodeFormatCodaBar )
  • EAN-13 ( FIRVisionBarcodeFormatEAN13 )
  • EAN-8 ( FIRVisionBarcodeFormatEAN8 )
  • ITF ( FIRVisionBarcodeFormatITF )
  • UPC-A ( FIRVisionBarcodeFormatUPCA )
  • UPC-E ( FIRVisionBarcodeFormatUPCE )
  • Código QR ( FIRVisionBarcodeFormatQRCode )
  • PDF417 ( FIRVisionBarcodeFormatPDF417 )
  • Azteca ( FIRVisionBarcodeFormatAztec )
  • Matriz de datos ( FIRVisionBarcodeFormatDataMatrix )

2. Ejecute el detector de códigos de barras

Para escanear códigos de barras en una imagen, pase la imagen como UIImage o CMSampleBufferRef al método detect(in:) de VisionBarcodeDetector :

  1. Obtenga una instancia de VisionBarcodeDetector :

    Rápido

    lazy var vision = Vision.vision()
    
    let barcodeDetector = vision.barcodeDetector(options: barcodeOptions)
    

    C objetivo

    FIRVision *vision = [FIRVision vision];
    FIRVisionBarcodeDetector *barcodeDetector = [vision barcodeDetector];
    // Or, to change the default settings:
    // FIRVisionBarcodeDetector *barcodeDetector =
    //     [vision barcodeDetectorWithOptions:options];
    
  2. Cree un objeto VisionImage utilizando UIImage o CMSampleBufferRef .

    Para usar una UIImage :

    1. Si es necesario, gire la imagen para que su propiedad imageOrientation sea .up .
    2. Cree un objeto VisionImage utilizando UIImage girado correctamente. No especifique ningún metadato de rotación; se debe utilizar el valor predeterminado, .topLeft .

      Rápido

      let image = VisionImage(image: uiImage)

      C objetivo

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];

    Para utilizar CMSampleBufferRef :

    1. Cree un objeto VisionImageMetadata que especifique la orientación de los datos de la imagen contenidos en el búfer CMSampleBufferRef .

      Para obtener la orientación de la imagen:

      Rápido

      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 objetivo

      - (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:

      Rápido

      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 objetivo

      FIRVisionImageMetadata *metadata = [[FIRVisionImageMetadata alloc] init];
      AVCaptureDevicePosition cameraPosition =
          AVCaptureDevicePositionBack;  // Set to the capture device you used.
      metadata.orientation =
          [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                       cameraPosition:cameraPosition];
    2. Cree un objeto VisionImage utilizando el objeto CMSampleBufferRef y los metadatos de rotación:

      Rápido

      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata

      C objetivo

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Luego, pasa la imagen al método detect(in:) :

    Rápido

    barcodeDetector.detect(in: visionImage) { features, error in
      guard error == nil, let features = features, !features.isEmpty else {
        // ...
        return
      }
    
      // ...
    }
    

    C objetivo

    [barcodeDetector detectInImage:image
                        completion:^(NSArray<FIRVisionBarcode *> *barcodes,
                                     NSError *error) {
      if (error != nil) {
        return;
      } else if (barcodes != nil) {
        // Recognized barcodes
        // ...
      }
    }];
    

3. Obtener información de códigos de barras

Si la operación de reconocimiento del código de barras tiene éxito, el detector devuelve una matriz de objetos VisionBarcode . Cada objeto VisionBarcode representa un código de barras que se detectó en la imagen. Para cada código de barras, puede obtener sus coordenadas delimitadoras en la imagen de entrada, así como los datos sin procesar codificados por el código de barras. Además, si el detector de códigos de barras pudo determinar el tipo de datos codificados por el código de barras, puede obtener un objeto que contenga datos analizados.

Por ejemplo:

Rápido

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 objetivo

 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;
   }
 }

Consejos para mejorar el rendimiento en tiempo real

Si desea escanear códigos de barras en una aplicación en tiempo real, siga estas pautas para lograr las mejores velocidades de fotogramas:

  • No capture entradas con la resolución nativa de la cámara. En algunos dispositivos, capturar la entrada con la resolución nativa produce imágenes extremadamente grandes (más de 10 megapíxeles), lo que resulta en una latencia muy pobre sin ningún beneficio para la precisión. En su lugar, solicite a la cámara únicamente el tamaño necesario para la detección de códigos de barras: normalmente no más de 2 megapíxeles.

    Sin embargo, no se recomiendan los ajustes preestablecidos de sesión de captura con nombre ( AVCaptureSessionPresetDefault , AVCaptureSessionPresetLow , AVCaptureSessionPresetMedium , etc.), ya que pueden asignarse a resoluciones inadecuadas en algunos dispositivos. En su lugar, utilice ajustes preestablecidos específicos como AVCaptureSessionPreset1280x720 .

    Si la velocidad de escaneo es importante, puede reducir aún más la resolución de captura de imágenes. Sin embargo, tenga en cuenta los requisitos de tamaño mínimo de código de barras descritos anteriormente.

  • Llamadas del acelerador al detector. Si hay un nuevo cuadro de video disponible mientras el detector está en ejecución, suelte el cuadro.
  • Si está utilizando la salida del detector para superponer gráficos en la imagen de entrada, primero obtenga el resultado del ML Kit, luego renderice la imagen y superpóngala en un solo paso. Al hacerlo, renderiza en la superficie de visualización solo una vez por cada cuadro de entrada. Consulte las clases previaOverlayView y FIRDetectionOverlayView en la aplicación de muestra de presentación para ver un ejemplo.