Przewodnik wykrywania twarzy w przypadku Androida

Zadanie MediaPipe Face Detector umożliwia wykrywanie twarzy na obrazie lub w filmie. Za pomocą tego zadania możesz zlokalizować twarze i cechy twarzy w ramce. W tym zadaniu używamy modelu uczenia maszynowego, który działa z pojedynczymi obrazami lub ciągłym strumieniem obrazów. Zadanie zwraca położenie twarzy oraz następujące punkty kluczowe twarzy: lewe oko, prawe oko, czubek nosa, usta, lewy kąt oka i prawy kąt oka.

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

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 usługi Face Detector 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:

  1. Sklonuj repozytorium Git za pomocą tego polecenia:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Opcjonalnie skonfiguruj instancję git do korzystania z funkcji Sparse Checkout, aby mieć tylko pliki przykładowej aplikacji Face Detector:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/face_detector/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

W tych plikach znajduje się kod, który jest kluczowy dla tej przykładowej aplikacji do wykrywania twarzy:

  • FaceDetectorHelper.kt – inicjuje detektor twarzy i obsługuje model oraz wybór delegata.
  • CameraFragment.kt – obsługuje kamerę urządzenia i przetwarza dane wejściowe dotyczące obrazu i wideo.
  • GalleryFragment.kt – współpracuje z OverlayView, aby wyświetlić obraz lub film wyjściowy.
  • OverlayView.kt – implementuje wyświetlanie z ramkami dla wykrytych twarzy.

Konfiguracja

W tej sekcji opisaliśmy kluczowe kroki konfigurowania środowiska programistycznego i projektów kodu w celu używania usługi Face Detector. 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 Wykrywanie 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 Detector wymaga pakietu wytrenowanych modeli, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach usługi Face Detector 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 FaceDetectorHelper.kt:

val modelName = "face_detection_short_range.tflite"
baseOptionsBuilder.setModelAssetPath(modelName)

Tworzenie zadania

Do konfiguracji zadania MediaPipe Face Detector służy funkcja createFromOptions(). Funkcja createFromOptions() akceptuje wartości opcji konfiguracji. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Opcje konfiguracji.

Detektor twarzy obsługuje te typy danych wejściowych: obrazy, pliki wideo i strumienie wideo 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 przeprowadzić wnioskowanie.

Obraz

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

val optionsBuilder =
    FaceDetector.FaceDetectorOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinDetectionConfidence(threshold)
        .setRunningMode(RunningMode.IMAGE)

val options = optionsBuilder.build()

FaceDetector =
    FaceDetector.createFromOptions(context, options)
    

Wideo

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

val optionsBuilder =
    FaceDetector.FaceDetectorOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinDetectionConfidence(threshold)
        .setRunningMode(RunningMode.VIDEO)

val options = optionsBuilder.build()

FaceDetector =
    FaceDetector.createFromOptions(context, options)
    

Transmisja na żywo

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

val optionsBuilder =
    FaceDetector.FaceDetectorOptions.builder()
        .setBaseOptions(baseOptionsBuilder.build())
        .setMinDetectionConfidence(threshold)
        .setResultListener(this::returnLivestreamResult)
        .setErrorListener(this::returnLivestreamError)
        .setRunningMode(RunningMode.LIVE_STREAM)

val options = optionsBuilder.build()

FaceDetector =
    FaceDetector.createFromOptions(context, options)
    

Implementacja przykładowego kodu wykrywacza twarzy umożliwia użytkownikowi przełączanie 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 setupFaceDetector() w pliku FaceDetectorHelper.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
minDetectionConfidence Minimalny wynik ufności, który pozwala uznać wykrywanie twarzy za skuteczne. Float [0,1] 0.5
minSuppressionThreshold Minimalny próg wygaszania niemaksymalizowanego wykrywania twarzy, który ma być traktowany jako nakładanie się. Float [0,1] 0.3
resultListener Gdy detektor twarzy jest w trybie transmisji na żywo, ustawia odbiornik wyników tak, aby otrzymywał wyniki asynchronicznie. Można go używać tylko wtedy, gdy tryb działania ma wartość LIVE_STREAM. N/A Not set
errorListener Ustawia opcjonalny odbiornik błędów. N/A Not set

Przygotuj dane

Funkcja wykrywacza twarzy działa w przypadku obrazów, plików wideo i transmisji wideo 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 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 usługi Face Detector przygotowanie danych jest obsługiwane w pliku FaceDetectorHelper.kt.

Uruchamianie zadania

W zależności od typu danych, z którymi pracujesz, użyj metody faceDetector.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 usługi Face Detector w różnych trybach danych:

Obraz

val result = faceDetector.detect(mpImage)
    

Wideo

val timestampMs = i * inferenceIntervalMs

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

Transmisja na żywo

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

faceDetector.detectAsync(mpImage, frameTime)
    

Pamiętaj:

  • W trybie wideo lub trybie transmisji na żywo zadanie wykrywacza twarzy musi zawierać sygnaturę czasową ramki wejściowej.
  • W trybie obrazu lub filmu zadanie wykrywacza twarzy blokuje bieżący wątek, dopóki nie zakończy przetwarzania obrazu wejściowego lub klatki. Aby uniknąć blokowania interfejsu użytkownika, przeprowadź przetwarzanie w wątku w tle.
  • W trybie transmisji na żywo zadanie wykrywania twarzy zwraca dane natychmiast i nie blokuje bieżącego wątku. Za każdym razem, gdy skończy przetwarzać daną klatkę wejściową, wywoła komponent odbiorczy z wynikiem wykrywania. Jeśli funkcja wykrywania jest wywoływana, gdy zadanie wykrywacza twarzy jest zajęte przetwarzaniem innego kadru, zadanie zignoruje nowy element wejściowy.

W pliku kodu przykładowego wykrywacza twarzy funkcje detect, detectForVideodetectAsync są zdefiniowane w pliku FaceDetectorHelper.kt.

Obsługa i wyświetlanie wyników

Detektor twarzy zwraca obiekt FaceDetectorResult dla każdego przetworzenia wykrywania. Obiekt result zawiera ramki ograniczające wykryte twarze oraz wskaźnik ufności dla każdej z nich.

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

FaceDetectionResult:
  Detections:
    Detection #0:
      BoundingBox:
        origin_x: 126
        origin_y: 100
        width: 463
        height: 463
      Categories:
        Category #0:
          index: 0
          score: 0.9729152917861938
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.18298381567001343
          y: 0.2961040139198303
        NormalizedKeypoint #1:
          x: 0.3302789330482483
          y: 0.29289937019348145
        ... (6 keypoints for each face)
    Detection #1:
      BoundingBox:
        origin_x: 616
        origin_y: 193
        width: 430
        height: 430
      Categories:
        Category #0:
          index: 0
          score: 0.9251380562782288
      NormalizedKeypoints:
        NormalizedKeypoint #0:
          x: 0.6151331663131714
          y: 0.3713381886482239
        NormalizedKeypoint #1:
          x: 0.7460576295852661
          y: 0.38825345039367676
        ... (6 keypoints for each face)

Na ilustracji poniżej widać wynik wykonania zadania:

2 dzieci z ramkami wokół twarzy

Obraz bez ramek ograniczających znajdziesz w oryginalnym pliku graficznym.

Przykładowy kod usługi wykrywania twarzy pokazuje, jak wyświetlać wyniki zwrócone przez zadanie. Więcej informacji znajdziesz w klasie OverlayView.