iOS 適用的位置地標偵測指南

「Pose 地標」工作可讓你偵測圖片中的人體地標 影片。您可以用這項工作找出主要的身體位置、分析情況 以及分類運動這項工作會使用 像是單張圖片或單一圖片這項工作會輸出圖片中的身體姿勢地標 以及 3D 世界座標。

以下指示將示範如何搭配使用 Pose 地標和 iOS 應用程式。程式碼 您可在 GitHub

如要查看這項工作的實際運作情形,請參閱這個網頁 示範。 進一步瞭解功能、模型和設定選項 請參閱 總覽

程式碼範例

MediaPipe Tasks 程式碼範例是 Pose Lander 的基本實作 App Engine 應用程式此範例使用實體 iOS 裝置上的相機來偵測 偵測連續影片串流中的姿勢這個應用程式也可以偵測 下載這些內容

你可以將這個應用程式做為起點,開始使用 iOS 應用程式,也可以參照這個應用程式 做出決定Pose Lander 範例程式碼 GitHub

下載程式碼

以下說明如何建立範例的本機副本 git 指令列工具編寫程式碼。

如要下載範例程式碼,請按照下列步驟操作:

  1. 使用下列指令複製 git 存放區:

    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. 您也可以設定 Git 執行個體來使用稀疏結帳功能, 只有 Pose 地標 er 範例應用程式的檔案:

    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/pose_landmarker/ios/
    

建立範例程式碼的本機版本後,您可以安裝 MediaPipe 工作程式庫,使用 Xcode 開啟專案,然後執行應用程式。適用對象 操作說明,請參閱 iOS 設定指南

重要元件

以下檔案包含 Pose Lander 範例的重要程式碼 應用程式:

設定

本節說明設定開發環境的重要步驟,以及 程式碼專案使用 Pose 地標 er。如需設定 使用 MediaPipe 工作 (包括平台版本) 的開發環境 規定,請參閱 iOS 設定指南

依附元件

Pose 地標 er 會使用 MediaPipeTasksVision 程式庫 (必須安裝) 開發應用程式這個程式庫同時與 Swift 和 Objective-C 應用程式相容 且不需要額外設定任何特定語言

如需在 macOS 上安裝 CocoaPods 的操作說明,請參閱 CocoaPods 安裝指南。 有關如何建立包含所需 Pod 的 Podfile 的操作說明 請參閱使用 CocoaPods

使用下列程式碼在 Podfile 中新增 MediaPipeTasksVision Pod:

target 'MyPoseLandmarkerApp' do
  use_frameworks!
  pod 'MediaPipeTasksVision'
end

如果您的應用程式包含單元測試目標,請參閱設定指南: iOS,進一步瞭解設定方式 您的 Podfile

型號

MediaPipe Pose Landmarker 需要經過訓練且與 透過這項工作如要進一步瞭解 定位地標,請參閱工作總覽模型 專區

使用 download_models.sh 腳本 下載模型,並使用 Xcode 將模型新增到專案目錄。適用對象 如需將檔案新增至 Xcode 專案的操作說明,請參閱管理檔案 Xcode 中的資料夾和資料夾 專案

使用 BaseOptions.modelAssetPath 屬性指定模型的路徑 。如需程式碼範例,請參閱下一節。

建立工作

您可以呼叫其其中一個初始化器來建立 Pose Materialer 工作。 PoseLandmarker(options:) 初始化器接受設定值 只要設定成「自動重新啟動」 和「在主機維護期間」選項即可

如果你不需要透過自訂設定初始化的 Pose 地標 您可以使用 PoseLandmarker(modelPath:) 初始化器建立 使用預設選項擺動地標人物。進一步瞭解設定 選項,請參閱設定總覽

Pose Marker 工作支援 3 種輸入資料類型:靜態圖片、影片檔案 和即時影像串流根據預設,PoseLandmarker(modelPath:) 會初始化 靜態圖片如要初始化工作以處理影片 檔案或直播影片串流,請使用 PoseLandmarker(options:) 指定影片 或即時串流執行模式使用直播模式時, poseLandmarkerLiveStreamDelegate 設定選項,以便啟用 調整位置標記,將姿勢地標的偵測結果傳送給委派代表 以非同步方式載入物件

選擇與執行中模式對應的分頁,瞭解如何建立工作 然後執行推論

Swift

圖片

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "pose_landmarker",
                                      ofType: "task")

let options = PoseLandmarkerOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .image
options.minPoseDetectionConfidence = minPoseDetectionConfidence
options.minPosePresenceConfidence = minPosePresenceConfidence
options.minTrackingConfidence = minTrackingConfidence
options.numPoses = numPoses

