Scansione dei codici a barre con ML Kit su iOS

Puoi utilizzare ML Kit per riconoscere e decodificare i codici a barre.

Prova

Prima di iniziare

  1. Includi i seguenti pod ML Kit nel podfile:
    pod 'GoogleMLKit/BarcodeScanning', '3.2.0'
    
  2. Dopo aver installato o aggiornato i pod del progetto, apri il progetto Xcode utilizzando il relativo .xcworkspace. ML Kit è supportato in Xcode versione 12.4 o successiva.

Linee guida per l'immagine di input

  • Affinché ML Kit legga accuratamente i codici a barre, le immagini di input devono contenere codici a barre rappresentati da una quantità sufficiente di dati di pixel.

    I requisiti specifici dei dati relativi ai pixel dipendono dal tipo di codice a barre e dalla quantità di dati codificati al suo interno, poiché molti codici a barre supportano un payload di dimensioni variabili. In generale, l'unità significativa più piccola del codice a barre deve essere di almeno 2 pixel in larghezza, mentre per i codici bidimensionali deve essere alta 2 pixel.

    Ad esempio, i codici a barre EAN-13 sono costituiti da barre e spazi larghi di 1, 2, 3 o 4 unità, pertanto un'immagine dei codici a barre EAN-13 presenta idealmente barre e spazi di almeno 2, 4, 6 e 8 pixel di larghezza. Poiché un codice a barre EAN-13 è largo in totale 95 unità, deve avere una larghezza di almeno 190 pixel.

    I formati più densi, come i PDF417, richiedono dimensioni in pixel maggiori affinché ML Kit possa leggerli in modo affidabile. Ad esempio, un codice PDF417 può contenere fino a 34 "parole" larghe 17 unità in una singola riga, idealmente almeno 1156 pixel.

  • Una scarsa messa a fuoco dell'immagine può influire sulla precisione della scansione. Se la tua app non sta ottenendo risultati accettabili, chiedi all'utente di acquisire nuovamente l'immagine.

  • Per le applicazioni tipiche, consigliamo di fornire un'immagine a risoluzione più elevata, ad esempio 1280 x 720 o 1920 x 1080, che consente di leggere i codici a barre da una distanza maggiore dalla fotocamera.

    Tuttavia, nelle applicazioni in cui la latenza è fondamentale, è possibile migliorare le prestazioni acquisendo immagini a una risoluzione inferiore, ma è necessario che il codice a barre copra la maggior parte dell'immagine di input. Consulta anche la sezione Suggerimenti per migliorare le prestazioni in tempo reale.

1. Configura il lettore di codici a barre

Se conosci i formati di codici a barre che prevedi di leggere, puoi migliorare la velocità del lettore di codici a barre configurandolo per la scansione dei soli formati.

Ad esempio, per scansionare solo codici aztechi e codici QR, crea un oggetto BarcodeScannerOptions come nell'esempio seguente:

Swift

let format = .all
let barcodeOptions = BarcodeScannerOptions(formats: format)
  

Sono supportati i seguenti formati:

  • code128
  • code39
  • code93
  • codaBar
  • dataMatrix
  • EAN13
  • EAN8
  • ITF
  • qrCode
  • UPCA
  • UPCE
  • PDF417
  • Aztec

Objective-C

MLKBarcodeScannerOptions *options =
  [[MLKBarcodeScannerOptions alloc]
   initWithFormats: MLKBarcodeFormatQRCode | MLKBarcodeFormatAztec];

Sono supportati i seguenti formati:

  • Codice 128 (MLKBarcodeFormatCode128)
  • Codice 39 (MLKBarcodeFormatCode39)
  • Codice-93 (MLKBarcodeFormatCode93)
  • Codabar (MLKBarcodeFormatCodaBar)
  • Matrice di dati (MLKBarcodeFormatDataMatrix)
  • EAN-13 (MLKBarcodeFormatEAN13)
  • EAN-8 (MLKBarcodeFormatEAN8)
  • ITF (MLKBarcodeFormatITF)
  • Codice QR (MLKBarcodeFormatQRCode)
  • UPC-A (MLKBarcodeFormatUPCA)
  • UPC-E (MLKBarcodeFormatUPCE)
  • PDF-417 (MLKBarcodeFormatPDF417)
  • Codice azteco (MLKBarcodeFormatAztec)

