Przewodnik dotyczący wykrywania punktów orientacyjnych dłoni na Androidzie

Zadanie MediaPipe Ręka umożliwia wykrywanie punktów orientacyjnych rąk na zdjęciu. Te instrukcje pokazują, jak korzystać z rękiego punktu orientacyjnego w aplikacjach na Androida. przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub

Więcej informacji o funkcjach, modelach i opcjach konfiguracji zapoznaj się z Przeglądem.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to prosta implementacja punktu orientacyjnego na Androida. W tym przykładzie użyliśmy aparatu w fizycznym urządzeniu z Androidem, stale wykrywają punkty orientacyjne z ręką, a także wykorzystywać zdjęcia i filmy do statycznego wykrywania punktów orientacyjnych.

Możesz użyć tej aplikacji jako punktu wyjścia dla własnej aplikacji na Androida lub odnieść się do niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod punktu orientacyjnego Ręka jest hostowany na GitHub

Pobieranie kodu

Poniżej znajdziesz instrukcje tworzenia lokalnej kopii przykładu. za pomocą narzędzia wiersza poleceń git.

Aby pobrać przykładowy kod:

  1. Sklonuj repozytorium git za pomocą tego polecenia:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Opcjonalnie możesz skonfigurować instancję git tak, aby wykorzystywała rozproszony proces płatności, masz więc tylko pliki przykładowej aplikacji Hand odsyłacz:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/hand_landmarker/android
    

Po utworzeniu lokalnej wersji przykładowego kodu możesz zaimportować projekt w Android Studio i uruchom aplikację. Instrukcje znajdziesz w Przewodnik po konfiguracji na Androida

Kluczowe elementy

Poniższe pliki zawierają kluczowy kod tego punktu orientacyjnego przykładowa aplikacja do wykrywania:

  • HandLandmarkerHelper.kt – Inicjuje wykrywanie punktów orientacyjnych rąk i obsługuje model oraz przedstawiciela wyboru.
  • MainActivity.kt – Implementuje aplikację, w tym wywołuje funkcję HandLandmarkerHelper.

Konfiguracja

W tej sekcji opisujemy najważniejsze czynności związane z konfigurowaniem środowiska programistycznego oraz w projektach kodu wyłącznie z zastosowaniem punktów orientacyjnych handel. Ogólne informacje na temat: skonfigurować środowisko programistyczne do korzystania z zadań MediaPipe, w tym wymagań wersji platformy, patrz Przewodnik po konfiguracji na Androida

Zależności

Zadanie wyznaczania punktów orientacyjnych korzysta z punktu com.google.mediapipe:tasks-vision bibliotece. Dodaj tę zależność do pliku build.gradle aplikacji na Androida:

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

Model

Zadanie MediaPipe Hand Markuper wymaga wytrenowanego pakietu modeli zgodnego z w tym zadaniu. Aby uzyskać więcej informacji na temat dostępnych wytrenowanych modeli dla punktu orientacyjnego w ręku, zapoznaj się z omówieniem zadania sekcją Modele.

Wybierz i pobierz model oraz zapisz go w katalogu projektu:

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

Określ ścieżkę modelu w parametrze ModelAssetPath. W przykładowy kod model jest zdefiniowany w HandLandmarkerHelper.kt plik:

baseOptionBuilder.setModelAssetPath(MP_HAND_LANDMARKER_TASK)

Tworzenie zadania

Zadanie MediaPipe Hand Pointer używa funkcji createFromOptions() do konfigurowania zadanie. Funkcja createFromOptions() akceptuje wartości konfiguracji . Więcej informacji o opcjach konfiguracji znajdziesz w artykule Opcje konfiguracji:

Ręczny punkt orientacyjny obsługuje 3 typy danych wejściowych: obrazy, pliki wideo transmisji na żywo. Musisz określić tryb działania odpowiadający Twojej typu danych wejściowych podczas tworzenia zadania. Wybierz kartę odpowiadającą typu danych wejściowych, aby zobaczyć, jak utworzyć zadanie i uruchomić wnioskowanie.

