在 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 專案。ML Kit 支援 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;
  }
}

提高成效的訣竅

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

  • 為了讓 ML Kit 準確偵測姿勢,影像中的人物應有充足的像素資料;為獲得最佳效能,拍攝主體應至少有 256 x 256 像素。
  • 如果您在即時應用程式中偵測姿勢,可能還得考量輸入圖片的整體尺寸。較小的圖片可以更快處理,因此為了縮短延遲時間,請以較低解析度拍攝圖片,但必須遵守上述的解析度規定,並確保主題盡可能佔據圖片比例。
  • 圖片對焦不佳也可能會影響準確度。如果未取得可接受的結果,請要求使用者重新擷取圖片。

如想在即時應用程式中使用姿勢偵測功能,請按照下列指南操作,達成最佳影格速率:

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

後續步驟