2. Prepara l'immagine di input

Per eseguire la scansione dei codici a barre in un'immagine, trasmetti l'immagine come UIImage o CMSampleBufferRef al metodo process() o results(in:) di BarcodeScanner:

Crea un oggetto VisionImage utilizzando UIImage o CMSampleBuffer.

Se usi un UIImage, segui questi passaggi:

  • Crea un oggetto VisionImage con il UIImage. Assicurati di specificare il valore .orientation corretto.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Se usi un CMSampleBuffer, segui questi passaggi:

  • Specifica l'orientamento dei dati immagine contenuti in CMSampleBuffer.

    Per ottenere l'orientamento dell'immagine:

    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 oggetto VisionImage utilizzando l'oggetto CMSampleBuffer e l'orientamento:

    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. Ottieni un'istanza di BarcodeScanner

Ottieni un'istanza di 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. Elabora l'immagine

Quindi, passa l'immagine al metodo 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. Ottieni informazioni dai codici a barre

Se l'operazione di scansione del codice a barre ha esito positivo, lo scanner restituisce un array di oggetti Barcode. Ogni oggetto Barcode rappresenta un codice a barre rilevato nell'immagine. Per ogni codice a barre, puoi ottenere le sue coordinate di delimitazione nell'immagine di input, così come i dati non elaborati codificati dal codice a barre. Inoltre, se lo scanner di codici a barre è riuscito a determinare il tipo di dati codificati dal codice a barre, puoi ottenere un oggetto contenente i dati analizzati.

Ad esempio:

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

Suggerimenti per migliorare il rendimento in tempo reale

Se vuoi scansionare i codici a barre in un'applicazione in tempo reale, segui queste linee guida per ottenere le frequenze fotogrammi migliori:

  • Non acquisire l'input alla risoluzione originale della fotocamera. Su alcuni dispositivi, l'acquisizione dell'input con la risoluzione nativa produce immagini estremamente grandi (oltre 10 megapixel), il che comporta una latenza molto bassa senza alcun vantaggio per l'accuratezza. Richiedi invece solo le dimensioni della fotocamera necessarie per la scansione dei codici a barre, che in genere non superano i 2 megapixel.

    Tuttavia, le preimpostazioni della sessione di acquisizione denominate AVCaptureSessionPresetDefault, AVCaptureSessionPresetLow, AVCaptureSessionPresetMedium e così via non sono consigliate perché potrebbero essere mappate a risoluzioni non adatte su alcuni dispositivi. Usa invece i valori preimpostati specifici, come AVCaptureSessionPreset1280x720.

    Se la velocità di scansione è importante, puoi ridurre ulteriormente la risoluzione di acquisizione delle immagini. Tuttavia, tieni presente i requisiti minimi per le dimensioni del codice a barre descritti sopra.

    Se stai tentando di riconoscere i codici a barre da una sequenza di fotogrammi video in streaming, il riconoscimento potrebbe produrre risultati diversi da un fotogramma all'altro. Dovresti attendere di ottenere una serie consecutiva dello stesso valore per avere la certezza di restituire un risultato positivo.

    La cifra di checksum non è supportata per ITF e CODE-39.

  • Per elaborare i fotogrammi video, utilizza l'API sincrona results(in:) del rilevatore. Richiama questo metodo dalla funzione captureOutput(_, didOutput:from:) di AVCaptureVideoDataOutputSampleBufferDelegate per ottenere in modo sincrono i risultati dal frame video specificato. Mantieni il valore true per alwaysDiscardsLateVideoFrames di AVCaptureVideoDataOutput per limitare le chiamate al rilevatore. Se un nuovo frame video diventa disponibile mentre il rilevatore è in esecuzione, questo verrà eliminato.
  • Se utilizzi l'output del rilevatore per sovrapporre gli elementi grafici all'immagine di input, recupera prima il risultato da ML Kit, quindi esegui il rendering dell'immagine e dell'overlay in un solo passaggio. In questo modo, esegui il rendering sulla piattaforma di visualizzazione solo una volta per ogni frame di input elaborato. Per un esempio, vedi updatePreviewOverlayViewWithLastFrame nell'esempio della guida rapida di ML Kit.