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

Vous pouvez utiliser ML Kit pour détecter et suivre des objets dans des images vidéo successives.

Lorsque vous transmettez une image à ML Kit, celui-ci détecte jusqu'à cinq objets dans l'image ainsi que la position de chaque objet dans l'image. Lorsque vous détectez des objets dans flux vidéo, chaque objet possède un identifiant unique que vous pouvez utiliser pour suivre d'une image à l'autre. Vous pouvez aussi activer la connectivité de classification, qui attribue aux objets des descriptions de catégories générales.

Essayer

Avant de commencer

  1. Incluez les pods ML Kit suivants dans votre Podfile:
    pod 'GoogleMLKit/ObjectDetection', '3.2.0'
    
  2. Après avoir installé ou mis à jour les pods de votre projet, ouvrez votre projet Xcode à l'aide de son .xcworkspace ML Kit est compatible avec Xcode 12.4 ou version ultérieure.

1. Configurer le détecteur d'objets

Pour détecter et suivre des objets, créez d'abord une instance de ObjectDetector, et éventuellement spécifier 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 ObjectDetectorOptions. Vous pouvez modifier les paramètres suivants : paramètres:

    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égories) 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 en cas de 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 renvoie le résultat après la détermination du cadre de délimitation de l'objet. Si vous activez également le résultat après le cadre de délimitation "étiquette de catégorie" sont toutes deux disponibles. Par conséquent, la détection la latence est potentiellement plus élevée. En mode "Image unique", le suivi Aucun ID n'est attribué. Utilisez ce mode si la latence n'est pas critique vous ne devez pas traiter de résultats partiels.

    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, des lieux et des plantes.

    L'API de détection et de suivi des objets est optimisée pour ces deux utilisations principales cas:

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

Swift

// Live detection and tracking
let options = ObjectDetectorOptions()
options.shouldEnableClassification = true

// Multiple object detection in static images
let options = ObjectDetectorOptions()
options.detectorMode = .singleImage
options.shouldEnableMultipleObjects = true
options.shouldEnableClassification = true

Objective-C

// Live detection and tracking
MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init];
options.shouldEnableClassification = YES;

// Multiple object detection in static images
MLKObjectDetectorOptions *options = [[MLKOptions alloc] init];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableMultipleObjects = YES;
options.shouldEnableClassification = YES;
  1. Obtenez une instance de ObjectDetector:

Swift

let objectDetector = ObjectDetector.objectDetector()

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

Objective-C

MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetector];

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

2. Préparer l'image d'entrée

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 CMSampleBuffer.

Créez un objet VisionImage à l'aide d'un UIImage ou d'un CMSampleBuffer

Si vous utilisez un UIImage, procédez comme suit:

  • Créez un objet VisionImage avec UIImage. Veillez à spécifier le bon .orientation.

    Swift

    let image = VisionImage(image: UIImage)
    visionImage.orientation = image.imageOrientation

    Objective-C

    MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
    visionImage.orientation = image.imageOrientation;

Si vous utilisez un CMSampleBuffer, procédez comme suit:

  • Spécifiez l'orientation des données d'image contenues dans le CMSampleBuffer

    Pour obtenir l'orientation de l'image:

    Swift

    func imageOrientation(
      deviceOrientation: UIDeviceOrientation,
      cameraPosition: AVCaptureDevice.Position
    ) -> UIImage.Orientation {
      switch deviceOrientation {
      case .portrait:
        return cameraPosition == .front ? .leftMirrored : .right
      case .landscapeLeft:
        return cameraPosition == .front ? .downMirrored : .up
      case .portraitUpsideDown:
        return cameraPosition == .front ? .rightMirrored : .left
      case .landscapeRight:
        return cameraPosition == .front ? .upMirrored : .down
      case .faceDown, .faceUp, .unknown:
        return .up
      }
    }
          

    Objective-C

    - (UIImageOrientation)
      imageOrientationFromDeviceOrientation:(UIDeviceOrientation)deviceOrientation
                             cameraPosition:(AVCaptureDevicePosition)cameraPosition {
      switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationLeftMirrored
                                                                : UIImageOrientationRight;
    
        case UIDeviceOrientationLandscapeLeft:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationDownMirrored
                                                                : UIImageOrientationUp;
        case UIDeviceOrientationPortraitUpsideDown:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationRightMirrored
                                                                : UIImageOrientationLeft;
        case UIDeviceOrientationLandscapeRight:
          return cameraPosition == AVCaptureDevicePositionFront ? UIImageOrientationUpMirrored
                                                                : UIImageOrientationDown;
        case UIDeviceOrientationUnknown:
        case UIDeviceOrientationFaceUp:
        case UIDeviceOrientationFaceDown:
          return UIImageOrientationUp;
      }
    }
          
  • Créez un objet VisionImage à l'aide de la méthode Objet CMSampleBuffer et orientation:

    Swift

    let image = VisionImage(buffer: sampleBuffer)
    image.orientation = imageOrientation(
      deviceOrientation: UIDevice.current.orientation,
      cameraPosition: cameraPosition)

    Objective-C

     MLKVisionImage *image = [[MLKVisionImage alloc] initWithBuffer:sampleBuffer];
     image.orientation =
       [self imageOrientationFromDeviceOrientation:UIDevice.currentDevice.orientation
                                    cameraPosition:cameraPosition];