Obraz

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)
    

Wideo

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)
    

Transmisja na żywo

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)
    

Przykładowa implementacja kodu punktu orientacyjnego Ręka pozwala użytkownikowi przełączać się między i przetwarzania danych. Takie podejście sprawia, że kod tworzenia zadań jest bardziej skomplikowany, może nie być odpowiednia w Twoim przypadku użycia. Możesz zobaczyć ten kod w setupHandLandmarker() w HandLandmarkerHelper.kt. .

Opcje konfiguracji

To zadanie zawiera te opcje konfiguracji aplikacji na Androida:

Nazwa opcji Opis Zakres wartości Wartość domyślna
runningMode Ustawia tryb działania zadania. Są trzy tryby:

IMAGE: tryb wprowadzania pojedynczego obrazu.

WIDEO: tryb zdekodowanych klatek filmu.

LIVE_STREAM: tryb transmisji danych wejściowych na przykład z kamery. W tym trybie detektor wyników musi mieć wartość wywołano, aby skonfigurować detektor i otrzymywać wyniki asynchronicznie.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
numHands Maksymalna liczba rąk wykrytych przez wykrywacz punktów orientacyjnych „Dłoń”. Any integer > 0 1
minHandDetectionConfidence Minimalny wskaźnik ufności, jaki musi osiągnąć wykrywanie ręki uznane za udane w modelu wykrywania dłoni. 0.0 - 1.0 0.5
minHandPresenceConfidence Minimalny wskaźnik ufności dla wyniku obecności dłoni na ręce model wykrywania punktów orientacyjnych. W trybie wideo i transmisji na żywo jeśli wskaźnik ufności obecności dłoni z modelu punktu orientacyjnego dłoni jest poniżej po osiągnięciu tego progu, aplikacja Ręka odwołuje się do modelu wykrywania dłoni. W przeciwnym razie łatwy algorytm śledzenia dłoni określa lokalizację ręce do późniejszego wykrywania punktu orientacyjnego. 0.0 - 1.0 0.5
minTrackingConfidence Minimalny wskaźnik ufności, z którego można korzystać podczas śledzenia dłoni udało się. Jest to wartość progowa współczynnika podobieństwa między dłońmi bieżącej i ostatniej klatki. W trybie wideo i w trybie strumienia Ręczny punkt orientacyjny, jeśli śledzenie nie powiedzie się, aktywuje punkt orientacyjny ręcznie wykrywaniem zagrożeń. W przeciwnym razie pomija wykrywanie rąk. 0.0 - 1.0 0.5
resultListener Konfiguruje detektor wyników, który otrzymuje wyniki wykrywania asynchronicznie, gdy punkt orientacyjny dłoni jest w trybie transmisji na żywo. Ma zastosowanie tylko wtedy, gdy tryb działania jest ustawiony na LIVE_STREAM Nie dotyczy Nie dotyczy
errorListener Ustawia opcjonalny detektor błędów. Nie dotyczy Nie dotyczy

Przygotuj dane

Hand Pointer obsługuje zdjęcia, pliki wideo i transmisje wideo na żywo. Zadanie obsługuje wstępne przetwarzanie danych wejściowych, w tym zmianę rozmiaru, obrót i wartość ich normalizację.

Ten kod pokazuje, jak przekazywać dane do przetworzenia. Tezy przykłady zawierają szczegółowe instrukcje postępowania z danymi z obrazów, plików wideo i transmisji na żywo strumienie wideo.

Obraz

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

Wideo

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

Transmisja na żywo

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

W Przykładowy kod punktu orientacyjnego rękodzieła. Przygotowanie danych odbywa się w HandLandmarkerHelper.kt .

Uruchamianie zadania

