在 iOS 上使用 ML Kit 偵測姿勢

ML Kit 提供兩個針對姿勢偵測所最佳化的 SDK。

SDK 名稱PoseDetectionPoseDetectionAccurate
導入作業基本偵測工具資產會在建構期間以靜態方式連結至您的應用程式。在建構期間,準確偵測工具的素材資源會以靜態方式連結至您的應用程式。
應用程式大小最大 29.6 MB最大 33.2 MB
效能iPhone X:約 45 FPSiPhone X:約 29 FPS

馬上試試

事前準備

  1. 在 Podfile 中加入下列 ML Kit Pod:

    # If you want to use the base implementation:
    pod 'GoogleMLKit/PoseDetection', '3.2.0'
    
    # If you want to use the accurate implementation:
    pod 'GoogleMLKit/PoseDetectionAccurate', '3.2.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 準確偵測姿勢,影像中的人物必須以充足的像素資料表示;為獲得最佳效能,主體至少應為 256 x 256 像素。
  • 如果您在即時應用程式中偵測到姿勢,建議您也考量輸入圖片的整體尺寸。系統可更快處理較小的圖片,因此為了縮短延遲時間,以較低的解析度擷取圖片,但請留意上述解析度要求,並盡可能讓主體佔用大量圖片。
  • 圖像對焦品質不佳也可能會影響準確度。如果您沒有取得可接受的結果,請要求使用者重新拍攝圖片。

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

  • 使用基本 PoseDetection SDK 和 stream 偵測模式。
  • 建議以較低的解析度拍攝圖片。不過,也請留意這個 API 的圖片尺寸規定。
  • 如要處理影片影格,請使用偵測工具的 results(in:) 同步 API。從 AVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, didOutput:from:) 函式中呼叫這個方法,以同步方式取得指定影片影格的結果。將 AVCaptureVideoDataOutputalwaysDiscardsLateVideoFrames 為 true,以限制對偵測工具的呼叫。如果偵測器執行時出現新的影片影格,系統會捨棄影片影格。
  • 如果使用偵測工具的輸出內容在輸入圖像上重疊圖像,請先從 ML Kit 取得結果,然後透過一個步驟算繪圖像和重疊。這樣一來,每個處理的輸入影格都只能轉譯一次到顯示介面一次。如需範例,請參閱展示範例應用程式中的 previewOverlayViewMLKDetectionOverlayView 類別。

後續步驟