Scanner des codes-barres avec ML Kit sur iOS

Vous pouvez utiliser ML Kit pour reconnaître et décoder les codes à barres.

Avant de commencer

  1. Si vous n'avez pas encore ajouté Firebase à votre application, suivez les les étapes décrites dans le guide de démarrage.
  2. Incluez les bibliothèques ML Kit dans votre Podfile:
    pod 'Firebase/MLVision'
    pod 'Firebase/MLVisionBarcodeModel'
    
    Après avoir installé ou mis à jour les pods de votre projet, ouvrez votre Xcode projet à l'aide de son .xcworkspace.
  3. Dans votre application, importez Firebase:

    Swift

    import Firebase

    Objective-C

    @import Firebase;

Consignes pour les images d'entrée

  • Pour que ML Kit lise précisément les codes-barres, les images d'entrée doivent contenir des codes-barres représentés par suffisamment de données de pixel.

    Les exigences spécifiques concernant les données de pixels dépendent à la fois du type code-barres et la quantité de données qui y sont encodées (puisque la plupart des codes-barres acceptent une charge utile de longueur variable). En général, la plus petite l'unité du code-barres doit être d'au moins 2 pixels de large (et pour codes bidimensionnels, hauteur de 2 pixels).

    Par exemple, les codes-barres EAN-13 sont composés de barres et d'espaces 1, 2, 3 ou 4 unités de large, donc une image de code-barres EAN-13 idéalement a des barres et espaces d'au moins 2, 4, 6 et 8 pixels de largeur. Étant donné qu'un code EAN-13 le code-barres fait 95 unités de large au total, le code-barres doit être d'au moins 190 pixels.

    Les formats de densité (tels que PDF417) nécessitent des dimensions en pixels supérieures pour ML Kit pour les lire de manière fiable. Par exemple, un code PDF417 peut contenir jusqu'à 34 "mots" de 17 unités de large sur une même ligne, qui devrait idéalement être au moins Largeur de 1 156 pixels.

  • Une mauvaise mise au point de l'image peut nuire à la précision de la numérisation. Si vous n'obtenez pas des résultats acceptables, essayez de demander à l'utilisateur de reprendre l'image.

  • Pour les applications standards, nous vous recommandons de fournir une image de résolution plus élevée (par exemple, 1 280 x 720 ou 1 920 x 1 080), ce qui permet de détecter les codes-barres à une plus grande distance de l'appareil photo.

    Toutefois, dans les applications où la latence est essentielle, vous pouvez améliorer en collectant des images à une résolution inférieure, le code-barres constituent la majorité de l'image d'entrée. Voir aussi Conseils pour améliorer les performances en temps réel

1. Configurer le détecteur de code-barres

Si vous connaissez les formats de code-barres que vous comptez lire, vous pouvez améliorer la vitesse de lecture du détecteur de code-barres en le configurant pour ne détecter que ces formats.

Par exemple, pour ne détecter que les codes Aztec et les codes QR, créez un objet VisionBarcodeDetectorOptions comme dans l'exemple suivant :

Swift

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

Les formats suivants sont acceptés :

  • Code128
  • Code39
  • Code93
  • CodaBar
  • EAN13
  • Code EAN8
  • ITF
  • UPCA
  • UPCE
  • Code QR
  • PDF417
  • Aztèque
  • DataMatrix

Objective-C

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

Les formats suivants sont acceptés :

  • Code 128 (FIRVisionBarcodeFormatCode128)
  • Code 39 (FIRVisionBarcodeFormatCode39)
  • Code 93 (FIRVisionBarcodeFormatCode93)
  • Codabar (FIRVisionBarcodeFormatCodaBar)
  • EAN-13 (FIRVisionBarcodeFormatEAN13)
  • EAN-8 (FIRVisionBarcodeFormatEAN8)
  • ITF (FIRVisionBarcodeFormatITF)
  • UPC-A (FIRVisionBarcodeFormatUPCA)
  • UPC-E (FIRVisionBarcodeFormatUPCE)
  • Code QR (FIRVisionBarcodeFormatQRCode)
  • PDF417 (FIRVisionBarcodeFormatPDF417)
  • Aztèque (FIRVisionBarcodeFormatAztec)
  • Matrice de données (FIRVisionBarcodeFormatDataMatrix)