W zależności od typu danych, z którymi pracujesz, skorzystaj z HandLandmarker.detect...(), która jest specyficzna dla tego typu danych. Używaj detect() w przypadku pojedynczych zdjęć, detectForVideo() w przypadku klatek w plikach wideo oraz detectAsync() w przypadku strumieni wideo. Jeśli wykonujesz wykrywanie na wideo, pamiętaj, aby uruchomić wykrywanie w oddzielnym wątku, aby uniknąć blokując wątek interfejsu użytkownika.

Poniższe przykłady kodu pokazują proste przykłady uruchamiania punktu orientacyjnego Ręka w różnych trybach danych:

Obraz

val result = handLandmarker?.detect(mpImage)
    

Wideo

val timestampMs = i * inferenceIntervalMs

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

Transmisja na żywo

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

handLandmarker?.detectAsync(mpImage, frameTime)
    

Pamiętaj:

  • Gdy pracujesz w trybie wideo lub w trybie transmisji na żywo, musisz też podać sygnaturę czasową ramki wejściowej zadania punktu orientacyjnego
  • Podczas pracy w trybie obrazu lub wideo zadanie wskażnik ręcznie zablokuj bieżący wątek do czasu zakończenia przetwarzania obrazu wejściowego lub ramki. Aby uniknąć blokowania interfejsu użytkownika, wykonaj przetwarzanie w w wątku w tle.
  • W trybie transmisji na żywo zadanie punktu orientacyjnego Ręka nie blokuje w bieżącym wątku, ale wraca natychmiast. Wywoła swój wynik detektor z wynikiem wykrywania za każdym razem, gdy zakończy przetwarzanie ramki wejściowej. Jeśli funkcja wykrywania jest wywoływana podczas jest zajęty przetwarzaniem innej ramki, zadanie zignoruje nową ramkę wejściową.

W Przykładowy kod punktu orientacyjnego: detect, detectForVideo i Funkcje detectAsync są zdefiniowane w sekcji HandLandmarkerHelper.kt .

Obsługa i wyświetlanie wyników

Ręka zakreślacza generuje obiekt wynikowy narzędzia do punktów orientacyjnych „ręka” dla każdego wykrycia bieganie. Obiekt wynikowy zawiera punkty orientacyjne we współrzędnych obrazu, ręka punkty orientacyjne we współrzędnych świata i określonej orientacji(lewa/prawa ręka) wykrytego obiektu ręce.

Poniżej znajdziesz przykładowe dane wyjściowe tego zadania:

Dane wyjściowe HandLandmarkerResult zawierają 3 komponenty. Każdy komponent to tablica, w której każdy element zawiera następujące wyniki dla 1 wykrytej ręki:

  • Ręka dominująca

    Ręka wskazuje, czy wykryte ręce są lewe czy prawa.

  • Punkty orientacyjne

    Dostępnych jest 21 punktów orientacyjnych rozmieszczonych na dłoni, a każdy z nich składa się ze współrzędnych x, y i z. Współrzędne x i y są normalizowane do wartości [0,0, 1,0] przez szerokość obrazu i wysokości. Współrzędna z reprezentuje głębokość punktu orientacyjnego, a przy tym jest ich głębia na nadgarstku. Im mniejsza wartość, tym bliższa jest punktem orientacyjnym. z – magnituda ma mniej więcej taką samą skalę jak x

  • Punkty orientacyjne na świecie

    Współrzędne świata przedstawiają również 21 ręcznych punktów orientacyjnych. Każdy punkt orientacyjny składa się z elementów x, y i z, reprezentujących rzeczywiste współrzędne 3D w m, którego punkt początkowy znajduje się w środku geometrycznym dłoni.

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)

Ten obraz przedstawia wizualizację danych wyjściowych zadania:

Przykładowy kod punktu orientacyjnego pokazuje, jak wyświetlać wyników zwróconych przez zadanie, patrz OverlayView klasy, by dowiedzieć się więcej.