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

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

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

Пример кода

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

Вы можете использовать это приложение в качестве отправной точки для своего собственного приложения для Android или обращаться к нему при изменении существующего приложения. Пример кода 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/android
    

После создания локальной версии кода примера вы можете импортировать проект в Android Studio и запустить приложение. Инструкции см. в Руководстве по установке для Android .

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

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

  • PoseLandmarkerHelper.kt — инициализирует ориентир позы и обрабатывает выбор модели и делегата.
  • CameraFragment.kt — управляет камерой устройства и обрабатывает входные данные изображения и видео.
  • GalleryFragment.kt — взаимодействует с OverlayView для отображения выходного изображения или видео.
  • OverlayView.kt — реализует отображение обнаруженных поз.

Настраивать

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

Зависимости

Задача Pose Landmarker использует библиотеку com.google.mediapipe:tasks-vision . Добавьте эту зависимость в файл build.gradle вашего приложения Android:

dependencies {
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

Модель

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

Выберите и загрузите модель и сохраните ее в каталоге вашего проекта:

<dev-project-root>/src/main/assets

Укажите путь к модели в параметре ModelAssetPath . В примере кода модель определена в файле PoseLandmarkerHelper.kt :

val modelName = "pose_landmarker_lite.task"
baseOptionsBuilder.setModelAssetPath(modelName)

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

Задача MediaPipe Pose Landmarker использует функцию createFromOptions() для настройки задачи. Функция createFromOptions() принимает значения параметров конфигурации. Дополнительные сведения о параметрах конфигурации см. в разделе Параметры конфигурации .

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

Изображение

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(modelName)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()
poseLandmarker = poseLandmarker.createFromOptions(context, options)
    

Видео

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(modelName)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()
poseLandmarker = poseLandmarker.createFromOptions(context, options)
    

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

val baseOptionsBuilder = BaseOptions.builder().setModelAssetPath(modelName)
val baseOptions = baseOptionBuilder.build()

val optionsBuilder = 
    poseLandmarker.poseLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinPoseDetectionConfidence(minPoseDetectionConfidence)
        .setMinTrackingConfidence(minPoseTrackingConfidence)
        .setMinPosePresenceConfidence(minposePresenceConfidence)
        .setNumPoses(maxNumPoses)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)

val options = optionsBuilder.build()
poseLandmarker = poseLandmarker.createFromOptions(context, options)
    

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

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

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

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

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

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

LIVE_STREAM: режим прямой трансляции входных данных, например с камеры. В этом режиме необходимо вызвать resultListener, чтобы настроить прослушиватель на асинхронное получение результатов.
{ IMAGE, VIDEO, LIVE_STREAM } IMAGE
numposes Максимальное количество поз, которые может обнаружить ориентир позы. Integer > 0 1
minPoseDetectionConfidence Минимальный показатель достоверности, позволяющий считать обнаружение позы успешным. Float [0.0,1.0] 0.5
minPosePresenceConfidence Минимальный показатель достоверности оценки присутствия позы при обнаружении ориентира позы. Float [0.0,1.0] 0.5
minTrackingConfidence Минимальный показатель достоверности, позволяющий отслеживанию позы считаться успешным. Float [0.0,1.0] 0.5
outputSegmentationMasks Выводит ли Pose Landmarker маску сегментации для обнаруженной позы. Boolean False
resultListener Настраивает прослушиватель результатов на асинхронное получение результатов ориентира, когда Pose Landmarker находится в режиме прямой трансляции. Может использоваться только в том случае, если для режима работы установлено значение LIVE_STREAM ResultListener N/A
errorListener Устанавливает дополнительный прослушиватель ошибок. ErrorListener N/A

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

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

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

Изображение

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(image).build()
    

Видео

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

val argb8888Frame =
    if (frame.config == Bitmap.Config.ARGB_8888) frame
    else frame.copy(Bitmap.Config.ARGB_8888, false)

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(argb8888Frame).build()
    

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

import com.google.mediapipe.framework.image.BitmapImageBuilder
import com.google.mediapipe.framework.image.MPImage

// Convert the input Bitmap object to an MPImage object to run inference
val mpImage = BitmapImageBuilder(rotatedBitmap).build()
    

В примере кода Pose Landmarker подготовка данных выполняется в файле PoseLandmarkerHelper.kt .

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

В зависимости от типа данных, с которыми вы работаете, используйте poseLandmarker.detect...() , специфичный для этого типа данных. Используйте detect() для отдельных изображений, detectForVideo() для кадров в видеофайлах и detectAsync() для видеопотоков. Когда вы выполняете обнаружения в видеопотоке, убедитесь, что вы запускаете обнаружения в отдельном потоке, чтобы избежать блокировки потока ввода пользователя.

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

Изображение

val result = poseLandmarker.detect(mpImage)
    

Видео

val timestampMs = i * inferenceIntervalMs

poseLandmarker.detectForVideo(mpImage, timestampMs)
    .let { detectionResult ->
        resultList.add(detectionResult)
    }
    

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

val mpImage = BitmapImageBuilder(rotatedBitmap).build()
val frameTime = SystemClock.uptimeMillis()

poseLandmarker.detectAsync(mpImage, frameTime)
    

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

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

В примере кода Pose Landmarker функции detect , detectForVideo и detectAsync определены в файле PoseLandmarkerHelper.kt .

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

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