Руководство по обнаружению ориентиров позы для iOS

Задача Pose Landmarker позволяет обнаруживать ориентиры человеческих тел на изображении или видео. Вы можете использовать это задание для определения ключевых положений тела, анализа позы и классификации движений. В этой задаче используются модели машинного обучения (ML), которые работают с отдельными изображениями или видео. Задача выводит ориентиры позы тела в координатах изображения и в трехмерных мировых координатах.

В этих инструкциях показано, как использовать Pose Landmarker с приложениями для iOS. Пример кода, описанный в этой инструкции, доступен на GitHub .

Вы можете увидеть эту задачу в действии, просмотрев эту веб-демо . Дополнительные сведения о возможностях, моделях и параметрах конфигурации этой задачи см. в разделе Обзор .

Пример кода

Пример кода задач MediaPipe — это базовая реализация приложения Pose Landmarker для iOS. В примере используется камера на физическом устройстве iOS для обнаружения поз в непрерывном видеопотоке. Приложение также может определять позы на изображениях и видео из галереи устройства.

Вы можете использовать это приложение в качестве отправной точки для своего собственного приложения для iOS или обращаться к нему при изменении существующего приложения. Пример кода Pose Landmarker размещен на GitHub .

Загрузите код

Следующие инструкции показывают, как создать локальную копию кода примера с помощью инструмента командной строки git .

Чтобы загрузить пример кода:

  1. Клонируйте репозиторий git, используя следующую команду:

    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. При желании настройте свой экземпляр git на использование разреженной проверки, чтобы у вас были только файлы для примера приложения Pose Landmarker:

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

После создания локальной версии примера кода вы можете установить библиотеку задач MediaPipe, открыть проект с помощью Xcode и запустить приложение. Инструкции см. в Руководстве по установке для iOS .

Ключевые компоненты

Следующие файлы содержат ключевой код для примера приложения Pose Landmarker:

  • PoseLandmarkerService.swift : инициализирует ориентир, обрабатывает выбор модели и выполняет вывод на основе входных данных.
  • CameraViewController : реализует пользовательский интерфейс для режима ввода изображения с камеры в реальном времени и визуализирует ориентиры.
  • MediaLibraryViewController.swift : реализует пользовательский интерфейс для режима ввода неподвижных изображений и видеофайлов и визуализирует ориентиры.

Настраивать

В этом разделе описаны ключевые шаги по настройке среды разработки и проектов кода для использования Pose Landmarker. Общие сведения о настройке среды разработки для использования задач MediaPipe, включая требования к версии платформы, см. в руководстве по настройке для iOS .

Зависимости

Pose Landmarker использует библиотеку MediaPipeTasksVision , которую необходимо установить с помощью CocoaPods. Библиотека совместима с приложениями Swift и Objective-C и не требует дополнительной настройки для конкретного языка.

Инструкции по установке CocoaPods на macOS см. в руководстве по установке CocoaPods . Инструкции о том, как создать Podfile с необходимыми модулями для вашего приложения, см. в разделе Использование CocoaPods .

Добавьте модуль MediaPipeTasksVision в Podfile используя следующий код:

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

Если ваше приложение включает в себя цели модульного тестирования, обратитесь к Руководству по настройке для iOS для получения дополнительной информации о настройке вашего Podfile .

Модель

Для задачи MediaPipe Pose Landmarker требуется обученный пакет, совместимый с этой задачей. Дополнительную информацию о доступных обученных моделях для Pose Landmarker см. в разделе «Модели» обзора задач.

Используйте сценарий download_models.sh , чтобы загрузить модели и добавить их в каталог проекта с помощью Xcode. Инструкции по добавлению файлов в проект Xcode см. в разделе Управление файлами и папками в проекте Xcode .

Используйте свойство BaseOptions.modelAssetPath , чтобы указать путь к модели в вашем пакете приложений. Пример кода см. в следующем разделе.

Создать задачу

Вы можете создать задачу Pose Landmarker, вызвав один из ее инициализаторов. Инициализатор PoseLandmarker(options:) принимает значения для параметров конфигурации.

