在 iOS 上使用 ML Kit 偵測姿勢

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

SDK 名稱PoseDetectionPoseDetectionion 準確性
實作中基本偵測工具的資產會在建構期間以靜態方式連結至您的應用程式。準確偵測器的資產會在建構期間以靜態方式連結至您的應用程式。
應用程式大小最大 29.6 MB最大 33.2 MB
成效iPhone X:約 45 個影格iPhone 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
姿勢偵測器會偵測一個人,然後執行姿勢偵測。系統會針對每張圖片執行人為偵測步驟,因此延遲時間會較長,且不會追蹤個別使用者。對靜態圖片使用姿勢偵測時,請使用這個模式。

指定 pose 偵測工具選項:

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(_, hadOutput:from:) 函式呼叫此方法,以同步取得指定影片畫面的結果。將 AVCaptureVideoDataOutputalways 捨棄 sLateVideoFrames 保持為 true,藉此限制對偵測工具的呼叫。如果偵測工具執行期間有新的影片畫面,就會立即捨棄。
  • 如果您使用偵測工具的輸出內容在輸入圖像上疊加圖片,請先透過 ML Kit 取得結果,然後在單一步驟中顯示圖片和疊加層。如此一來,每個處理的輸入影格在顯示途徑中只會算一次。如需範例,請參閱展示範例應用程式的 previewOverlayViewMLKDetectionOverlayView 類別。

後續步驟