在 iOS 上使用機器學習套件偵測姿勢

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

機器學習套件提供兩個經過最佳化的姿勢 SDK。

SDK 名稱姿勢偵測姿勢偵測準確性
實作基礎偵測工具的資產會在建構期間以靜態方式連結至您的應用程式。在建構期間,精準偵測器的資產會靜態連結至您的應用程式。
應用程式大小最大 29.6MB最大 33.2MB
效能iPhone X:約 45 FPSiPhone X:約 29 FPS

立即體驗

事前準備

  1. 在 Podfile 中加入下列機器學習套件 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;
  }
}

改善成效的訣竅

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

  • 為了讓機器學習套件能正確偵測姿勢,圖片中的人應使用足夠的像素資料;為了獲得最佳效能,拍攝目標至少應為 256x256 像素。
  • 如果在即時應用程式中偵測姿勢,建議您考慮輸入圖片的整體尺寸。系統可以更快處理較小的圖片,因此為了縮短延遲時間,請以較低解析度擷取圖片,但請留意前述的解析度規定,並確保拍攝主體盡量呈現圖片。
  • 圖片品質不佳也可能會影響準確率。如果沒有收到可接受的結果,請要求使用者重新拍攝圖片。

如果您想在即時應用程式中使用姿勢偵測,請遵守下列規範,以達到最佳影格速率:

  • 使用基礎 PoseDetection SDK 和 stream 偵測模式。
  • 請考慮以較低的解析度拍照。同時也要注意此 API 圖片尺寸規定。
  • 如要處理影格,請使用偵測工具的 results(in:) 同步 API。從 AVCaptureVideoDataOutputSampleBufferDelegatecaptureOutput(_, doOutput:from:) 函式呼叫此方法,以同步取得指定影片影格的結果。將 AVCaptureVideoDataOutputalwaysDropsLateVideoFrames 保留為 true,以限制對偵測工具的呼叫。假如偵測器在執行期間有新的視訊畫面可用,就會捨棄。
  • 如果您使用偵測工具的輸出內容,為輸入圖片上的圖像重疊,請先透過 ML Kit 取得結果,然後透過單一步驟算繪影像和疊加層。如此一來,每個處理的輸入影格只會轉譯一次到顯示途徑一次。如需範例,請參閱展示範例應用程式的 previewOverlayViewMLKDetectionOverlayView 類別。

後續步驟