Przewodnik po wykrywaniu obiektów w Androidzie

Zadanie wykrywania obiektów pozwala wykrywać obecność i lokalizację wielu klas obiektów. Detektor obiektów może na przykład zlokalizować psy w obrazie. Poniżej znajdziesz instrukcje korzystania z zadania Wykrywacz obiektów na Androidzie. Przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub. Możesz zobaczyć, jak działa to zadanie, oglądając tę prezentację internetową. 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 do wykrywania obiektów na Androida. W tym przykładzie użyto kamery na fizycznym urządzeniu z Androidem, aby stale wykrywać obiekty, a także używać obrazów i filmów z galerii urządzenia do ich statycznego wykrywania.

Możesz użyć aplikacji jako punktu wyjścia dla własnej aplikacji na Androida lub skorzystać z niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod detektora obiektów 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 obiektów:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/object_detection/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

Poniższe pliki zawierają najważniejszy kod przykładowej aplikacji do wykrywania obiektów:

Konfiguracja

W tej sekcji opisujemy najważniejsze czynności, jakie należy wykonać, aby skonfigurować środowisko programistyczne i projekty kodu, w których będzie używany detektor obiektów. 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

Detektor obiektów używa biblioteki com.google.mediapipe:tasks-vision. Dodaj tę zależność do pliku build.gradle swojego projektu na Androida. Zaimportuj wymagane zależności za pomocą tego kodu:

