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

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

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

Пример кода

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

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

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

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

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

  1. Клонируйте репозиторий git, используя следующую команду:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. При желании настройте свой экземпляр git на использование разреженной проверки, чтобы у вас были только файлы для примера приложения Hand Landmarker:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/hand_landmarker/android
    

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

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

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

  • HandLandmarkerHelper.kt — инициализирует детектор ориентиров рук и обрабатывает выбор модели и делегата.
  • MainActivity.kt — реализует приложение, включая вызов HandLandmarkerHelper .

Настраивать

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

Зависимости

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

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

Модель

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

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

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

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

baseOptionBuilder.setModelAssetPath(MP_HAND_LANDMARKER_TASK)

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

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

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

Изображение

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

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

Видео

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

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

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

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

val optionsBuilder =
    HandLandmarker.HandLandmarkerOptions.builder()
        .setBaseOptions(baseOptions)
        .setMinHandDetectionConfidence(minHandDetectionConfidence)
        .setMinTrackingConfidence(minHandTrackingConfidence)
        .setMinHandPresenceConfidence(minHandPresenceConfidence)
        .setNumHands(maxNumHands)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

handLandmarker =
    HandLandmarker.createFromOptions(context, options)
    

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

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

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

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

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

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

LIVE_STREAM: режим прямой трансляции входных данных, например, с камеры. В этом режиме необходимо вызвать resultListener, чтобы настроить прослушиватель на асинхронное получение результатов.
{ IMAGE, VIDEO, LIVE_STREAM } IMAGE
numHands Максимальное количество рук, обнаруженных детектором ориентиров рук. Any integer > 0 1
minHandDetectionConfidence Минимальный показатель достоверности, позволяющий считать обнаружение рук успешным в модели обнаружения ладоней. 0.0 - 1.0 0.5
minHandPresenceConfidence Минимальная оценка достоверности для оценки присутствия руки в модели обнаружения ориентиров руки. В режиме «Видео» и режиме прямой трансляции, если показатель достоверности присутствия руки из модели ориентира руки ниже этого порога, Hand Landmarker запускает модель обнаружения ладони. В противном случае упрощенный алгоритм отслеживания рук определяет местоположение руки (рук) для последующего обнаружения ориентиров. 0.0 - 1.0 0.5
minTrackingConfidence Минимальный показатель достоверности, позволяющий считать отслеживание рук успешным. Это порог IoU ограничивающей рамки между руками в текущем кадре и последнем кадре. В режиме видео и потоковом режиме Hand Landmarker, если отслеживание не удается, Hand Landmarker запускает обнаружение руки. В противном случае обнаружение руки будет пропущено. 0.0 - 1.0 0.5
resultListener Настраивает прослушиватель результатов на асинхронное получение результатов обнаружения, когда ручной ориентир находится в режиме прямой трансляции. Применимо только в том случае, если для режима работы установлено значение LIVE_STREAM Н/Д Н/Д
errorListener Устанавливает дополнительный прослушиватель ошибок. Н/Д Н/Д

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

Hand 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()
    

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

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

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

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

Изображение

val result = handLandmarker?.detect(mpImage)
    

Видео

val timestampMs = i * inferenceIntervalMs

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

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

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

handLandmarker?.detectAsync(mpImage, frameTime)
    

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

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

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

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

Hand Landmarker генерирует объект результата ручного ориентира для каждого запуска обнаружения. Объект результата содержит ориентиры рук в координатах изображения, ориентиры рук в мировых координатах и ​​направление руки (левая/правая) обнаруженных рук.

Ниже показан пример выходных данных этой задачи:

Выходные данные HandLandmarkerResult содержат три компонента. Каждый компонент представляет собой массив, где каждый элемент содержит следующие результаты для одной обнаруженной руки:

  • Рукава

    Handedness показывает, являются ли обнаруженные руки левыми или правыми.

  • Достопримечательности

    Имеется 21 ручной ориентир, каждый из которых состоит из координат x , y и z . Координаты x и y нормализуются на [0,0, 1,0] по ширине и высоте изображения соответственно. Координата z представляет глубину ориентира, при этом глубина на запястье является началом координат. Чем меньше значение, тем ближе ориентир к камере. Величина z использует примерно тот же масштаб, что и x .

  • Достопримечательности мира

    21 ориентир также представлен в мировых координатах. Каждый ориентир состоит из x , y и z , представляющих реальные трехмерные координаты в метрах с началом координат в геометрическом центре руки.

HandLandmarkerResult:
  Handedness:
    Categories #0:
      index        : 0
      score        : 0.98396
      categoryName : Left
  Landmarks:
    Landmark #0:
      x            : 0.638852
      y            : 0.671197
      z            : -3.41E-7
    Landmark #1:
      x            : 0.634599
      y            : 0.536441
      z            : -0.06984
    ... (21 landmarks for a hand)
  WorldLandmarks:
    Landmark #0:
      x            : 0.067485
      y            : 0.031084
      z            : 0.055223
    Landmark #1:
      x            : 0.063209
      y            : -0.00382
      z            : 0.020920
    ... (21 world landmarks for a hand)

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

Пример кода Hand Landmarker демонстрирует, как отображать результаты, возвращаемые задачей. Дополнительные сведения см. в классе OverlayView .