Scansiona i codici a barre con ML Kit su iOS

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

Prova subito

Prima di iniziare

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

Linee guida sull'immagine di input

  • Affinché ML Kit possa leggere con precisione i codici a barre, le immagini di input devono contenere codici a barre rappresentati da dati pixel sufficienti.

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

    Ad esempio, i codici a barre EAN-13 sono composti da barre e spazi larghi 1, 2, 3 o 4 unità, quindi un'immagine codice a barre EAN-13 ha idealmente barre e spazi con una larghezza di almeno 2, 4, 6 e 8 pixel. Poiché un codice a barre EAN-13 ha una larghezza totale di 95 unità, il codice a barre deve avere una larghezza di almeno 190 pixel.

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

  • Una messa a fuoco dell'immagine scadente può influire sulla precisione della scansione. Se la tua app non ottiene risultati accettabili, chiedi all'utente di riprendere l'immagine.

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

    Tuttavia, nelle applicazioni in cui la latenza è fondamentale, puoi migliorare le prestazioni acquisendo immagini a una risoluzione inferiore, ma richiedendo che il codice a barre rappresenti la maggior parte dell'immagine di input. Consulta anche i suggerimenti per migliorare le prestazioni in tempo reale.

1. Configurare il lettore di codici a barre

Se sai quali formati di codici a barre prevedi di leggere, puoi migliorare la velocità dello scanner configurandolo per eseguire la scansione solo di tali formati.

Ad esempio, per scansionare solo il codice azteco e i codici QR, crea un oggetto BarcodeScannerOptions come nell'esempio seguente:

Swift

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

Sono supportati i seguenti formati:

  • codice128
  • codice39
  • codice93
  • codabar
  • DataMatrix
  • EAN13
  • EAN8
  • ITF
  • Codice qr
  • 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 scansionare i codici a barre in un'immagine, passa l'immagine come UIImage o CMSampleBufferRef al metodo process() o results(in:) di BarcodeScanner:

Crea un oggetto VisionImage utilizzando un UIImage o un CMSampleBuffer.

Se utilizzi un UIImage, segui questi passaggi:

  • Crea un oggetto VisionImage con il UIImage. Assicurati di specificare il .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 utilizzi un CMSampleBuffer, segui questi passaggi:

  • Specifica l'orientamento dei dati dell'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 e l'orientamento 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. 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 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. Ricevi 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 coordinate di delimitazione nell'immagine di input, nonché i dati non elaborati codificati dal codice a barre. Inoltre, se lo scanner di codici a barre è in grado di determinare il tipo di dati codificati dal codice a barre, puoi ottenere un oggetto contenente 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 la migliore frequenza fotogrammi:

  • Non acquisire l'input con la risoluzione nativa della videocamera. Su alcuni dispositivi, l'acquisizione degli input con la risoluzione nativa produce immagini estremamente grandi (oltre 10 megapixel), il che si traduce in una latenza molto bassa senza vantaggi per la precisione. Richiedere invece alla fotocamera solo le dimensioni necessarie per la scansione dei codici a barre, che di solito non superano i 2 megapixel.

    Tuttavia, i valori predefiniti per le sessioni di acquisizione (AVCaptureSessionPresetDefault, AVCaptureSessionPresetLow, AVCaptureSessionPresetMedium e così via) non sono consigliati, in quanto possono essere mappati a risoluzioni non adatte su alcuni dispositivi. Utilizza invece le preimpostazioni specifiche, 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 dei codici a barre indicati sopra.

    Se stai cercando di riconoscere i codici a barre da una sequenza di frame video in streaming, il riconoscimento potrebbe produrre risultati diversi da un frame all'altro. Devi attendere finché non ottieni una serie consecutivi di valori uguali per assicurarti di restituire un buon risultato.

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

  • Per l'elaborazione dei frame 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 alwaysDiscardsLateVideoFrames di AVCaptureVideoDataOutput come true per limitare le chiamate al rilevatore. Se un nuovo video diventa disponibile mentre il rilevatore è in esecuzione, viene eliminato.
  • Se utilizzi l'output del rilevatore per sovrapporre la grafica all'immagine di input, prima ottieni il risultato da ML Kit, quindi visualizza l'immagine e l'overlay in un solo passaggio. In questo modo, visualizzerai nella piattaforma display solo una volta per ogni frame di input elaborato. Guarda un esempio di updateAnteprimaOverlayViewWithLastFrame nell'esempio della guida rapida di ML Kit.