Escanea códigos de barras con ML Kit en iOS

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

Probar

Antes de comenzar

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

Lineamientos para imágenes de entrada

  • Para que el Kit de AA lea correctamente los códigos de barras, 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 los píxeles dependen del tipo de código de barras y la cantidad de datos codificados en él, ya que muchos de los admiten una carga útil de tamaño variable. En general, la parte más pequeña del código de barras debe tener al menos 2 píxeles de ancho y, para Códigos bidimensionales de 2 píxeles de altura

    Por ejemplo, los códigos de barras EAN-13 se componen de barras y espacios 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 que tengan al menos 2, 4, 6 y 8 píxeles de ancho. Debido a que un EAN-13 el código de barras 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 para leerlas de forma confiable. Por ejemplo, un código PDF417 puede tener hasta 34 “words” de 17 unidades en una sola fila, lo que idealmente sería al menos 1,156 píxeles de ancho

  • Un enfoque de imagen deficiente puede afectar la exactitud del escaneo. Si tu app no se carga resultados aceptables, pide al usuario que vuelva a capturar la imagen.

  • Para aplicaciones típicas, se recomienda proporcionar una protección resolución de la imagen, como 1280 x 720 o 1920 x 1080, para que los códigos escaneables a una mayor distancia de la cámara.

    Sin embargo, en las aplicaciones en las que la latencia es fundamental, de alto rendimiento mediante la captura de imágenes con una resolución más baja, pero que y el código de barras constituyen 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 mejorar la velocidad del escáner de código de barras configurándolo para que solo escanee esos formatos.

Por ejemplo, para escanear solo códigos QR y Aztec, crea una objeto BarcodeScannerOptions, como en 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)
  • Aztec Code (MLKBarcodeFormatAztec)

2. Prepara la imagen de entrada

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

Crea un objeto VisionImage con un objeto UIImage o CMSampleBuffer

Si usas un UIImage, sigue estos pasos:

  • Crea un objeto VisionImage con UIImage. 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:

  • Especificar la orientación de los datos de imagen que se incluyen en la 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 elemento Objeto CMSampleBuffer y 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 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

Por último, 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 devuelve un array 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 su coordenadas límite en la imagen de entrada, así como los datos sin procesar codificados código de barras. Además, si el escáner de código de barras pudiera determinar el tipo de datos codificado por el código de barras, puedes obtener un objeto que contenga 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 pasos: pautas para lograr la mejor velocidad de fotogramas:

  • No captures imágenes de entrada con la resolución nativa de la cámara. En algunos dispositivos, capturar entradas con la resolución nativa produce errores extremadamente grandes (más de 10 megapíxeles) con imágenes, lo que genera una latencia muy deficiente sin beneficio para exactitud. En su lugar, solicita únicamente el tamaño necesario a la cámara para escanear códigos de barras, que en general no supera los 2 megapíxeles.

    Los ajustes predeterminados de la sesión de captura con nombre: AVCaptureSessionPresetDefault, AVCaptureSessionPresetLow, AVCaptureSessionPresetMedium etcétera) no se recomiendan, ya que pueden asignarse a 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 captura de imágenes resolución. Sin embargo, ten en cuenta los requisitos de tamaño mínimo de los códigos de barras. descrita anteriormente.

    Si intentas reconocer los códigos de barras de una secuencia de transmisión fotogramas de video, el reconocedor podría producir resultados diferentes marco. Debes esperar hasta obtener una serie consecutiva de la misma para tener la certeza de que obtendrás un buen resultado.

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

  • Para procesar fotogramas de video, usa la API síncrona results(in:) del detector. Llamada este método desde el De AVCaptureVideoDataOutputSampleBufferDelegate La función captureOutput(_, didOutput:from:) para obtener resultados de un video determinado de forma síncrona marco. Mantener de AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames como true para limitar las llamadas al detector Si un nuevo cliente El fotograma estará disponible mientras se ejecute el detector, que se descartará.
  • Si usas la salida del detector para superponer gráficos la imagen de entrada, primero obtén el resultado del Kit de AA y, luego, renderiza la imagen y superponerla en un solo paso. De esta manera, renderizas en la superficie de visualización. solo una vez por cada trama de entrada procesada. Consulta updatePreviewOverlayViewWithLastFrame. en la muestra de inicio rápido del Kit de AA para ver un ejemplo.