Если вам не нужен ориентир Pose Landmarker, инициализированный с настраиваемыми параметрами конфигурации, вы можете использовать инициализатор PoseLandmarker(modelPath:) для создания ориентира Pose с параметрами по умолчанию. Дополнительные сведения о параметрах конфигурации см. в разделе Обзор конфигурации .

Задача Pose Landmarker поддерживает 3 типа входных данных: неподвижные изображения, видеофайлы и прямые видеопотоки. По умолчанию PoseLandmarker(modelPath:) инициализирует задачу для неподвижных изображений. Если вы хотите, чтобы ваша задача была инициализирована для обработки видеофайлов или прямых видеопотоков, используйте PoseLandmarker(options:) , чтобы указать режим работы видео или прямой трансляции. Для режима прямой трансляции также требуется дополнительный параметр poseLandmarkerLiveStreamDelegate , который позволяет Pose Landmarker асинхронно доставлять делегату результаты обнаружения ориентиров позы.

Выберите вкладку, соответствующую вашему режиму работы, чтобы узнать, как создать задачу и выполнить вывод.

Быстрый

Изображение

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)
    

Цель-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 Landmarker использует отслеживание, чтобы избежать запуска модели обнаружения ладоней в каждом кадре, что помогает уменьшить задержку.

Варианты конфигурации

Эта задача имеет следующие параметры конфигурации для приложений iOS:

Название опции Описание Диапазон значений Значение по умолчанию
running_mode Устанавливает режим выполнения задачи. Есть три режима:

ИЗОБРАЖЕНИЕ: Режим для ввода одного изображения.

ВИДЕО: Режим декодированных кадров видео.

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 Landmarker маску сегментации для обнаруженной позы. Boolean False
result_callback Настраивает прослушиватель результатов на асинхронное получение результатов ориентира, когда Pose Landmarker находится в режиме прямой трансляции. Может использоваться только в том случае, если для режима работы установлено значение LIVE_STREAM ResultListener N/A

Конфигурация прямой трансляции

Когда режим бега установлен на прямую трансляцию, для Pose Landmarker требуется дополнительный параметр poseLandmarkerLiveStreamDelegate , который позволяет Pose Landmarker асинхронно доставлять результаты обнаружения ориентиров позы. Делегат должен реализовать poseLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) , который вызывается Pose Landmarker после обработки результатов обнаружения ориентиров позы в каждом кадре.

Название опции Описание Диапазон значений Значение по умолчанию
poseLandmarkerLiveStreamDelegate Позволяет Pose Landmarker получать результаты асинхронного обнаружения ориентиров позы в режиме прямой трансляции. Класс, экземпляру которого присвоено это свойство, должен реализовать poseLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) . Непригодный Не установлено

Подготовьте данные

Вам необходимо преобразовать входное изображение или кадр в объект MPImage , прежде чем передавать его в Pose Landmarker. MPImage поддерживает различные типы форматов изображений iOS и может использовать их в любом рабочем режиме для вывода. Для получения дополнительной информации о MPImage обратитесь к MPImage API .

Выберите формат изображения iOS в зависимости от вашего варианта использования и режима работы, который требуется вашему приложению. MPImage принимает форматы изображений iOS UIImage , CVPixelBuffer и CMSampleBuffer .

UIImage

Формат UIImage хорошо подходит для следующих режимов работы:

  • Изображения: изображения из пакета приложения, пользовательской галереи или файловой системы, отформатированные как изображения UIImage можно преобразовать в объект MPImage .

  • Видео: используйте AVAssetImageGenerator для извлечения видеокадров в формат CGImage , а затем преобразуйте их в изображения UIImage .

Быстрый

// 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)
    

Цель-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 . Pose Landmarker не поддерживает зеркальные ориентации, такие как .upMirrored , .downMirrored , .leftMirrored , .rightMirrored .

Для получения дополнительной информации о UIImage обратитесь к документации UIImage Apple Developer Documentation .

CVPixelBuffer

Формат CVPixelBuffer хорошо подходит для приложений, генерирующих кадры и использующих для обработки платформу iOS CoreImage .

