Zadanie MediaPipe Hand Pointer umożliwia wykrywanie punktów orientacyjnych dłoni na zdjęciu. Te instrukcje pokazują, jak używać Podręcznego punktu orientacyjnego z aplikacjami 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 tego zadania znajdziesz w sekcji Omówienie.
Przykładowy kod
Przykładowy kod MediaPipe Tasks jest prostą implementacją aplikacji wskaźniki rejonu dłoni na Androida. W tym przykładzie korzystamy z aparatu w fizycznym urządzeniu z Androidem, aby stale wykrywać punkty orientacyjne dłoni, a także wykorzystywać obrazy i filmy z galerii urządzenia do statycznego wykrywania punktów orientacyjnych.
Możesz użyć aplikacji jako punktu wyjścia dla własnej aplikacji na Androida lub odwołać się do niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod obszaru orientacyjnego jest hostowany na GitHub.
Pobieranie kodu
Z instrukcji poniżej 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 tak, aby używała rozproszonego procesu płatności, aby mieć tylko pliki dla przykładowej aplikacji Notatnik ręki:
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 na Androida.
Kluczowe elementy
Te pliki zawierają najważniejszy kod tej przykładowej aplikacji do wykrywania punktów orientacyjnych:
- HandLandmarkerHelper.kt – inicjuje detektor punktu orientacyjnego z dłonią i obsługuje model oraz wybór przedstawicieli.
- MainActivity.kt – implementuje aplikację, umożliwiając wywołanie metody
HandLandmarkerHelper
.
Konfiguracja
W tej sekcji opisujemy najważniejsze czynności, jakie należy wykonać, aby skonfigurować środowisko programistyczne i projekty kodu tak, aby używały tego narzędzia. Ogólne informacje o konfigurowaniu środowiska programistycznego na potrzeby zadań MediaPipe, w tym o wymaganiach dotyczących wersji platformy, znajdziesz w przewodniku konfiguracji na Androida.
Zależności
Zadanie Zakreślacz ręki 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 Pointer wymaga wytrenowanego pakietu modeli, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach dla Wskaźnika ręcznego znajdziesz w omówieniu zadań w sekcji „Modele”.
Wybierz i pobierz model, a następnie zapisz go w katalogu projektu:
<dev-project-root>/src/main/assets
Podaj ścieżkę modelu w parametrze ModelAssetPath
. W przykładowym kodzie model jest zdefiniowany w pliku HandLandmarkerHelper.kt
:
baseOptionBuilder.setModelAssetPath(MP_HAND_LANDMARKER_TASK)
Tworzenie zadania
Zadanie tworzenia punktu orientacyjnego MediaPipe ręcznie konfiguruje to zadanie za pomocą funkcji createFromOptions()
. Funkcja createFromOptions()
akceptuje wartości opcji konfiguracji. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Opcje konfiguracji.
To narzędzie 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ą typowi 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)
Implementacja przykładowego kodu Hand Pointer umożliwia użytkownikowi przełączanie trybów przetwarzania. Takie podejście zwiększa złożoność kodu tworzenia zadania i może nie być odpowiednie w Twoim przypadku. Ten kod znajdziesz w funkcji setupHandLandmarker()
w pliku HandLandmarkerHelper.kt
.
Opcje konfiguracji
To zadanie ma te opcje konfiguracji aplikacji na Androida:
Nazwa opcji | Opis | Zakres wartości | Wartość domyślna |
---|---|---|---|
runningMode |
Ustawia tryb działania zadania. Są 3 tryby: IMAGE: tryb wprowadzania pojedynczych obrazów. WIDEO: tryb dekodowanych klatek filmu. TRANSMISJA NA ŻYWO: tryb transmisji danych wejściowych na żywo, np. z kamery. W tym trybie należy wywołać metodę resultListener, aby skonfigurować odbiornik, który będzie odbierał wyniki asynchronicznie. |
{IMAGE, VIDEO, LIVE_STREAM } |
IMAGE |
numHands |
Maksymalna liczba rąk wykrytych przez detektor punktów orientacyjnych dłoni. | Any integer > 0 |
1 |
minHandDetectionConfidence |
Minimalny stopień pewności, że wykrywanie dłoni zostanie uznane za udane w modelu wykrywania dłoni. | 0.0 - 1.0 |
0.5 |
minHandPresenceConfidence |
Minimalny wskaźnik 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 dla modelu punktu orientacyjnego dłoni jest poniżej tego progu, komponent wskazuje rękę ręcznie uruchamia model wykrywania dłoni. W przeciwnym razie do wykrywania punktów orientacyjnych potrzebny jest uproszczony algorytm śledzenia dłoni. | 0.0 - 1.0 |
0.5 |
minTrackingConfidence |
Minimalny wynik pewności, że śledzenie dłoni zostanie uznane za udane. Jest to próg interfejsu użytkownika w ramce ograniczającej między rękami w bieżącej a ostatniej klatce. W trybie wideo i trybie strumienia Wskaźnika ręcznego, jeśli śledzenie nie powiedzie się, wskazujesz rękę ręcznie. W przeciwnym razie pomijane jest wykrywanie rąk. | 0.0 - 1.0 |
0.5 |
resultListener |
Konfiguruje detektor wyników, aby asynchronicznie otrzymywać wyniki wykrywania, gdy punkt orientacyjny z ręczną ręką działa 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
Aplikacja Hand Pointer obsługuje zdjęcia, pliki wideo oraz transmisje wideo na żywo. To zadanie obsługuje wstępne przetwarzanie danych wejściowych, w tym zmianę rozmiaru, rotację i normalizację wartości.
Poniższy kod pokazuje, jak przekazywać dane do przetwarzania. Obejmują one szczegółowe informacje o sposobie postępowania z danymi z obrazów, plików wideo i strumieni wideo 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 Ręczne narzędzie przygotowanie danych odbywa się 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żyj detect()
w przypadku pojedynczych obrazów, detectForVideo()
– klatek w plikach wideo i detectAsync()
w przypadku strumieni wideo. Podczas wykrywania strumienia wideo pamiętaj o uruchamianiu wykrywania w osobnym wątku, aby uniknąć zablokowania wątku interfejsu.
Poniższe przykłady kodu pokazują proste przykłady uruchamiania punktu orientacyjnego ręcznego 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)
Uwaga:
- W trybie wideo lub w trybie transmisji na żywo musisz też podać znacznik czasu ramki wejściowej w zadaniu Zakreślacz ręki.
- W trybie graficznym lub wideo zadanie Wskażnik dłoni będzie blokować bieżący wątek do momentu zakończenia przetwarzania obrazu wejściowego lub klatki. Aby uniknąć zablokowania interfejsu, przetwarzanie odbywa się w wątku w tle.
- W trybie transmisji na żywo zadanie Oznaczenie ręki nie blokuje bieżącego wątku, ale wraca natychmiast. Wywołuje on detektor wyników z wynikiem wykrywania za każdym razem, gdy zakończy przetwarzanie ramki wejściowej. Jeśli funkcja wykrywania zostanie wywołana, gdy zadanie Mapa witryny jest zajęte przetwarzaniem innej klatki, zignoruje nową ramkę wejściową.
W przykładowym kodzie funkcji
Zielone punkty orientacyjne funkcje detect
, detectForVideo
i detectAsync
są zdefiniowane w pliku HandLandmarkerHelper.kt
.
Obsługa i wyświetlanie wyników
Narzędzie do tworzenia punktów orientacyjnych ręcznie generuje obiekt wynikowy wskaźniku ręcznego dla każdego uruchomienia wykrywania. Otrzymany obiekt zawiera punkty orientacyjne dłoni we współrzędnych zdjęcia, punkty orientacyjne we współrzędnych świata i ręczność(lewa/prawa ręka) wykrytych dłoni.
Poniżej znajdziesz przykład danych wyjściowych z tego zadania:
Dane wyjściowe HandLandmarkerResult
zawierają 3 komponenty. Każdy komponent jest tablicą, w której każdy element zawiera te wyniki dotyczące pojedynczej wykrytej dłoni:
Ręka dominująca
Ręka wskazuje, czy wykryte ręce są lewą czy prawą ręką.
Punkty orientacyjne
Jest 21 punktów orientacyjnych wskazujących dłonie, a każdy z nich składa się ze współrzędnych
x
,y
iz
. Współrzędnex
iy
są normalizowane do wartości [0,0, 1,0] odpowiednio do szerokości i wysokości obrazu. Współrzędnaz
reprezentuje głębokość punktu orientacyjnego, przy czym głębokość na nadgarstku jest punktem początkowym. Im mniejsza wartość, tym zbliża się punkt orientacyjny do aparatu. Siła działaniaz
jest mniej więcej zbliżona do skalix
.Punkty orientacyjne na świecie
We współrzędnych świata są również przedstawione 21 punktów orientacyjnych. Każdy punkt orientacyjny składa się z elementów
x
,y
iz
, które reprezentują rzeczywiste współrzędne 3D w metrach z punktem początkowym 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)
Poniższy obraz przedstawia wizualizację wyników zadania:
Przykładowy kod modułu ręki wskazuje, jak wyświetlać wyniki zwrócone z zadania. Więcej informacji znajdziesz w klasie OverlayView
.