Détecter des postures avec ML Kit sur iOS

ML Kit fournit deux SDK optimisés pour la détection de pose.

Nom du SDKPoseDetectionPoseDetectionAccurate
ImplémentationLes composants du détecteur de base sont liés statiquement à votre application au moment de la compilation.Les composants pour le détecteur précis sont associés statiquement à votre application au moment de la compilation.
Taille de l'applicationJusqu'à 29,6 MoJusqu'à 33,2 Mo
PerformancesiPhone X : ~45 FPSiPhone X : ~29 FPS

Essayer

Avant de commencer

  1. Incluez les pods ML Kit suivants dans votre fichier Podfile :

    # If you want to use the base implementation:
    pod 'GoogleMLKit/PoseDetection', '8.0.0'
    
    # If you want to use the accurate implementation:
    pod 'GoogleMLKit/PoseDetectionAccurate', '8.0.0'
    
  2. Après avoir installé ou mis à jour les pods de votre projet, ouvrez votre projet Xcode à l'aide de son fichier xcworkspace. ML Kit est compatible avec Xcode version 13.2.1 ou ultérieure.

1. Créer une instance de PoseDetector

Pour détecter une pose dans une image, commencez par créer une instance de PoseDetector et spécifiez éventuellement les paramètres du détecteur.

Options PoseDetector

Mode de détection

Le PoseDetector fonctionne dans deux modes de détection. Veillez à sélectionner celui qui correspond à votre cas d'utilisation.

stream (par défaut)
 Le détecteur de pose détecte d'abord la personne la plus en évidence dans l'image, puis exécute la détection de pose. Dans les images suivantes, l'étape de détection de personnes ne sera pas effectuée, sauf si la personne est masquée ou n'est plus détectée avec un degré de confiance élevé. Le détecteur de pose tentera de suivre la personne la plus en vue et de renvoyer sa pose dans chaque inférence. Cela réduit la latence et facilite la détection. Utilisez ce mode lorsque vous souhaitez détecter une pose dans un flux vidéo.
singleImage
Le détecteur de pose détecte une personne, puis exécute la détection de pose. L'étape de détection des personnes s'exécute pour chaque image. La latence est donc plus élevée et il n'y a pas de suivi des personnes. Utilisez ce mode lorsque vous utilisez la détection de pose sur des images statiques ou lorsque le suivi n'est pas souhaité.

Spécifiez les options du détecteur de pose :

Swift

// Base pose detector with streaming, when depending on the PoseDetection SDK
let options = PoseDetectorOptions()
options.detectorMode = .stream

// Accurate pose detector on static images, when depending on the
// PoseDetectionAccurate SDK
let options = AccuratePoseDetectorOptions()
options.detectorMode = .singleImage

Objective-C

// Base pose detector with streaming, when depending on the PoseDetection SDK
MLKPoseDetectorOptions *options = [[MLKPoseDetectorOptions alloc] init];
options.detectorMode = MLKPoseDetectorModeStream;

// Accurate pose detector on static images, when depending on the
// PoseDetectionAccurate SDK
MLKAccuratePoseDetectorOptions *options =
    [[MLKAccuratePoseDetectorOptions alloc] init];
options.detectorMode = MLKPoseDetectorModeSingleImage;

Enfin, obtenez une instance de PoseDetector. Transmettez les options que vous avez spécifiées :

Swift

let poseDetector = PoseDetector.poseDetector(options: options)

Objective-C

MLKPoseDetector *poseDetector =
    [MLKPoseDetector poseDetectorWithOptions:options];

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

Pour détecter les poses, procédez comme suit pour chaque image ou frame de vidéo. Si vous avez activé le mode 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 .orientation approprié.

    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 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 l'objet CMSampleBuffer et de l'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'une des méthodes de traitement d'image du détecteur de pose. Vous pouvez utiliser la méthode asynchrone process(image:) ou la méthode synchrone results().

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

Swift

var results: [Pose]
do {
  results = try poseDetector.results(in: image)
} catch let error {
  print("Failed to detect pose with error: \(error.localizedDescription).")
  return
}
guard let detectedPoses = results, !detectedPoses.isEmpty else {
  print("Pose detector returned no results.")
  return
}