let poseLandmarker = try PoseLandmarker(options: options)
    

影片

import MediaPipeTasksVision

let modelPath = Bundle.main.path(forResource: "pose_landmarker",
                                      ofType: "task")

let options = PoseLandmarkerOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .video
options.minPoseDetectionConfidence = minPoseDetectionConfidence
options.minPosePresenceConfidence = minPosePresenceConfidence
options.minTrackingConfidence = minTrackingConfidence
options.numPoses = numPoses

let poseLandmarker = try PoseLandmarker(options: options)
    

直播

import MediaPipeTasksVision

// Class that conforms to the `PoseLandmarkerLiveStreamDelegate` protocol and
// implements the method that the pose landmarker calls once it finishes
// performing pose landmark detection in each input frame.
class PoseLandmarkerResultProcessor: NSObject, PoseLandmarkerLiveStreamDelegate {

  func poseLandmarker(
    _ poseLandmarker: PoseLandmarker,
    didFinishDetection result: PoseLandmarkerResult?,
    timestampInMilliseconds: Int,
    error: Error?) {

    // Process the pose landmarker result or errors here.

  }
}

let modelPath = Bundle.main.path(forResource: "pose_landmarker",
                                      ofType: "task")

let options = PoseLandmarkerOptions()
options.baseOptions.modelAssetPath = modelPath
options.runningMode = .liveStream
options.minPoseDetectionConfidence = minPoseDetectionConfidence
options.minPosePresenceConfidence = minPosePresenceConfidence
options.minTrackingConfidence = minTrackingConfidence
options.numPoses = numPoses

// Assign an object of the class to the `poseLandmarkerLiveStreamDelegate`
// property.
let processor = PoseLandmarkerResultProcessor()
options.poseLandmarkerLiveStreamDelegate = processor

let poseLandmarker = try PoseLandmarker(options: options)
    

Objective-C

圖片

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"pose_landmarker"
                                                      ofType:@"task"];

MPPPoseLandmarkerOptions *options = [[MPPPoseLandmarkerOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeImage;
options.minPoseDetectionConfidence = minPoseDetectionConfidence;
options.minPosePresenceConfidence = minPosePresenceConfidence;
options.minTrackingConfidence = minTrackingConfidence;
options.numPoses = numPoses;

MPPPoseLandmarker *poseLandmarker =
  [[MPPPoseLandmarker alloc] initWithOptions:options error:nil];
    

影片

@import MediaPipeTasksVision;

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"pose_landmarker"
                                                      ofType:@"task"];

MPPPoseLandmarkerOptions *options = [[MPPPoseLandmarkerOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeVideo;
options.minPoseDetectionConfidence = minPoseDetectionConfidence;
options.minPosePresenceConfidence = minPosePresenceConfidence;
options.minTrackingConfidence = minTrackingConfidence;
options.numPoses = numPoses;

MPPPoseLandmarker *poseLandmarker =
  [[MPPPoseLandmarker alloc] initWithOptions:options error:nil];
    

直播

@import MediaPipeTasksVision;

// Class that conforms to the `MPPPoseLandmarkerLiveStreamDelegate` protocol
// and implements the method that the pose landmarker calls once it finishes
// performing pose landmarks= detection in each input frame.

@interface APPPoseLandmarkerResultProcessor : NSObject 

@end

@implementation APPPoseLandmarkerResultProcessor

-   (void)poseLandmarker:(MPPPoseLandmarker *)poseLandmarker
    didFinishDetectionWithResult:(MPPPoseLandmarkerResult *)poseLandmarkerResult
         timestampInMilliseconds:(NSInteger)timestampInMilliseconds
                           error:(NSError *)error {

    // Process the pose landmarker result or errors here.

}

@end

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"pose_landmarker"
                                                      ofType:@"task"];

MPPPoseLandmarkerOptions *options = [[MPPPoseLandmarkerOptions alloc] init];
options.baseOptions.modelAssetPath = modelPath;
options.runningMode = MPPRunningModeLiveStream;
options.minPoseDetectionConfidence = minPoseDetectionConfidence;
options.minPosePresenceConfidence = minPosePresenceConfidence;
options.minTrackingConfidence = minTrackingConfidence;
options.numPoses = numPoses;

// Assign an object of the class to the `poseLandmarkerLiveStreamDelegate`
// property.
APPPoseLandmarkerResultProcessor *processor =
  [APPPoseLandmarkerResultProcessor new];
options.poseLandmarkerLiveStreamDelegate = processor;

MPPPoseLandmarker *poseLandmarker =
  [[MPPPoseLandmarker alloc] initWithOptions:options error:nil];
    

注意:如果你使用影片模式或直播模式,Pose 地標會使用 避免在每個影格觸發手掌偵測模型 縮短延遲時間

設定選項

這項工作有下列 iOS 應用程式設定選項:

選項名稱 說明 值範圍 預設值
running_mode 設定任務的執行模式。在架構中 模式:

圖片:單一圖片輸入模式。

VIDEO:影片已解碼的影格模式。

LIVE_STREAM:輸入串流模式 擷取的資訊等。 在此模式下,poseLandmarkerLiveStreamDelegate 必須設為 實作 PoseLandmarkerLiveStreamDelegate,以便接收 以非同步方式執行姿勢地標偵測
{RunningMode.image, RunningMode.video, RunningMode.liveStream} RunningMode.image
num_poses 可偵測的姿勢數量上限 擺好姿勢的地標師。 Integer > 0 1
min_pose_detection_confidence 姿勢偵測必須達到的最低可信度分數 。 Float [0.0,1.0] 0.5
min_pose_presence_confidence 擺出姿勢的最低可信度分數 姿勢地標偵測結果的分數 Float [0.0,1.0] 0.5
min_tracking_confidence 姿勢追蹤的最低可信度分數 才算是成功 Float [0.0,1.0] 0.5
output_segmentation_masks Pose 地標 er 是否會為偵測到的警示輸出區隔遮罩 姿勢。 Boolean False
result_callback 設定結果事件監聽器以接收地標結果 以非同步方式顯示參與者 只有在執行模式設為「LIVE_STREAM」時才能使用 ResultListener N/A

直播設定

將跑步模式設為即時串流時,Pose Lander 需要 額外的 poseLandmarkerLiveStreamDelegate 設定選項 讓 Pose 地標 er 傳送姿勢地標的偵測結果 以非同步方式載入物件委派項目必須執行 poseLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) 方法, Pose Lander 會在處理完姿勢的結果後呼叫 每個影格都有地標偵測項目

選項名稱 說明 值範圍 預設值
poseLandmarkerLiveStreamDelegate 使 Pose 地標 er 取得姿勢的跑步結果 在直播模式下非同步進行地標偵測。該類別具有 設為這個屬性必須導入 poseLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) 方法。 不適用 未設定