3. Traiter l'image

Transmettez VisionImage à l'un des processus de traitement d'image du détecteur d'objets. méthodes. Vous pouvez utiliser la méthode process(image:) asynchrone ou la méthode results() synchrone.

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

Swift

objectDetector.process(image) { objects, error in
  guard error == nil else {
    // Error.
    return
  }
  guard !objects.isEmpty else {
    // No objects detected.
    return
  }

  // Success. Get object info here.
  // ...
}

Objective-C

[objectDetector processImage:image
                  completion:^(NSArray * _Nullable objects,
                               NSError * _Nullable error) {
                    if (error == nil) {
                      return;
                    }
                    if (objects.count == 0) {
                      // No objects detected.
                      return;
                    }

                    // Success. Get object info here.
                  }];

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

Swift

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

// Success. Get object info here.

Objective-C

NSError *error;
NSArray *objects = [objectDetector resultsInImage:image error:&error];
if (error == nil) {
  return;
}
if (objects.count == 0) {
  // No objects detected.
  return;
}

// Success. Get object info here.

4. Obtenir des informations sur les objets détectés

Si l'appel au processeur d'image aboutit, soit il transmet une liste de Object au gestionnaire d'achèvement ou renvoie la liste, en fonction de que vous ayez appelé la méthode synchrone ou asynchrone.

Chaque Object 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 toutes les images, ou "nil" dans avec le mode "Image unique".
labels Tableau d'étiquettes décrivant l'objet renvoyé par le détecteur. La propriété est vide si l'option de détecteur shouldEnableClassification est défini sur false.

Swift

// objects contains one item if multiple object detection wasn't enabled.
for object in objects {
  let frame = object.frame
  let trackingID = object.trackingID

  // If classification was enabled:
  let description = object.labels.enumerated().map { (index, label) in
    "Label \(index): \(label.text), \(label.confidence)"
    }.joined(separator:"\n")

}

Objective-C

// The list of detected objects contains one item if multiple
// object detection wasn't enabled.
for (MLKObject *object in objects) {
  CGRect frame = object.frame;
  NSNumber *trackingID = object.trackingID;
  for (MLKObjectLabel *label in object.labels) {
    NSString *labelString = [NSString stringWithFormat: @"%@, %f, %lu",
      label.text, label.confidence, (unsigned long)label.index];
    ...
  }
}

Amélioration de la convivialité 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. Dans pour être détectés, les objets dotés d'un petit nombre de caractéristiques visuelles peuvent avoir besoin pour occuper une plus grande partie de l'image. Vous devez fournir aux utilisateurs des conseils sur en capturant une entrée qui fonctionne bien avec le type d'objets que vous souhaitez détecter.
  • Quand 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 le cours 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.
  • Pour traiter les images vidéo, utilisez l'API synchrone results(in:) du détecteur. Appeler cette méthode à partir de AVCaptureVideoDataOutputSampleBufferDelegate <ph type="x-smartling-placeholder"></ph> captureOutput(_, didOutput:from:) pour obtenir les résultats d'une vidéo donnée de manière synchrone. cadre. Conserver <ph type="x-smartling-placeholder"></ph> de AVCaptureVideoDataOutput alwaysDiscardsLateVideoFrames en tant que true afin de limiter les appels au détecteur. Si un nouveau l'image vidéo devient disponible pendant l'exécution du détecteur, elle est ignorée.
  • Si vous utilisez la sortie du détecteur pour superposer des graphiques sur 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 traitée. Consultez la classe updatePreviewOverlayViewWithLastFrame. dans l'exemple de démarrage rapide de ML Kit.