dependencies {
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

Model

Zadanie wykrywania obiektów MediaPipe wymaga wytrenowanego modelu, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach dotyczących wykrywania obiektów znajdziesz w sekcji poświęconej modelom – omówieniem zadania.

Wybierz i pobierz model, a następnie zapisz go w katalogu projektu:

<dev-project-root>/src/main/assets

Aby określić ścieżkę używaną przez model, użyj metody BaseOptions.Builder.setModelAssetPath(). Przykładowy kod znajdziesz w następnej sekcji.

Tworzenie zadania

Aby utworzyć zadanie, możesz użyć funkcji createFromOptions. Funkcja createFromOptions akceptuje opcje konfiguracji, w tym tryb działania, język wyświetlanych nazw, maksymalną liczbę wyników, próg ufności, listę dozwolonych kategorii i listę odrzuconych. Jeśli opcja konfiguracji nie zostanie określona, zostanie użyta wartość domyślna. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Omówienie konfiguracji.

Zadanie wykrywania obiektów obsługuje 3 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

ObjectDetectorOptions options =
  ObjectDetectorOptions.builder()
    .setBaseOptions(BaseOptions.builder().setModelAssetPath(‘model.tflite’).build())
    .setRunningMode(RunningMode.IMAGE)
    .setMaxResults(5)
    .build();
objectDetector = ObjectDetector.createFromOptions(context, options);
    

Wideo

ObjectDetectorOptions options =
  ObjectDetectorOptions.builder()
    .setBaseOptions(BaseOptions.builder().setModelAssetPath(‘model.tflite’).build())
    .setRunningMode(RunningMode.VIDEO)
    .setMaxResults(5)
    .build();
objectDetector = ObjectDetector.createFromOptions(context, options);
    

Transmisja na żywo

ObjectDetectorOptions options =
  ObjectDetectorOptions.builder()
    .setBaseOptions(BaseOptions.builder().setModelAssetPath(‘model.tflite’).build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setMaxResults(5)
    .setResultListener((result, inputImage) -> {
      // Process the detection result here.
    })
    .setErrorListener((result, inputImage) -> {
      // Process the classification errors here.
    })
   .build();
objectDetector = ObjectDetector.createFromOptions(context, options);
    

Przykładowa implementacja kodu do wykrywania obiektów 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 setupObjectDetector() klasy ObjectDetectorHelper.

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
displayNamesLocales Ustawia język etykiet, które mają być używane w przypadku nazw wyświetlanych w metadanych modelu zadania (jeśli są dostępne). Wartość domyślna w języku angielskim to en. Za pomocą TensorFlow Lite MetadataWriter API możesz dodawać zlokalizowane etykiety do metadanych modelu niestandardowego. Kod języka en
maxResults Określa opcjonalną maksymalną liczbę wyników wykrywania o najwyższych wynikach do zwrócenia. Dowolne liczby dodatnie -1 (zwracane są wszystkie wyniki)
scoreThreshold Ustawia próg wyniku prognozy, który zastępuje próg podany w metadanych modelu (jeśli istnieją). Wyniki poniżej tej wartości zostały odrzucone. Dowolna liczba zmiennoprzecinkowa Nie ustawiono
categoryAllowlist Ustawia opcjonalną listę dozwolonych nazw kategorii. Jeśli pole nie jest puste, wyniki wykrywania, których nazwy kategorii nie ma w tym zbiorze, zostaną odfiltrowane. Zduplikowane i nieznane nazwy kategorii są ignorowane. Ta opcja wzajemnie się wyklucza, categoryDenylist i ich użycie kończy się błędem. Dowolne ciągi Nie ustawiono
categoryDenylist Ustawia opcjonalną listę niedozwolonych nazw kategorii. Jeśli pole nie jest puste, wyniki wykrywania, których nazwa kategorii znajduje się w tym zbiorze, zostaną odfiltrowane. Zduplikowane i nieznane nazwy kategorii są ignorowane. Ta opcja wzajemnie się wyklucza z categoryAllowlist, a korzystanie z obu daje błąd. Dowolne ciągi Nie ustawiono
resultListener Konfiguruje detektor wyników, aby asynchronicznie otrzymywać wyniki wykrywania, gdy detektor obiektów działa w trybie transmisji na żywo. Możesz użyć tej opcji tylko wtedy, gdy ustawisz tryb biegania na LIVE_STREAM. Nie dotyczy Nie ustawiono

Przygotuj dane

Zanim prześlesz obraz lub ramkę do wykrywania obiektów, musisz przekonwertować go na obiekt com.google.mediapipe.framework.image.MPImage.

Poniższe przykłady wyjaśniają i pokazują, jak przygotować dane do przetwarzania w przypadku każdego z dostępnych typów danych:

Obraz

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load an image on the user’s device as a Bitmap object using BitmapFactory.

// Convert an Android’s Bitmap object to a MediaPipe’s Image object.
Image mpImage = new BitmapImageBuilder(bitmap).build();
    

Wideo

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load a video file on the user's device using MediaMetadataRetriever

// From the video’s metadata, load the METADATA_KEY_DURATION and
// METADATA_KEY_VIDEO_FRAME_COUNT values. Use these values
// to calculate the timestamp of each frame later.

// Loop through the video and load each frame as a Bitmap object.

// Convert the Android’s Bitmap object to a MediaPipe’s Image object.
Image mpImage = new BitmapImageBuilder(frame).build();
    

Transmisja na żywo

import com.google.mediapipe.framework.image.MediaImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Create a CameraX’s ImageAnalysis to continuously receive frames
// from the device’s camera. Configure it to output frames in RGBA_8888
// format to match with what is required by the model.

// For each Android’s ImageProxy object received from the ImageAnalysis,
// extract the encapsulated Android’s Image object and convert it to
// a MediaPipe’s Image object.
android.media.Image mediaImage = imageProxy.getImage()
MPImage mpImage = new MediaImageBuilder(mediaImage).build();
    

W przykładowym kodzie detektora obiektów przygotowanie danych jest przeprowadzane w klasie ObjectDetectorHelper w funkcjach detectImage(), detectVideoFile() i detectLivestreamFrame().

Uruchamianie zadania

W zależności od typu danych, z którymi pracujesz, użyj metody ObjectDetector.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 detektora obiektów w różnych trybach danych:

Obraz

ObjectDetectorResult detectionResult = objectDetector.detect(image);
    

Wideo

// Calculate the timestamp in milliseconds of the current frame.
long frame_timestamp_ms = 1000 * video_duration * frame_index / frame_count;

// Run inference on the frame.
ObjectDetectorResult detectionResult =
    objectDetector.detectForVideo(image, frameTimestampMs);
    

Transmisja na żywo

// Run inference on the frame. The detection results will be available
// via the `resultListener` provided in the `ObjectDetectorOptions` when
// the object detector was created.
objectDetector.detectAsync(image, frameTimestampMs);
    

W przykładowym kodzie detektora obiektów znajdziesz bardziej szczegółowe opisy każdego z tych trybów: detect(), detectVideoFile() i detectAsync(). Przykładowy kod pozwala użytkownikowi przełączać się między trybami przetwarzania, które mogą nie być wymagane w Twoim przypadku.

Uwaga:

  • Gdy działasz w trybie wideo lub w trybie transmisji na żywo, musisz też podać sygnaturę czasową klatki wejściowej do zadania wykrywania obiektów.
  • W trybie obrazu lub wideo zadanie wykrywania obiektów zablokuje bieżący wątek do momentu zakończenia przetwarzania obrazu wejściowego lub klatki. Aby uniknąć zablokowania bieżącego wątku, wykonaj przetwarzanie w wątku w tle.
  • W trybie transmisji na żywo zadanie Wykrywacz obiektów nie blokuje bieżącego wątku, ale zwraca je 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 wykrywania obiektów jest zajęte przetwarzaniem innej ramki, nowa ramka wejściowa zostanie zignorowana.

Obsługa i wyświetlanie wyników

Po uruchomieniu wnioskowania zadanie wykrywania obiektów zwraca obiekt ObjectDetectorResult, który opisuje obiekty znalezione na obrazie wejściowym.

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

ObjectDetectorResult:
 Detection #0:
  Box: (x: 355, y: 133, w: 190, h: 206)
  Categories:
   index       : 17
   score       : 0.73828
   class name  : dog
 Detection #1:
  Box: (x: 103, y: 15, w: 138, h: 369)
  Categories:
   index       : 17
   score       : 0.73047
   class name  : dog

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

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