準備資料

您必須先將輸入圖片或影格轉換為 MPImage 物件。 把它傳給 Pose 地標者MPImage 支援不同類型的 iOS 圖片 並且可在任何執行模式中使用,以便進行推論。如要 關於「MPImage」的資訊,請參閱 MPImage API

根據您的用途和執行模式,選擇 iOS 圖片格式 應用程式需要。MPImage 接受 UIImageCVPixelBufferCMSampleBuffer iOS 圖片格式。

UIImage

UIImage 格式非常適合下列執行模式:

  • 圖片:應用程式套件、使用者圖片庫或檔案系統的圖片,格式為 UIImage 張圖片可轉換成 MPImage 物件。

  • 影片:使用 AVAssetImageGenerator 將影片影格擷取到 CGImage 格式,然後轉換為 UIImage 張圖片。

Swift

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(uiImage: image)
    

Objective-C

// Load an image on the user's device as an iOS `UIImage` object.

// Convert the `UIImage` object to a MediaPipe's Image object having the default
// orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

本範例使用預設值來初始化 MPImage UIImage.Orientation.Up 方向。您可以使用任一支援的任一種初始化 MPImage UIImage.Orientation 輕鬆分配獎金姿勢地標不支援鏡像方向,例如 .upMirrored.downMirrored.leftMirrored.rightMirrored

如要進一步瞭解 UIImage,請參閱 UIImage Apple 開發人員 說明文件

CVPixelBuffer

CVPixelBuffer 格式非常適合會產生影格的應用程式 並使用 iOS CoreImage 處理流程

CVPixelBuffer 格式非常適合下列執行模式:

  • 圖片:應用程式在經過處理後產生 CVPixelBuffer 張圖片 使用 iOS 的 CoreImage 架構,就能傳送給 Pose 地標 執行映像檔執行模式

  • 影片:您可以將影片影格轉換為 CVPixelBuffer 格式 並傳送到 Pose 地標,這時影片模式

  • 直播:系統可能會轉換使用 iOS 相機產生影格的應用程式。 轉換成 CVPixelBuffer 格式進行處理,才能傳送到 在直播模式中擺動地標人物

Swift

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(pixelBuffer: pixelBuffer)
    

Objective-C

// Obtain a CVPixelBuffer.

// Convert the `CVPixelBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithUIImage:image error:nil];
    

如要進一步瞭解 CVPixelBuffer,請參閱 CVPixelBuffer Apple 顯像組件 說明文件

CMSampleBuffer

