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

Vous pouvez utiliser ML Kit pour détecter et suivre des objets sur plusieurs images d'une 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 dans les flux vidéo, chaque objet possède un identifiant que vous pouvez utiliser pour suivre entre les images. Vous pouvez aussi activer la connectivité de classification, qui attribue aux objets des descriptions de catégories générales.

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', '6.25.0'
    pod 'Firebase/MLVisionObjectDetection', '6.25.0'
    
    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:
    import Firebase
    @import Firebase;

1. Configurer le détecteur d'objets

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

  1. Configurez le détecteur d'objets pour votre cas d'utilisation à l'aide d'une 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'objets s'exécute avec une faible mais peut produire des résultats incomplets (par exemple, cadres de délimitation ou catégorie) lors des premiers appels de le détecteur. En mode flux, le détecteur attribue le suivi des identifiants d'objets, que vous pouvez utiliser pour suivre des objets sur plusieurs frames. Utilisez ce mode lorsque vous souhaitez suivre des objets ou lorsque la faible latence est importante, par exemple lors du traitement de flux vidéo en temps réel.

    En mode "Image unique", le détecteur d'objets attend qu'une cadre de délimitation de l'objet et catégorie (si vous avez activé la classification) sont disponibles avant de renvoyer un résultat. Par conséquent, la latence de détection est potentiellement plus élevée. De plus, dans une seule image, , aucun ID de suivi n'est attribué. Utilisez ce mode si la latence n'est pas critique et ne doit pas être traité résultats.

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

    Permet de détecter et de suivre jusqu'à cinq objets, ou seulement les plus objet proéminent (par défaut).

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

    Indique s'il faut classer ou non les objets détectés en catégories approximatives. Lorsqu'il est activé, le détecteur d'objets classe les objets dans les catégories suivantes: articles de mode, alimentation, articles pour la maison, de lieux, de plantes et d’inconnus.

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

    • Détection et suivi en direct de l'objet le plus proéminent de la caméra viseur
    • Détection de plusieurs objets dans une image statique

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

    // 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
    
    // 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:

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

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

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

  1. 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 de sorte que son imageOrientation est .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).
      let image = VisionImage(image: uiImage)
      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:

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

      let cameraPosition = AVCaptureDevice.Position.back  // Set to the capture device you used.
      let metadata = VisionImageMetadata()
      metadata.orientation = imageOrientation(
          deviceOrientation: UIDevice.current.orientation,
          cameraPosition: cameraPosition
      )
      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:
      let image = VisionImage(buffer: sampleBuffer)
      image.metadata = metadata
      FIRVisionImage *image = [[FIRVisionImage alloc] initWithBuffer:sampleBuffer];
      image.metadata = metadata;
  2. Transmettez l'VisionImage à l'une des méthodes de traitement d'images du détecteur d'objets. Vous pouvez utiliser la méthode process(image:) asynchrone ou la méthode results() synchrone.

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

    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.
      // ...
    }
    
    [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, procédez comme suit:

    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
    }
    
    // ...
    
    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 du processeur d'images aboutit, il transmet une liste de VisionObject au gestionnaire de finalisation ou la renvoie, 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 Entier qui identifie l'objet dans les images. Nil dans un seul le mode Image.
    classificationCategory Catégorie approximative de l'objet. Si le détecteur d'objets pour lequel la classification est activée, il s'agit toujours de .unknown.
    confidence Niveau de confiance de la classification des objets. Si l'objet n'a pas de classification activée ou si l'objet est classée comme inconnue, la requête suivante est nil.
    // 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
    }
    
    // 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 l'usabilité et des performances

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

  • La réussite d'une détection d'objets dépend de sa complexité visuelle. Objets avec un petit nombre de caractéristiques visuelles peuvent avoir besoin d’occuper une plus grande partie l'image à détecter. 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.
  • Lorsque vous utilisez la classification, si vous souhaitez détecter les objets qui ne tombent pas correctement dans les catégories prises en charge, implémenter un traitement spécial pour les d'objets.

Consultez également les [Application de présentation Material Design de ML Kit][showcase-link]{: .external } et Material Design Modèles pour la collection de caractéristiques basées sur le machine learning.

Lorsque vous utilisez le mode de traitement par flux dans une application en temps réel, suivez ces consignes pour d'obtenir les meilleures fréquences d'images:

  • N'utilisez pas la détection d'objets multiples en mode de traitement par flux, car la plupart des appareils être en mesure de produire des fréquences d'images adéquates.

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

  • Limiter 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. Pour en savoir plus, consultez les classes previewOverlayView et FIRDetectionOverlayView dans l'application exemple de démonstration.

ML Kit for Firebase provided ready-to-use ML solutions for app developers. New apps should use the standalone ML Kit library for on-device ML and Firebase ML for cloud-based ML.

Mise à jour le Feb 28, 2025

ML Kit for Firebase provided ready-to-use ML solutions for app developers. New apps should use the standalone ML Kit library for on-device ML and Firebase ML for cloud-based ML.

Mise à jour le Feb 28, 2025

ML Kit for Firebase provided ready-to-use ML solutions for app developers. New apps should use the standalone ML Kit library for on-device ML and Firebase ML for cloud-based ML.

Mise à jour le Feb 28, 2025