Формат CVPixelBuffer хорошо подходит для следующих режимов работы:

  • Изображения: приложения, которые генерируют изображения CVPixelBuffer после некоторой обработки с использованием платформы iOS CoreImage , могут быть отправлены в Pose Landmarker в режиме работы изображения.

  • Видео: видеокадры можно конвертировать в формат CVPixelBuffer для обработки, а затем отправлять в Pose Landmarker в видеорежиме.

  • прямая трансляция: приложения, использующие камеру iOS для создания кадров, могут быть преобразованы в формат CVPixelBuffer для обработки перед отправкой в ​​Pose Landmarker в режиме прямой трансляции.

Быстрый

// 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)
    

Цель-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 см. в документации разработчика Apple CVPixelBuffer .

CMSampleBuffer

Формат CMSampleBuffer хранит образцы мультимедиа единого типа и хорошо подходит для режима прямой трансляции. Живые кадры с камер iOS асинхронно доставляются в формате CMSampleBuffer с помощью iOS AVCaptureVideoDataOutput .

Быстрый

// 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)
    

Цель-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 для разработчиков .

Запустить задачу

Чтобы запустить ориентир позы, используйте метод detect() специфичный для назначенного режима бега:

  • Неподвижное изображение: detect(image:)
  • Видео: detect(videoFrame:timestampInMilliseconds:)
  • Прямая трансляция: detectAsync(image:timestampInMilliseconds:)

В следующих примерах кода показаны простые примеры запуска Pose Landmarker в различных режимах работы:

Быстрый

Изображение

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

Видео

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

Прямая трансляция

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

Цель-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 Landmarker более detect(image:) показаны реализации каждого из detectAsync(image:timestampInMilliseconds:) режимов detect(videoFrame:timestampInMilliseconds:) Пример кода позволяет пользователю переключаться между режимами обработки, которые могут не потребоваться для вашего варианта использования.

Обратите внимание на следующее:

  • При работе в режиме видео или в режиме прямой трансляции вы также должны предоставить метку времени входного кадра для задачи Pose Landmarker.

  • При работе в режиме изображения или видео задача Pose Landmarker блокирует текущий поток до тех пор, пока не завершит обработку входного изображения или кадра. Чтобы избежать блокировки текущего потока, выполните обработку в фоновом потоке с помощью платформ iOS Dispatch или NSOperation .

  • При работе в режиме прямой трансляции задача Pose Landmarker немедленно возвращается и не блокирует текущий поток. Он вызывает poseLandmarker(_:didFinishDetection:timestampInMilliseconds:error:) с результатом определения ориентира позы после обработки каждого входного кадра. Pose Landmarker вызывает этот метод асинхронно в выделенной последовательной очереди отправки. Для отображения результатов в пользовательском интерфейсе отправьте результаты в основную очередь после обработки результатов. Если функция detectAsync вызывается, когда задача Pose Landmarker занята обработкой другого кадра, Pose Landmarker игнорирует новый входной кадр.

Обработка и отображение результатов

После выполнения вывода задача Pose Landmarker возвращает 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 ):

  • x и y : координаты ориентира, нормированные между 0,0 и 1,0 по ширине изображения ( x ) и высоте ( y ).

  • z : Глубина ориентира, в качестве исходной точки используется глубина в середине бедер. Чем меньше значение, тем ближе ориентир к камере. Величина z использует примерно тот же масштаб, что и x .

  • visibility : вероятность того, что ориентир будет виден на изображении.

Вывод содержит следующие мировые координаты ( WorldLandmarks ):

  • x , y и z : Реальные трехмерные координаты в метрах, в качестве начала координат используется середина бедер.

  • visibility : вероятность того, что ориентир будет виден на изображении.

На следующем изображении показана визуализация результатов задачи:

Дополнительная маска сегментации представляет вероятность того, что каждый пиксель принадлежит обнаруженному человеку. Следующее изображение представляет собой маску сегментации выходных данных задачи:

Пример кода Pose Landmarker демонстрирует, как отображать результаты Pose Landmarker.