Zadanie MediaPipe Hand Landmarker umożliwia wykrywanie punktów orientacyjnych dłoni na obrazie. Z tych instrukcji dowiesz się, jak używać Hand Landmarker w aplikacjach na Androida. Przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub.
Więcej informacji o możliwościach, modelach i opcjach konfiguracji związanych z tym zadaniem znajdziesz w sekcji Omówienie.
Przykładowy kod
Przykładowy kod MediaPipe Tasks to prosta implementacja aplikacji Hand Landmarker na Androida. Przykład wykorzystuje kamerę na fizycznym urządzeniu z Androidem do ciągłego wykrywania punktów orientacyjnych dłoni. Można też używać obrazów i filmów z galerii urządzenia do statycznego wykrywania punktów orientacyjnych dłoni.
Możesz użyć tej aplikacji jako punktu wyjścia do utworzenia własnej aplikacji na Androida lub skorzystać z niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod Hand Landmarker jest hostowany na GitHub.
Pobieranie kodu
Z tych instrukcji dowiesz się, jak utworzyć lokalną kopię przykładowego kodu za pomocą narzędzia wiersza poleceń git.
Aby pobrać przykładowy kod:
- Sklonuj repozytorium Git za pomocą tego polecenia:
git clone https://github.com/google-ai-edge/mediapipe-samples
- Opcjonalnie skonfiguruj instancję git, aby używać rzadkiego sprawdzania, dzięki czemu będziesz mieć tylko pliki przykładowej aplikacji Hand Landmarker:
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 do Android Studio i uruchomić aplikację. Instrukcje znajdziesz w przewodniku konfiguracji Androida.
Kluczowe komponenty
Te pliki zawierają kluczowy kod przykładowej aplikacji do wykrywania punktów orientacyjnych dłoni:
- HandLandmarkerHelper.kt – inicjuje wykrywacz punktów orientacyjnych dłoni i obsługuje model oraz wybór delegowany.
- MainActivity.kt – implementuje aplikację, w tym wywołanie
HandLandmarkerHelper
.
Konfiguracja
W tej sekcji opisaliśmy kluczowe kroki konfigurowania środowiska programistycznego i projektów kodu w celu używania narzędzia Hand Landmarker. Ogólne informacje o konfigurowaniu środowiska programistycznego do korzystania z zadań MediaPipe, w tym wymagania dotyczące wersji platformy, znajdziesz w przewodniku konfiguracji na Androida.
Zależności
Zadanie Hand Landmarker korzysta z biblioteki com.google.mediapipe:tasks-vision
. Dodaj tę zależność do pliku build.gradle
aplikacji na Androida:
dependencies {
implementation 'com.google.mediapipe:tasks-vision:latest.release'
}
Model
Zadanie MediaPipe Hand Landmarker wymaga pakietu wytrenowanych modeli, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach usługi Hand Landmarker znajdziesz w sekcji Modele w omówieniu zadania.
Wybierz i pobierz model, a potem zapisz go w katalogu projektu:
<dev-project-root>/src/main/assets
W parametrze ModelAssetPath
podaj ścieżkę do modelu. W przykładowym kodzie model jest zdefiniowany w pliku HandLandmarkerHelper.kt
:
baseOptionBuilder.setModelAssetPath(MP_HAND_LANDMARKER_TASK)
Tworzenie zadania
Do konfiguracji zadania MediaPipe Hand Landmarker służy funkcja createFromOptions()
. Funkcja createFromOptions()
akceptuje wartości opcji konfiguracji. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Opcje konfiguracji.
Narzędzie Hand Landmarker obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i transmisje na żywo. Podczas tworzenia zadania musisz określić tryb działania odpowiadający typowi danych wejściowych. Wybierz kartę odpowiadającą Twojemu typowi danych wejściowych, aby dowiedzieć się, jak utworzyć zadanie i wykonywać 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)
Implementacja przykładowego kodu Hand Landmarker pozwala użytkownikowi przełączać się między trybami przetwarzania. Takie podejście skomplikuje kod tworzący zadanie i może nie być odpowiednie w Twoim przypadku. Ten kod znajdziesz w funkcji setupHandLandmarker()
w pliku HandLandmarkerHelper.kt
.
Opcje konfiguracji
W tym zadaniu dostępne są te opcje konfiguracji aplikacji na Androida:
Nazwa opcji | Opis | Zakres wartości | Wartość domyślna |
---|---|---|---|
runningMode |
Ustawia tryb działania zadania. Dostępne są 3 tryby: OBRAZ: tryb dla pojedynczych obrazów wejściowych. FILM: tryb dekodowanych klatek filmu. LIVE_STREAM: tryb transmisji na żywo danych wejściowych, takich jak dane z kamery. W tym trybie należy wywołać metodę resultListener, aby skonfigurować odbiornik, który będzie asynchronicznie odbierał wyniki. |
{IMAGE, VIDEO, LIVE_STREAM } |
IMAGE |
numHands |
Maksymalna liczba rąk wykrywana przez detektor punktów orientacyjnych dłoni. | Any integer > 0 |
1 |
minHandDetectionConfidence |
Minimalny wynik ufności wykrywania dłoni, który jest uznawany za udany w przypadku modelu wykrywania dłoni. | 0.0 - 1.0 |
0.5 |
minHandPresenceConfidence |
Minimalny wynik ufności dla wyniku obecności ręki w modelu wykrywania punktów orientacyjnych ręki. W trybie wideo i w trybie transmisji na żywo, jeśli wskaźnik ufności obecności ręki z modelu punktów orientacyjnych ręki jest poniżej tego progu, funkcja Hand Landmarker uruchamia model wykrywania dłoni. W przeciwnym razie lekki algorytm śledzenia dłoni określa położenie dłoni na potrzeby wykrywania kolejnych punktów orientacyjnych. | 0.0 - 1.0 |
0.5 |
minTrackingConfidence |
Minimalny wynik ufności śledzenia dłoni, który jest uznawany za udany. To próg współczynnika podobieństwa ramki ograniczającej między dłońmi w bieżącej i ostatniej ramie. W trybie wideo i trybie strumieniowania w Hand Landmarker, jeśli śledzenie się nie powiedzie, Hand Landmarker uruchamia wykrywanie dłoni. W przeciwnym razie pomija wykrywanie dłoni. | 0.0 - 1.0 |
0.5 |
resultListener |
Ustawia odbiornik wyników w celu asynchronicznego otrzymywania wyników wykrywania, gdy punkt odniesienia ręki jest w trybie transmisji na żywo.
Ma zastosowanie tylko wtedy, gdy tryb działania ma wartość LIVE_STREAM |
Nie dotyczy | Nie dotyczy |
errorListener |
Ustawia opcjonalny odbiornik błędów. | Nie dotyczy | Nie dotyczy |
Przygotuj dane
Hand Landmarker działa z obrazami, plikami wideo i transmisjami na żywo. Zadanie to obsługuje wstępną obróbkę danych wejściowych, w tym zmianę rozmiaru, obrót i normalizację wartości.
Poniższy kod pokazuje, jak przekazywać dane do przetwarzania. Te przykłady zawierają szczegółowe informacje o obsługiwaniu danych pochodzących z obrazów, plików wideo i transmisji na żywo.
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ładowym kodzie Hand Landmarker przygotowanie danych jest obsługiwane w pliku HandLandmarkerHelper.kt
.
Uruchamianie zadania
W zależności od typu danych, z którymi pracujesz, użyj metody HandLandmarker.detect...()
odpowiedniej dla tego typu danych. Używaj:
detect()
do pojedynczych obrazów,
detectForVideo()
do klatek w plikach wideo, detectAsync()
do strumieni wideo. Podczas wykrywania treści w strumieniach wideo należy uruchamiać wykrywanie na osobnym wątku, aby nie blokować wątku interfejsu użytkownika.
Poniższe przykłady kodu pokazują proste przykłady uruchamiania modułu Hand Landmarker 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:
- W trybie wideo lub transmisji na żywo musisz też podać zadaniu Hand Landmarker sygnaturę czasową ramki wejściowej.
- Gdy zadanie jest wykonywane w trybie obrazu lub filmu, blokuje bieżący wątek, dopóki nie przetworzy wejściowego obrazu lub klatki. Aby uniknąć blokowania interfejsu użytkownika, przeprowadź przetwarzanie w wątku w tle.
- W trybie transmisji na żywo zadanie Hand Landmarker nie blokuje bieżącego wątku, ale zwraca się natychmiast. Za każdym razem, gdy zakończy przetwarzanie ramki wejściowej, wywoła swojego słuchacza z wynikiem wykrywania. Jeśli funkcja wykrywania jest wywoływana, gdy zadanie Hand Landmarker jest zajęte przetwarzaniem innego kadru, zadanie zignoruje nowy klatka wejściowa.
W pliku kodu przykładowego Hand Landmarker funkcje detect
, detectForVideo
i detectAsync
są zdefiniowane w pliku HandLandmarkerHelper.kt
.
Obsługa i wyświetlanie wyników
W przypadku każdego uruchomienia wykrywania Hand Landmarker generuje obiekt wyników. Obiekt wyniku zawiera punkty odniesienia dłoni w współrzędnych obrazu, punkty odniesienia dłoni w współrzędnych globalnych oraz rękę(lewą lub prawą) wykrytej dłoni.
Poniżej znajdziesz przykład danych wyjściowych z tego zadania:
Dane wyjściowe HandLandmarkerResult
zawierają 3 komponenty. Każdy komponent to tablica, której każdy element zawiera te wyniki dla jednej wykrytej ręki:
Ręka dominująca
Ręka określa, czy wykryta ręka jest lewą czy prawą.
Punkty orientacyjne
Jest 21 punktów orientacyjnych dłoni, z których każdy składa się ze współrzędnych
x
,y
iz
. współrzędnex
iy
są normalizowane do zakresu [0,0, 1,0] odpowiednio według szerokości i wysokości obrazu; Współrzędnaz
reprezentuje głębokość punktu orientacyjnego, przy czym punktem wyjścia jest głębokość na wysokości nadgarstka. Im mniejsza wartość, tym obiektyw jest bliżej zabytku. Wielkośćz
używa mniej więcej tej samej skali cox
.Punkty orientacyjne na świecie
21 punktów orientacyjnych dłoni jest też przedstawionych w współrzędnych światowych. Każdy punkt orientacyjny składa się z wartości
x
,y
iz
, które reprezentują rzeczywiste współrzędne 3D w metrach z początkiem w geometrycznym środku 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)
Na ilustracji poniżej widać wynik wykonania zadania:
Przykładowy kod funkcji Hand Landmarker pokazuje, jak wyświetlać wyniki zwrócone przez zadanie. Więcej informacji znajdziesz w klasie OverlayView
.