2. Exécuter le détecteur de code-barres

Pour scanner le code-barres d'une image, transmettez-la en tant que UIImage ou CMSampleBufferRef jusqu'au detect(in:) de VisionBarcodeDetector méthode:

  1. Obtenez une instance de VisionBarcodeDetector:

    Swift

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

    Objective-C

    FIRVision *vision = [FIRVision vision];
    FIRVisionBarcodeDetector *barcodeDetector = [vision barcodeDetector];
    // Or, to change the default settings:
    // FIRVisionBarcodeDetector *barcodeDetector =
    //     [vision barcodeDetectorWithOptions:options];
  2. Créez un objet VisionImage à l'aide d'un UIImage ou d'un CMSampleBufferRef

    Pour utiliser un UIImage:

    1. Si nécessaire, faites pivoter l'image pour que sa propriété imageOrientation soit .up.
    2. Créez un objet VisionImage en utilisant la rotation correcte UIImage Ne spécifiez aucune métadonnée de rotation (valeur par défaut : (.topLeft).

      Swift

      let image = VisionImage(image: uiImage)

      Objective-C

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

    Pour utiliser un CMSampleBufferRef:

    1. Créez un objet VisionImageMetadata qui spécifie le l'orientation des données d'image contenues dans le Mémoire tampon CMSampleBufferRef.

      Pour obtenir l'orientation de l'image:

      Swift

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

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

      Ensuite, créez l'objet de métadonnées:

      Swift

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

      Objective-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. Créez un objet VisionImage à l'aide de la méthode CMSampleBufferRef et les métadonnées de rotation:

      Swift

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

      Objective-C

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  3. Transmettez ensuite l'image à la méthode detect(in:):

    Swift

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

    Objective-C

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

3. Obtenir des informations à partir des codes-barres

Si l'opération de reconnaissance de code-barres aboutit, le détecteur renvoie un tableau des Objets VisionBarcode. Chaque objet VisionBarcode représente le code-barres détecté dans l'image. Pour chaque code-barres, vous pouvez obtenir les coordonnées de délimitation dans l'image d'entrée, ainsi que les données brutes encodées par code-barres. De plus, si le détecteur de codes-barres a pu déterminer le type de données encodé par le code-barres, vous pouvez obtenir un objet contenant des données analysées.

Exemple :

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

Conseils pour améliorer les performances en temps réel

Si vous souhaitez scanner des codes-barres dans une application en temps réel, suivez ces consignes pour obtenir les meilleurs fréquences d'images :

  • Ne enregistrez pas d'entrée à la résolution native de l'appareil photo. Sur certains appareils, la capture d'entrée à la résolution native produit des images extrêmement volumineuses (plus de 10 de pixels), ce qui entraîne une latence très faible et ne présente aucun avantage précision. Demandez plutôt la taille à la caméra requise pour la détection des codes-barres: généralement inférieure à 2 mégapixels.

    Les préréglages de la session de capture nommée : AVCaptureSessionPresetDefault, AVCaptureSessionPresetLow, AVCaptureSessionPresetMedium, etc.), elles ne sont pas recommandées, car elles peuvent correspondre les résolutions inappropriées sur certains appareils. Utilisez plutôt les préréglages spécifiques comme AVCaptureSessionPreset1280x720.

    Si la vitesse de numérisation est importante, vous pouvez réduire davantage la capture d'image. la résolution de problèmes. Toutefois, tenez compte des exigences minimales de taille des codes-barres décrites ci-dessus.

  • Limitez les appels au détecteur. Si une nouvelle image vidéo devient disponible pendant l'exécution du détecteur, supprimez la trame.
  • Si vous utilisez la sortie du détecteur pour superposer des images l'image d'entrée, récupérez d'abord le résultat à partir de ML Kit, puis effectuez le rendu de l'image. et les superposer en une seule étape. Cela vous permet d'afficher sur la surface d'affichage une seule fois pour chaque trame d'entrée. Consultez la vue previewOverlayView. et FIRDetectionOverlayView dans l'application exemple Showcase.