Przewodnik wykrywania twarzy w przypadku Androida

Zadanie Wykrywacz twarzy MediaPipe umożliwia wykrywanie twarzy na zdjęciu lub filmie. Dzięki temu możesz zlokalizować twarze w kadrze. To zadanie wykorzystuje model systemów uczących się (ML), który działa z pojedynczymi obrazami lub ciągłym strumieniem obrazów. Zadanie określa lokalizacje twarzy i uwzględnia te najważniejsze punkty: lewe i prawe oko, opuszka nosa, usta, tragie dla lewego oka oraz tragie w prawym oku.

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 artykule Omówienie.

Przykładowy kod

Przykładowy kod aplikacji MediaPipe Tasks to prosta implementacja aplikacji do wykrywania twarzy 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 zdjęciach i filmach z galerii urządzenia.

Możesz użyć aplikacji jako punktu wyjścia dla własnej aplikacji na Androida lub skorzystać z niej podczas jej modyfikowania. Przykładowy kod wykrywacza twarzy 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 do wykrywania twarzy:
    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 na Androida.

Kluczowe elementy

Te pliki zawierają kluczowy kod tej przykładowej aplikacji do wykrywania twarzy:

  • FaceDetectorHelper.kt – inicjuje wykrywanie 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 – w interakcji z interfejsem OverlayView wyświetla obraz wyjściowy lub film.
  • OverlayView.kt – implementuje ekran z ramkami ograniczającymi w przypadku wykrytych twarzy.

Konfiguracja

W tej sekcji opisujemy najważniejsze czynności, jakie należy wykonać, aby skonfigurować środowisko programistyczne i projekty kodu na potrzeby wykrywania twarzy. 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 Wykrywacz 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 wytrenowanego pakietu modeli, który jest z nim zgodny. Więcej informacji o dostępnych wytrenowanych modelach służących do wykrywania twarzy znajdziesz w sekcji poświęconej modelom zadania.

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 FaceDetectorHelper.kt:

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

Tworzenie zadania

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

Wykrywacz 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ą typowi danych wejściowych, aby zobaczyć, jak utworzyć zadanie i uruchomić 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)
    

Przykładowa implementacja kodu do wykrywania twarzy 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 setupFaceDetector() w pliku FaceDetectorHelper.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
minDetectionConfidence Minimalny stopień pewności, że wykrywanie twarzy zostanie uznane za udane. Float [0,1] 0.5
minSuppressionThreshold Minimalny próg niemaksymalnego ograniczenia wykrywania twarzy, który ma być uznawany za nakładający się. Float [0,1] 0.3
resultListener Powoduje, że detektor wyników będzie asynchronicznie otrzymywać wyniki wykrywania, gdy czytnik twarzy działa w trybie transmisji na żywo. Tej opcji można używać tylko wtedy, gdy tryb biegowy jest ustawiony na LIVE_STREAM. N/A Not set
errorListener Ustawia opcjonalny detektor błędów. N/A Not set

Przygotuj dane

Wykrywanie twarzy obsługuje obrazy, pliki wideo i transmisje 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 Wykrywacz twarzy przygotowanie danych odbywa się 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ż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.

Na tych przykładach kodu widać proste przykłady uruchamiania funkcji wykrywania twarzy 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)
    

Uwaga:

  • Gdy urządzenie działa w trybie wideo lub transmisji na żywo, musisz podać sygnaturę czasową klatki wejściowej, aby umożliwić wykrywanie twarzy.
  • W trybie obrazu lub filmu zadanie Wykrywacz twarzy blokuje bieżący wątek, dopóki nie zakończy przetwarzania obrazu wejściowego lub klatki. Aby uniknąć zablokowania interfejsu, przetwarzanie odbywa się w wątku w tle.
  • W trybie transmisji na żywo zadanie Wykrywanie twarzy jest natychmiast zwracane 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. Jeśli funkcja wykrywania zostanie wywołana, gdy zadanie Wykrywacz twarzy jest zajęte przetwarzaniem kolejnej klatki, zignoruje nową ramkę wejściową.

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

Obsługa i wyświetlanie wyników

Czujnik twarzy przy każdym uruchomieniu zwraca obiekt FaceDetectorResult. Wynikowy obiekt zawiera ramki ograniczające dla wykrytych twarzy oraz wskaźnik ufności dla każdej wykrytej twarzy.

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)

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

W przypadku obrazu bez ramek ograniczających wyświetl oryginalny obraz.

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