Join us in person and online for Firebase Summit on October 18, 2022. Learn how Firebase can help you accelerate app development, release your app with confidence, and scale with ease. Register now

Détecter et suivre des objets avec ML Kit sur iOS

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

Vous pouvez utiliser ML Kit pour détecter et suivre des objets à travers les images de la vidéo.

Lorsque vous transmettez des images ML Kit, ML Kit renvoie, pour chaque image, une liste de jusqu'à cinq objets détectés et leur position dans l'image. Lors de la détection d'objets dans des flux vidéo, chaque objet a un ID que vous pouvez utiliser pour suivre l'objet à travers les images. Vous pouvez également éventuellement activer la classification grossière des objets, qui étiquette les objets avec des descriptions de catégorie larges.

Avant que tu commences

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

    Rapide

    import Firebase

    Objectif c

    @import Firebase;

1. Configurer le détecteur d'objets

Pour commencer à détecter et à suivre des objets, créez d'abord une instance de VisionObjectDetector , en spécifiant éventuellement les paramètres du détecteur que vous souhaitez modifier par défaut.

  1. Configurez le détecteur d'objets pour votre cas d'utilisation avec un objet VisionObjectDetectorOptions . Vous pouvez modifier les paramètres suivants :

    Paramètres du détecteur d'objets
    Mode de détection .stream (par défaut) | .singleImage

    En mode flux (par défaut), le détecteur d'objet s'exécute avec une latence très faible, mais peut produire des résultats incomplets (tels que des cadres de délimitation ou une catégorie non spécifiés) lors des premières invocations du détecteur. De plus, en mode flux, le détecteur attribue des identifiants de suivi aux objets, que vous pouvez utiliser pour suivre les objets à travers les images. Utilisez ce mode lorsque vous souhaitez suivre des objets ou lorsqu'une faible latence est importante, comme lors du traitement de flux vidéo en temps réel.

    En mode image unique, le détecteur d'objet attend que la boîte englobante d'un objet détecté et (si vous avez activé la classification) la catégorie soient disponibles avant de renvoyer un résultat. Par conséquent, la latence de détection est potentiellement plus élevée. De plus, en mode image unique, les identifiants de suivi ne sont pas attribués. Utilisez ce mode si la latence n'est pas critique et que vous ne voulez pas traiter des résultats partiels.

    Détecter et suivre plusieurs objets false (par défaut) | true

    S'il faut détecter et suivre jusqu'à cinq objets ou seulement l'objet le plus important (par défaut).

    Classer les objets false (par défaut) | true

    S'il faut ou non classer les objets détectés dans des catégories grossières. Lorsqu'il est activé, le détecteur d'objets classe les objets dans les catégories suivantes : articles de mode, aliments, articles pour la maison, lieux, plantes et inconnus.

    L'API de détection et de suivi d'objets est optimisée pour ces deux principaux cas d'utilisation :

    • Détection et suivi en direct de l'objet le plus visible dans le viseur de l'appareil photo
    • Détection de plusieurs objets dans une image statique

    Pour configurer l'API pour ces cas d'utilisation :

    Rapide

    // Live detection and tracking
    let options = VisionObjectDetectorOptions()
    options.detectorMode = .stream
    options.shouldEnableMultipleObjects = false
    options.shouldEnableClassification = true  // Optional
    
    // Multiple object detection in static images
    let options = VisionObjectDetectorOptions()
    options.detectorMode = .singleImage
    options.shouldEnableMultipleObjects = true
    options.shouldEnableClassification = true  // Optional
    

    Objectif c

    // Live detection and tracking
    FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init];
    options.detectorMode = FIRVisionObjectDetectorModeStream;
    options.shouldEnableMultipleObjects = NO;
    options.shouldEnableClassification = YES;  // Optional
    
    // Multiple object detection in static images
    FIRVisionObjectDetectorOptions *options = [[FIRVisionObjectDetectorOptions alloc] init];
    options.detectorMode = FIRVisionObjectDetectorModeSingleImage;
    options.shouldEnableMultipleObjects = YES;
    options.shouldEnableClassification = YES;  // Optional
    
  2. Obtenez une instance de FirebaseVisionObjectDetector :

    Rapide

    let objectDetector = Vision.vision().objectDetector()
    
    // Or, to change the default settings:
    let objectDetector = Vision.vision().objectDetector(options: options)
    

    Objectif c

    FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetector];
    
    // Or, to change the default settings:
    FIRVisionObjectDetector *objectDetector = [[FIRVision vision] objectDetectorWithOptions:options];
    

2. Exécutez le détecteur d'objets

