使用机器学习套件检测姿势 (iOS)

ML Kit 提供了两个针对姿势检测进行优化的 SDK。

SDK 名称PoseDetectionPoseDetectionAccurate
实现基础检测器的资源在构建时会静态链接到您的应用。精准检测器的资源在构建时会静态链接到您的应用。
应用大小最大 29.6MB最大 33.2MB
性能iPhone X:约 45 FPSiPhone X:约 29FPS

试试看

  • 您可以试用示例应用,了解此 API 的使用示例。

准备工作

  1. 在 Podfile 中添加以下 ML Kit pod:

    # 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. 安装或更新项目的 pod 之后,请使用 Xcode 项目的 xcworkspace 打开该项目。Xcode 13.2.1 版或更高版本支持机器学习套件。

1. 创建 PoseDetector 实例

如需检测图片中的姿势,请先创建 PoseDetector 的实例,并视需要指定检测器设置。

PoseDetector 个选项

检测模式

PoseDetector 在两种检测模式下运行。请务必选择与您的使用场景相符的选项。

stream(默认)
姿势检测器会先检测图片中最突出的人,然后运行姿势检测。在后续帧中,除非人物被遮挡或不再以高置信度被检测到,否则不会再进行人物检测步骤。姿势检测器会尝试跟踪最突出的人,并在每次推理中返回其姿势。这样可以减少延迟并使检测更加顺畅。如果您想检测视频流中的姿势,请使用此模式。
singleImage
姿势检测器会检测人物,然后运行姿势检测。人检测步骤将针对每张图片运行,因此延迟时间会更长,并且不会进行人跟踪。在静态图片上使用姿势检测或不需要跟踪时,请使用此模式。

指定姿势检测器选项:

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;

最后,获取 PoseDetector 的一个实例。传递您指定的选项:

Swift

let poseDetector = PoseDetector.poseDetector(options: options)

Objective-C

MLKPoseDetector *poseDetector =     [MLKPoseDetector poseDetectorWithOptions:options];

2. 准备输入图片

如需检测姿势,请对每个图片或视频帧执行以下操作。 如果您启用了流模式,则必须基于 CMSampleBuffer 创建 VisionImage 对象。

使用 UIImageCMSampleBuffer 创建一个 VisionImage 对象。

如果您使用的是 UIImage,请按以下步骤操作:

  • 使用 UIImage 创建一个 VisionImage 对象。请务必指定正确的 .orientation

    Swift

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

    Objective-C

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

如果您使用的是 CMSampleBuffer,请按以下步骤操作:

  • 指定 CMSampleBuffer 中所含图片数据的方向。

    如需获取图片方向,请运行以下命令:

    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;   } }       
  • 使用 CMSampleBuffer 对象和方向创建一个 VisionImage 对象:

    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. 处理图片

VisionImage 传递给姿势检测器的图片处理方法之一。您可以使用异步的 process(image:) 方法或同步的 results() 方法。

如需同步检测对象,请运行以下代码:

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.

如需异步检测对象,请运行以下代码:

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. 获取有关检测到的姿势的信息

如果检测到图片中有人,姿势检测 API 会将 Pose 对象数组传递给完成处理程序或返回该数组,具体取决于您调用的是异步方法还是同步方法。

如果人物未完全位于图片内,模型会将缺失的地标坐标分配到框架外,并为其提供较低的 InFrameConfidence 值。

如果未检测到任何人,则该数组为空。

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

提升效果的相关提示

结果的质量取决于输入图片的质量:

  • 为了使机器学习套件准确检测姿势,图片中的人物应由足够大的像素数据表示;为获得最佳性能,拍摄对象应至少为 256x256 像素。
  • 如果您是在实时应用中检测姿势,可能还需要考虑输入图片的整体尺寸。较小图片的处理速度相对较快,因此,为了减少延迟时间,请以较低的分辨率捕获图片,但请牢记上述分辨率要求,并确保正文在图片中占据尽可能大的画面。
  • 图片聚焦不良也会影响准确性。如果您无法获得满意的结果,请让用户重新捕获图片。

如果要在实时应用中使用姿势检测,请遵循以下准则以实现最佳帧速率:

  • 使用基本 PoseDetection SDK 和 stream 检测模式。
  • 建议以较低分辨率捕获图片,但是,请注意此 API 的图片尺寸要求。
  • 如需处理视频帧,请使用检测器的 results(in:) 同步 API。从 AVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, didOutput:from:) 函数调用此方法,以从给定的视频帧同步获取结果。将 AVCaptureVideoDataOutputalwaysDiscardsLateVideoFrames 保持为 true,以限制对检测器的调用次数。如果在检测器运行时有新的视频帧可用,则会丢弃该帧。
  • 如果您要将检测器的输出作为图形叠加在输入图片上,请先从机器学习套件获取结果,然后在一个步骤中完成图片的呈现和叠加。采用这一方法,每个处理后的输入帧只需在显示表面呈现一次。如需查看示例,请参阅展示示例应用中的 previewOverlayViewMLKDetectionOverlayView 类。

后续步骤