// Success. Get pose landmarks here.

Objective-C

NSError *error;
NSArray *poses = [poseDetector resultsInImage:image error:&error];
if (error != nil) {
  // Error.
  return;
}
if (poses.count == 0) {
  // No pose detected.
  return;
}

// Success. Get pose landmarks here.

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

Swift

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

  // Success. Get pose landmarks here.
}

Objective-C

[poseDetector processImage:image
                completion:^(NSArray * _Nullable poses,
                             NSError * _Nullable error) {
                    if (error != nil) {
                      // Error.
                      return;
                    }
                    if (poses.count == 0) {
                      // No pose detected.
                      return;
                    }

                    // Success. Get pose landmarks here.
                  }];

4. Obtenir des informations sur la pose détectée

Si une personne est détectée dans l'image, l'API de détection de pose transmet un tableau d'objets Pose au gestionnaire d'achèvement ou renvoie le tableau, selon que vous avez appelé la méthode asynchrone ou synchrone.

Si la personne n'était pas entièrement dans l'image, le modèle attribue aux coordonnées des points de repère manquants des valeurs InFrameConfidence faibles et les place en dehors du cadre.

Si aucune personne n'a été détectée, le tableau est vide.

Swift

for pose in detectedPoses {
  let leftAnkleLandmark = pose.landmark(ofType: .leftAnkle)
  if leftAnkleLandmark.inFrameLikelihood > 0.5 {
    let position = leftAnkleLandmark.position
  }
}

Objective-C

for (MLKPose *pose in detectedPoses) {
  MLKPoseLandmark *leftAnkleLandmark =
      [pose landmarkOfType:MLKPoseLandmarkTypeLeftAnkle];
  if (leftAnkleLandmark.inFrameLikelihood > 0.5) {
    MLKVision3DPoint *position = leftAnkleLandmark.position;
  }
}

Conseils pour améliorer les performances

La qualité de vos résultats dépend de celle de l'image d'entrée :

  • Pour que ML Kit détecte précisément la pose, la personne sur l'image doit être représentée par suffisamment de données de pixels. Pour des performances optimales, le sujet doit faire au moins 256 x 256 pixels.
  • Si vous détectez une pose dans une application en temps réel, vous pouvez également tenir compte des dimensions globales des images d'entrée. Les images plus petites peuvent être traitées plus rapidement. Pour réduire la latence, capturez des images à des résolutions plus faibles, mais gardez à l'esprit les exigences de résolution ci-dessus et assurez-vous que le sujet occupe autant d'espace que possible dans l'image.
  • Une mise au point médiocre de l'image peut également avoir un impact sur la précision. Si vous n'obtenez pas de résultats acceptables, demandez à l'utilisateur de reprendre la photo.

Si vous souhaitez utiliser la détection de pose dans une application en temps réel, suivez ces consignes pour obtenir les meilleures fréquences d'images :

  • Utilisez le SDK PoseDetection de base et le mode de détection stream.
  • Envisagez de prendre des photos à une résolution inférieure. Toutefois, gardez également à l'esprit les exigences de cette API concernant les dimensions des images.
  • Pour traiter les images vidéo, utilisez l'API synchrone results(in:) du détecteur. Appelez cette méthode à partir de la fonction captureOutput(_, didOutput:from:) de AVCaptureVideoDataOutputSampleBufferDelegate pour obtenir de manière synchrone les résultats de la frame vidéo donnée. Définissez alwaysDiscardsLateVideoFrames de AVCaptureVideoDataOutput sur "true" pour limiter les appels au détecteur. Si une nouvelle image vidéo devient disponible pendant l'exécution du détecteur, elle sera supprimée.
  • Si vous utilisez la sortie du détecteur pour superposer des éléments graphiques sur l'image d'entrée, obtenez d'abord le résultat de ML Kit, puis affichez l'image et la superposition en une seule étape. Vous n'avez ainsi besoin d'effectuer le rendu sur la surface d'affichage qu'une seule fois pour chaque frame d'entrée traité. Pour obtenir un exemple, consultez les classes previewOverlayView et MLKDetectionOverlayView dans l'application exemple de présentation.

Étapes suivantes