在 iOS 上使用 ML Kit 偵測姿勢

ML Kit 提供兩種經過最佳化的 SDK,用於姿勢偵測。

SDK 名稱PoseDetectionPoseDetectionAccurate
導入作業基礎偵測器的資產會在建構時靜態連結至應用程式。準確偵測器資產會在建構時靜態連結至應用程式。
應用程式大小最大 29.6 MB最大 33.2 MB
成效iPhone X:~45FPSiPhone X:約 29 FPS

立即試用

事前準備

  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 後,請使用 xcworkspace 開啟 Xcode 專案。Xcode 13.2.1 以上版本支援 ML Kit。

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

提升成效的訣竅

結果品質取決於輸入圖片的品質:

  • 為確保 ML Kit 能準確偵測姿勢,圖片中的人物應有足夠的像素資料;如要獲得最佳成效,主體應至少為 256x256 像素。
  • 如果您在即時應用程式中偵測姿勢,可能也需要考量輸入圖片的整體尺寸。較小的圖片處理速度較快,因此如要減少延遲,請以較低的解析度拍攝圖片,但請注意上述解析度規定,並確保主體盡可能佔據圖片的大部分。
  • 圖片對焦不佳也會影響準確度。如果結果不符合要求,請要求使用者重新拍攝圖片。

如要在即時應用程式中使用姿勢偵測功能,請按照下列準則操作,以達到最佳影格速率:

  • 使用基礎 PoseDetection SDK 和 stream 偵測模式。
  • 建議您以較低的解析度拍攝圖片。但請注意,這項 API 也有圖片尺寸規定。
  • 如要處理影片影格,請使用偵測器的 results(in:) 同步 API。從 AVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, didOutput:from:) 函式呼叫這個方法,即可從指定的影片影格同步取得結果。將 AVCaptureVideoDataOutputalwaysDiscardsLateVideoFrames 設為 true,即可節流對偵測器的呼叫。如果偵測器執行期間有新的影片影格可用,系統會捨棄該影格。
  • 如果使用偵測器的輸出內容,在輸入圖片上疊加圖像,請先從 ML Kit 取得結果,然後在單一步驟中算繪圖片並疊加圖像。這樣一來,每個處理過的輸入影格只會轉譯到顯示表面一次。如需範例,請參閱展示範例應用程式中的 previewOverlayViewMLKDetectionOverlayView 類別。

後續步驟