CMSampleBuffer 格式會儲存統一媒體類型的媒體樣本, 也很適合使用直播模式iOS 攝影機的即時影格 由 iOS 以 CMSampleBuffer 格式非同步提供 AVCaptureVideoDataOutput

Swift

// Obtain a CMSampleBuffer.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the default
// orientation `UIImage.Orientation.up`.
let image = try MPImage(sampleBuffer: sampleBuffer)
    

Objective-C

// Obtain a `CMSampleBuffer`.

// Convert the `CMSampleBuffer` object to a MediaPipe's Image object having the
// default orientation `UIImageOrientationUp`.
MPImage *image = [[MPPImage alloc] initWithSampleBuffer:sampleBuffer error:nil];
    

如要進一步瞭解 CMSampleBuffer,請參閱 CMSampleBuffer Apple 顯像組件 說明文件

執行工作

如要執行 Pose 地標,請使用已指派的 detect() 方法 執行模式:

  • 靜態圖片:detect(image:)
  • 影片:detect(videoFrame:timestampInMilliseconds:)
  • 直播:detectAsync(image:timestampInMilliseconds:)

以下程式碼範例顯示如何在 不同的跑步模式

Swift

圖片

let result = try poseLandmarker.detect(image: image)
    

影片

let result = try poseLandmarker.detect(
  videoFrame: image,
  timestampInMilliseconds: timestamp)
    

直播

try poseLandmarker.detectAsync(
  image: image,
  timestampInMilliseconds: timestamp)
    

Objective-C

圖片

MPPPoseLandmarkerResult *result =
  [poseLandmarker detectImage:image error:nil];
    

影片

MPPPoseLandmarkerResult *result =
  [poseLandmarker detectVideoFrame:image
           timestampInMilliseconds:timestamp
                             error:nil];
    

直播

BOOL success =
  [poseLandmarker detectAsyncImage:image
           timestampInMilliseconds:timestamp
                             error:nil];
    

Pose Marker 程式碼範例說明每種模式的實作方式 詳細說明 detect(image:)detect(videoFrame:timestampInMilliseconds:)detectAsync(image:timestampInMilliseconds:)。範例程式碼允許 使用者可以切換使用系統可能不需要的處理模式 確認是否屬於此情況

注意事項:

  • 以影片模式或直播模式執行時,您必須同時提供 輸入框的時間戳記。

  • 在圖片或影片模式中執行時,「Pose 地標」工作會封鎖 直到完成處理輸入圖片或影格為止。目的地: 為避免封鎖目前的執行緒,請在背景執行處理作業 使用 iOS 的執行緒 調度NSOperation 架構。

  • 在直播模式下執行時,Pose 地標 er 工作會立即傳回 但不會封鎖目前的執行緒該函式會叫用 poseLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) 種方式 處理每個輸入影格後,含有姿勢地標結果 調整地標位置,以非同步方式在專屬的系列中叫用這個方法 調度佇列。為了在使用者介面顯示結果,請調度 結果傳送到主要佇列。如果detectAsync 而 Pose 地標工作正忙於處理其他工作時,會呼叫函式 便忽略新的輸入框

處理及顯示結果

在執行推論時,「Pose 地標 er」工作會傳回 PoseLandmarkerResult 內含每個姿勢地標的座標。

以下範例顯示這項工作的輸出資料範例:

PoseLandmarkerResult:
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : 0.129959
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
      visibility   : 0.999909
      presence     : 0.999958
    ... (33 landmarks per pose)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
      visibility   : 0.9999997615814209
      presence     : 0.9999984502792358
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
      visibility   : 0.999976
      presence     : 0.999998
    ... (33 world landmarks per pose)
  SegmentationMasks:
    ... (pictured below)

輸出結果包含正規化座標 (Landmarks) 和世界 每個地標的座標 (WorldLandmarks)。

輸出結果包含下列正規化座標 (Landmarks):

  • xy:地標座標,由 0.0 和 1.0 正規化 圖片寬度 (x) 和高度 (y)。

  • z:地標深度,月經中點的深度為 來源。值越小,地標越接近相機位置。 z 的規模與 x 幾乎相同。

  • visibility:地標在圖片中可見的可能性。

輸出結果包含下列世界座標 (WorldLandmarks):

  • xyz:實際 3D 座標 (以公尺為單位), 這兩個字的起源

  • visibility:地標在圖片中可見的可能性。

下圖是工作輸出內容的視覺化呈現:

選用的區隔遮罩代表每個像素歸屬的可能性 並提供給偵測到的人下圖是 工作輸出:

「Pose 地標 er」範例程式碼示範如何顯示 Pose 地標 er 也就是預測結果