Przewodnik wykrywania punktów orientacyjnych twarzy na Androidzie

Zadanie MediaPipe Face Markuper umożliwia wykrywanie punktów orientacyjnych i mimiki twarzy na zdjęciach i filmach. W tym zadaniu możesz rozpoznawać mimikę, stosować filtry i efekty oraz tworzyć wirtualne awatary. To zadanie wykorzystuje modele systemów uczących się, które mogą działać z pojedynczymi obrazami lub ciągłym strumieniem obrazów. Zadanie generuje trójwymiarowe punkty orientacyjne, wyniki mieszania (współczynniki reprezentujące wyraz twarzy), aby w czasie rzeczywistym określić szczegółowe dane o twarzach, oraz macierze przekształceń do wykonywania przekształceń wymaganych do renderowania efektów.

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 aplikacji MediaPipe Tasks to prosta implementacja aplikacji Face pointer na Androida. W tym przykładzie użyto kamery w fizycznym urządzeniu z Androidem do wykrywania twarzy w ciągłym strumieniu wideo. Aplikacja może też wykrywać twarze na obrazach i filmach z galerii urządzenia.

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 aplikacji Face Pointer 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:

  1. Sklonuj repozytorium git za pomocą tego polecenia:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Opcjonalnie skonfiguruj instancję git tak, aby używała rozproszonego procesu płatności, aby mieć tylko pliki dla przykładowej aplikacji Face pointer:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/face_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ą kluczowy kod tej przykładowej aplikacji do oznaczania twarzy:

  • FaceLandmarkerHelper.kt – inicjuje punkt orientacyjny twarzy i obsługuje model oraz wybór przedstawicieli.
  • CameraFragment.kt – obsługuje aparat urządzenia oraz przetwarza wejściowe dane obrazu i filmu.
  • GalleryFragment.kt – wchodzi w interakcję z elementem OverlayView, by wyświetlić obraz lub film wyjściowy.
  • OverlayView.kt – implementuje wyświetlacz z siatką twarzy w przypadku wykrytych twarzy.

Konfiguracja

W tej sekcji opisujemy najważniejsze czynności, jakie należy wykonać, aby skonfigurować środowisko programistyczne i projekty kodu pod kątem użycia funkcji Face Pointer. 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 tworzenia punktów orientacyjnych twarzy 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 Face Pointer wymaga wytrenowanego pakietu modeli, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach dla znacznika twarzy 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 FaceLandmarkerHelper.kt:

baseOptionsBuilder.setModelAssetPath(MP_FACE_LANDMARKER_TASK)

Tworzenie zadania

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

Narzędzie do rozpoznawania twarzy obsługuje następujące typy danych wejściowych: obrazy, pliki wideo i strumienie wideo na żywo. Podczas tworzenia zadania musisz określić tryb działania odpowiadającym typowi danych wejściowych. Wybierz kartę z typem danych wejściowych, aby zobaczyć, jak utworzyć zadanie i uruchomić wnioskowanie.

Obraz

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

val optionsBuilder = 
    FaceLandmarker.FaceLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinFaceDetectionConfidence(minFaceDetectionConfidence)
        .setMinTrackingConfidence(minFaceTrackingConfidence)
        .setMinFacePresenceConfidence(minFacePresenceConfidence)
        .setNumFaces(maxNumFaces)
        .setRunningMode(RunningMode.IMAGE)

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

Wideo

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

val optionsBuilder = 
    FaceLandmarker.FaceLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinFaceDetectionConfidence(minFaceDetectionConfidence)
        .setMinTrackingConfidence(minFaceTrackingConfidence)
        .setMinFacePresenceConfidence(minFacePresenceConfidence)
        .setNumFaces(maxNumFaces)
        .setRunningMode(RunningMode.VIDEO)

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

Transmisja na żywo

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

val optionsBuilder = 
    FaceLandmarker.FaceLandmarkerOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinFaceDetectionConfidence(minFaceDetectionConfidence)
        .setMinTrackingConfidence(minFaceTrackingConfidence)
        .setMinFacePresenceConfidence(minFacePresenceConfidence)
        .setNumFaces(maxNumFaces)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)

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

