在 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. 準備輸入圖片

如要偵測姿勢,請對每個影像或影格執行下列步驟。 如果啟用串流模式,就必須從以下位置建立 VisionImage 物件: CMSampleBuffer 秒。

使用 UIImageVisionImage CMSampleBuffer

如果您使用 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;
      }
    }
          
  • 使用VisionImage CMSampleBuffer 物件和方向:

    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 例如,在展示範例應用程式中使用類別。

後續步驟