Scansiona codici a barre con ML Kit su iOS

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

Prima di iniziare

  1. Se non hai già aggiunto Firebase alla tua app, fallo seguendo i passaggi nella guida introduttiva .
  2. Includi le librerie ML Kit nel tuo Podfile:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    Dopo aver installato o aggiornato i Pod del tuo progetto, assicurati di aprire il tuo progetto Xcode utilizzando il relativo .xcworkspace .
  3. Nella tua app, importa Firebase:

    Veloce

    import Firebase

    Obiettivo-C

    @import Firebase;

Inserisci le linee guida per l'immagine

  • 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 dei dati pixel dipendono sia dal tipo di codice a barre che dalla quantità di dati in esso codificati (poiché la maggior parte dei codici a barre supporta un carico utile di lunghezza variabile). In generale, la più piccola unità significativa del codice a barre dovrebbe essere larga almeno 2 pixel (e per i codici bidimensionali, alta 2 pixel).

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

    I formati più densi, come PDF417, necessitano di 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, che idealmente sarebbe larga almeno 1156 pixel.

  • Una scarsa messa a fuoco dell'immagine può compromettere la precisione della scansione. Se non ottieni risultati accettabili, prova a chiedere all'utente di acquisire nuovamente l'immagine.

  • Per le applicazioni tipiche, si consiglia di fornire un'immagine con una risoluzione più elevata (ad esempio 1280x720 o 1920x1080), che renda i codici a barre rilevabili 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 richiedendo che il codice a barre costituisca la maggior parte dell'immagine di input. Vedi anche Suggerimenti per migliorare le prestazioni in tempo reale .

1. Configurare il rilevatore di codici a barre

Se sai quali formati di codici a barre prevedi di leggere, puoi migliorare la velocità del rilevatore di codici a barre configurandolo per rilevare solo tali formati.

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

Veloce

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

Sono supportati i seguenti formati:

  • Codice128
  • Codice39
  • Codice93
  • CodaBar
  • EAN13
  • EAN8
  • ITF
  • UPCA
  • UPCE
  • QR Code
  • PDF417
  • Azteco
  • DataMatrix

Obiettivo-C

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

Sono supportati i seguenti formati:

  • Codice 128 ( FIRVisionBarcodeFormatCode128 )
  • Codice 39 ( FIRVisionBarcodeFormatCode39 )
  • Codice 93 ( FIRVisionBarcodeFormatCode93 )
  • Codabar ( FIRVisionBarcodeFormatCodaBar )
  • EAN-13 ( FIRVisionBarcodeFormatEAN13 )
  • EAN-8 ( FIRVisionBarcodeFormatEAN8 )
  • ITF ( FIRVisionBarcodeFormatITF )
  • UPC-A ( FIRVisionBarcodeFormatUPCA )
  • UPC-E ( FIRVisionBarcodeFormatUPCE )
  • Codice QR ( FIRVisionBarcodeFormatQRCode )
  • PDF417 ( FIRVisionBarcodeFormatPDF417 )
  • Azteco ( FIRVisionBarcodeFormatAztec )
  • Matrice dati ( FIRVisionBarcodeFormatDataMatrix )

2. Eseguire il rilevatore di codici a barre

Per eseguire la scansione dei codici a barre in un'immagine, passare l'immagine come UIImage o CMSampleBufferRef al metodo detect(in:) di VisionBarcodeDetector :

  1. Ottieni un'istanza di VisionBarcodeDetector :

    Veloce

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

    Obiettivo-C

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

    Per utilizzare un'immagine UIImage :

    1. Se necessario, ruotare l'immagine in modo che la relativa proprietà imageOrientation sia .up .
    2. Crea un oggetto VisionImage utilizzando UIImage ruotato correttamente. Non specificare alcun metadato di rotazione: è necessario utilizzare il valore predefinito, .topLeft .

      Veloce

      let image = VisionImage(image: uiImage)

      Obiettivo-C

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

    Per utilizzare un CMSampleBufferRef :

    1. Crea un oggetto VisionImageMetadata che specifica l'orientamento dei dati dell'immagine contenuti nel buffer CMSampleBufferRef .

      Per ottenere l'orientamento dell'immagine:

      Veloce

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

      Obiettivo-C

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

      Quindi, crea l'oggetto metadati:

      Veloce

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )

      Obiettivo-C

      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. Crea un oggetto VisionImage utilizzando l'oggetto CMSampleBufferRef e i metadati di rotazione:

      Veloce

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

      Obiettivo-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Quindi, passa l'immagine al metodo detect(in:) :

    Veloce

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

    Obiettivo-C

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

3. Ottieni informazioni dai codici a barre

Se l'operazione di riconoscimento del codice a barre ha esito positivo, il rilevatore restituisce una serie di oggetti VisionBarcode . Ogni oggetto VisionBarcode rappresenta un codice a barre rilevato nell'immagine. Per ciascun codice a barre è possibile ottenere le coordinate di delimitazione nell'immagine di input, nonché i dati grezzi codificati dal codice a barre. Inoltre, se il rilevatore di codici a barre è riuscito a determinare il tipo di dati codificati dal codice a barre, è possibile ottenere un oggetto contenente dati analizzati.

Per esempio:

Veloce

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

Obiettivo-C

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

Suggerimenti per migliorare le prestazioni in tempo reale

Se desideri scansionare i codici a barre in un'applicazione in tempo reale, segui queste linee guida per ottenere i migliori framerate:

  • Non acquisire l'input alla risoluzione nativa della fotocamera. Su alcuni dispositivi, l'acquisizione dell'input alla risoluzione nativa produce immagini estremamente grandi (oltre 10 megapixel), il che si traduce in una latenza molto ridotta senza alcun vantaggio in termini di precisione. Richiedi invece alla fotocamera solo la dimensione necessaria per il rilevamento dei codici a barre: solitamente non più di 2 megapixel.

    Le preimpostazioni della sessione di acquisizione denominate AVCaptureSessionPresetDefault , AVCaptureSessionPresetLow , AVCaptureSessionPresetMedium e così via) non sono consigliate, tuttavia, poiché possono essere associate a risoluzioni non adatte su alcuni dispositivi. Utilizzare invece le preimpostazioni specifiche come AVCaptureSessionPreset1280x720 .

    Se la velocità di scansione è importante, è possibile ridurre ulteriormente la risoluzione di acquisizione dell'immagine. Tuttavia, tieni presente i requisiti relativi alle dimensioni minime del codice a barre sopra indicati.

  • Limita le chiamate al rilevatore. Se un nuovo fotogramma video diventa disponibile mentre il rilevatore è in funzione, rilasciare il fotogramma.
  • Se si utilizza l'output del rilevatore per sovrapporre la grafica all'immagine in input, ottenere prima il risultato da ML Kit, quindi eseguire il rendering dell'immagine e sovrapporre in un unico passaggio. In questo modo, viene eseguito il rendering sulla superficie di visualizzazione solo una volta per ciascun fotogramma di input. Per un esempio, vedi le classi PreviewOverlayView e FIRDetectionOverlayView nell'app di esempio vetrina.