了解 2023 年 Google I/O 大会上介绍的 Firebase 亮点。了解详情

Scansiona i codici a barre con il kit ML 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 usando il suo .xcworkspace .
  3. Nella tua app, importa Firebase:

    Veloce

    import Firebase

    Obiettivo-C

    @import Firebase;

Linee guida per l'immagine di input

  • Affinché ML Kit possa leggere accuratamente 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 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 codici a barre EAN-13 idealmente ha barre e spazi di 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, richiedono dimensioni in pixel maggiori affinché ML Kit li legga in modo affidabile. Ad esempio, un codice PDF417 può contenere fino a 34 "parole" larghe 17 unità in una singola riga, che idealmente dovrebbero essere larghe 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 a risoluzione più elevata (come 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 in modo che rilevi solo quei formati.

Ad esempio, per rilevare solo codice azteco e codici QR, creare 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
  • Data Matrix

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 )
  • Aztec ( FIRVisionBarcodeFormatAztec )
  • Matrice di dati ( FIRVisionBarcodeFormatDataMatrix )

2. Avviare il rilevatore di codici a barre

Per eseguire la scansione di codici a barre in un'immagine, passare l'immagine come UIImage o CMSampleBufferRef al VisionBarcodeDetector di 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 usando un UIImage o un CMSampleBufferRef .

    Per utilizzare UIImage :

    1. Se necessario, ruota l'immagine in modo che la sua proprietà imageOrientation sia .up .
    2. Crea un oggetto VisionImage utilizzando l' UIImage ruotato correttamente. Non specificare metadati 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. Creare un oggetto VisionImageMetadata che specifichi 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 un array di oggetti VisionBarcode . Ogni oggetto VisionBarcode rappresenta un codice a barre che è stato rilevato nell'immagine. Per ogni codice a barre, puoi ottenere le sue coordinate di delimitazione nell'immagine di input, così come i dati grezzi codificati dal codice a barre. Inoltre, se il rilevatore di codici a barre è stato in grado di 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 eseguire la scansione di codici a barre in un'applicazione in tempo reale, segui queste linee guida per ottenere i framerate migliori:

  • Non acquisire input alla risoluzione nativa della fotocamera. Su alcuni dispositivi, l'acquisizione dell'input alla risoluzione nativa produce immagini estremamente grandi (10+ megapixel), il che si traduce in una latenza molto scarsa senza alcun vantaggio in termini di precisione. Invece, richiedi alla fotocamera solo la dimensione necessaria per il rilevamento del codice a barre: in genere non superiore a 2 megapixel.

    Le preimpostazioni della sessione di acquisizione denominata ( AVCaptureSessionPresetDefault , AVCaptureSessionPresetLow , AVCaptureSessionPresetMedium e così via) non sono consigliate, tuttavia, poiché possono essere mappate 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 di dimensione minima del codice a barre sopra descritti.

  • Accelera 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 di input, ottenere prima il risultato da ML Kit, quindi eseguire il rendering dell'immagine e sovrapporre in un unico passaggio. In questo modo, si esegue il rendering sulla superficie di visualizzazione solo una volta per ciascun frame di input. Per un esempio, vedere le classi previewOverlayView e FIRDetectionOverlayView nell'app di esempio della vetrina.