Pour détecter et suivre des objets, procédez comme suit pour chaque image ou image de vidéo. Si vous avez activé le mode flux, vous devez créer des objets VisionImage à partir de CMSampleBufferRef s.

  1. Créez un objet VisionImage à l'aide d'un UIImage ou d'un CMSampleBufferRef .

    Pour utiliser une UIImage :

    1. Si nécessaire, faites pivoter l'image afin que sa propriété imageOrientation soit .up .
    2. Créez un objet VisionImage à l'aide de l'objet UIImage correctement pivoté. Ne spécifiez aucune métadonnée de rotation—la valeur par défaut, .topLeft , doit être utilisée.

      Rapide

      let image = VisionImage(image: uiImage)

      Objectif c

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

    Pour utiliser un CMSampleBufferRef :

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

      Pour obtenir l'orientation de l'image :

      Rapide

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

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

      Créez ensuite l'objet de métadonnées :

      Rapide

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

      Objectif 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 l'objet CMSampleBufferRef et des métadonnées de rotation :

      Rapide

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

      Objectif c

      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  2. Passez le VisionImage à l'une des méthodes de traitement d'image du détecteur d'objet. Vous pouvez soit utiliser la méthode asynchrone process(image:) ou la méthode synchrone results() .

    Pour détecter des objets de manière asynchrone :

    Rapide

    objectDetector.process(image) { detectedObjects, error in
      guard error == nil else {
        // Error.
        return
      }
      guard let detectedObjects = detectedObjects, !detectedObjects.isEmpty else {
        // No objects detected.
        return
      }
    
      // Success. Get object info here.
      // ...
    }
    

    Objectif c

    [objectDetector processImage:image
                      completion:^(NSArray<FIRVisionObject *> * _Nullable objects,
                                   NSError * _Nullable error) {
                        if (error == nil) {
                          return;
                        }
                        if (objects == nil | objects.count == 0) {
                          // No objects detected.
                          return;
                        }
    
                        // Success. Get object info here.
                        // ...
                      }];
    

    Pour détecter des objets de manière synchrone :

    Rapide

    var results: [VisionObject]? = nil
    do {
      results = try objectDetector.results(in: image)
    } catch let error {
      print("Failed to detect object with error: \(error.localizedDescription).")
      return
    }
    guard let detectedObjects = results, !detectedObjects.isEmpty else {
      print("Object detector returned no results.")
      return
    }
    
    // ...
    

    Objectif c

    NSError *error;
    NSArray<FIRVisionObject *> *objects = [objectDetector resultsInImage:image
                                                                   error:&error];
    if (error == nil) {
      return;
    }
    if (objects == nil | objects.count == 0) {
      // No objects detected.
      return;
    }
    
    // Success. Get object info here.
    // ...
    
  3. Si l'appel au processeur d'image réussit, il transmet une liste de VisionObject au gestionnaire d'achèvement ou renvoie la liste, selon que vous avez appelé la méthode asynchrone ou synchrone.

    Chaque VisionObject contient les propriétés suivantes :

    frame Un CGRect indiquant la position de l'objet dans l'image.
    trackingID Un entier qui identifie l'objet à travers les images. Nul en mode image unique.
    classificationCategory La catégorie grossière de l'objet. Si le détecteur d'objets n'a pas de classification activée, c'est toujours .unknown .
    confidence La valeur de confiance de la classification d'objet. Si le détecteur d'objet n'a pas de classification activée, ou si l'objet est classé comme inconnu, c'est nil .

    Rapide

    // detectedObjects contains one item if multiple object detection wasn't enabled.
    for obj in detectedObjects {
      let bounds = obj.frame
      let id = obj.trackingID
    
      // If classification was enabled:
      let category = obj.classificationCategory
      let confidence = obj.confidence
    }
    

    Objectif c

    // The list of detected objects contains one item if multiple
    // object detection wasn't enabled.
    for (FIRVisionObject *obj in objects) {
      CGRect bounds = obj.frame;
      if (obj.trackingID) {
        NSInteger id = obj.trackingID.integerValue;
      }
    
      // If classification was enabled:
      FIRVisionObjectCategory category = obj.classificationCategory;
      float confidence = obj.confidence.floatValue;
    }
    

Amélioration de la convivialité et des performances

Pour une expérience utilisateur optimale, suivez ces consignes dans votre application :

  • La réussite de la détection d'objet dépend de la complexité visuelle de l'objet. Les objets avec un petit nombre de caractéristiques visuelles peuvent devoir occuper une plus grande partie de l'image pour être détectés. Vous devez fournir aux utilisateurs des conseils sur la capture d'entrées qui fonctionnent bien avec le type d'objets que vous souhaitez détecter.
  • Lors de l'utilisation de la classification, si vous souhaitez détecter des objets qui n'appartiennent pas clairement aux catégories prises en charge, implémentez une gestion spéciale pour les objets inconnus.

Découvrez également [ML Kit Material Design showcase app][showcase-link]{: .external } et la collection Material Design Patterns for machine learning-powered feature.

Lorsque vous utilisez le mode de diffusion en continu dans une application en temps réel, suivez ces instructions pour obtenir les meilleures fréquences d'images :

  • N'utilisez pas la détection d'objets multiples en mode streaming, car la plupart des appareils ne seront pas en mesure de produire des fréquences d'images adéquates.

  • Désactivez la classification si vous n'en avez pas besoin.

  • Throttle appelle le détecteur. Si une nouvelle image vidéo devient disponible pendant que le détecteur fonctionne, supprimez l'image.
  • Si vous utilisez la sortie du détecteur pour superposer des graphiques sur l'image d'entrée, obtenez d'abord le résultat de ML Kit, puis effectuez le rendu de l'image et de la superposition en une seule étape. Ce faisant, vous effectuez le rendu sur la surface d'affichage une seule fois pour chaque image d'entrée. Voir les classes previewOverlayView et FIRDetectionOverlayView dans l'exemple d'application vitrine pour un exemple.