Implementacja kodu przykładowego funkcji Face Charakterystyczna pozwala użytkownikowi przełączać się między trybami 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 setupFaceLandmarker() w pliku FaceLandmarkerHelper.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
numFaces Maksymalna liczba twarzy, które może wykryć FaceLandmarker. Wygładzanie jest stosowane tylko wtedy, gdy num_faces ma wartość 1. Integer > 0 1
minFaceDetectionConfidence Minimalny stopień pewności, że wykrywanie twarzy zostanie uznane za udane. Float [0.0,1.0] 0.5
minFacePresenceConfidence Minimalny wskaźnik ufności wykrywania obecności twarzy w przypadku wykrywania punktów orientacyjnych twarzy. Float [0.0,1.0] 0.5
minTrackingConfidence Minimalny wynik pewności, że śledzenie twarzy zostanie uznane za udane. Float [0.0,1.0] 0.5
outputFaceBlendshapes Określa, czy kreator twarzy wyświetla kształty twarzy. Do renderowania 3D modelu twarzy używane są kształty mieszania twarzy. Boolean False
outputFacialTransformationMatrixes Określa, czy FaceLandmarker generuje macierz transformacji twarzy. FaceLandmarker wykorzystuje macierz do przekształcania punktów orientacyjnych twarzy z kanonicznego modelu twarzy w wykrytą twarz, dzięki czemu użytkownicy mogą stosować efekty na wykryte punkty orientacyjne. Boolean False
resultListener Ustawia detektor wyników, aby asynchronicznie otrzymywać wyniki dotyczące punktów orientacyjnych, gdy FaceLandmarker jest w trybie transmisji na żywo. Tego ustawienia można używać tylko wtedy, gdy tryb biegowy jest ustawiony na LIVE_STREAM ResultListener N/A
errorListener Ustawia opcjonalny detektor błędów. ErrorListener N/A

Przygotuj dane

Aplikacja Face Director obsługuje zdjęcia, pliki wideo i 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 na temat 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 aplikacji Face Pointer przygotowanie danych odbywa się w pliku FaceLandmarkerHelper.kt.

Uruchamianie zadania

W zależności od typu danych, z którymi pracujesz, użyj metody FaceLandmarker.detect...() odpowiedniej dla tego typu danych. Użyj detect() w przypadku pojedynczych obrazów, detectForVideo() – klatek w plikach wideo, a 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 punktów orientacyjnych twarzy w tych różnych trybach danych:

Obraz

val result = FaceLandmarker.detect(mpImage)
    

Wideo

val timestampMs = i * inferenceIntervalMs

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

Transmisja na żywo

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

FaceLandmarker.detectAsync(mpImage, frameTime)
    

Uwaga:

  • Gdy urządzenie działa w trybie wideo lub w trybie transmisji na żywo, musisz w zadaniu „Oznaczenie twarzy” podać sygnaturę czasową klatki wejściowej.
  • W trybie graficznym lub wideo zadanie Oznaczenie twarzy będzie blokować bieżący wątek, dopóki nie zakończy się przetwarzanie obrazu wejściowego lub klatki. Aby uniknąć zablokowania interfejsu, przetwarzanie odbywa się w wątku w tle.
  • W trybie transmisji na żywo zadanie Oznaczenie twarzy przywraca natychmiast i nie blokuje bieżącego wątku. Wywoła on detektor wyników z wynikiem wykrywania za każdym razem, gdy zakończy przetwarzanie ramki wejściowej.

W przykładowym kodzie znacznika twarzy funkcje detect, detectForVideo i detectAsync są zdefiniowane w pliku FaceLandmarkerHelper.kt.

Obsługa i wyświetlanie wyników

Punkt orientacyjny twarzy zwraca obiekt FaceLandmarkerResult przy każdym uruchomieniu wykrywania. Wynikowy obiekt zawiera siatkę z twarzami dla każdej wykrytej twarzy oraz współrzędne każdego punktu orientacyjnego. Opcjonalnie obiekt w wyniku może zawierać również kształty twarzy oznaczające wyraz twarzy, a także macierze przekształcania twarzy do zastosowania efektów twarzy na wykryte punkty orientacyjne.

Poniżej znajdziesz przykład danych wyjściowych z tego zadania:

FaceLandmarkerResult:
  face_landmarks:
    NormalizedLandmark #0:
      x: 0.5971359014511108
      y: 0.485361784696579
      z: -0.038440968841314316
    NormalizedLandmark #1:
      x: 0.3302789330482483
      y: 0.29289937019348145
      z: -0.09489090740680695
    ... (478 landmarks for each face)
  face_blendshapes:
    browDownLeft: 0.8296722769737244
    browDownRight: 0.8096957206726074
    browInnerUp: 0.00035583582939580083
    browOuterUpLeft: 0.00035752105759456754
    ... (52 blendshapes for each face)
  facial_transformation_matrixes:
    [9.99158978e-01, -1.23036895e-02, 3.91213447e-02, -3.70770246e-01]
    [1.66496094e-02,  9.93480563e-01, -1.12779640e-01, 2.27719707e+01]
    ...

Poniższy obraz przedstawia wizualizację wyników zadania:

Przykładowy kod funkcji rozpoznawania twarzy pokazuje, jak wyświetlać wyniki zwrócone z zadania. Więcej informacji znajdziesz w klasie OverlayView.