Przewodnik umieszczania obrazów w przypadku Androida

Zadanie MediaPipe Image Embedder umożliwia konwertowanie danych obrazu na postać liczbową, aby wykonywać zadania związane z przetwarzaniem obrazu za pomocą uczenia maszynowego, takie jak porównywanie podobieństwa 2 obrazów. Z tych instrukcji dowiesz się, jak używać wtyczki do umieszczania obrazów w aplikacjach na Androida.

Więcej informacji o możliwościach, modelach i opcjach konfiguracji związanych z tym zadaniem znajdziesz w sekcji Omówienie.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to prosta implementacja aplikacji Image Embedder na Androida. W przykładzie do ciągłego umieszczania obrazów używana jest kamera na fizycznym urządzeniu z Androidem. Można też uruchomić narzędzie do umieszczania na plikach obrazów zapisanych na urządzeniu.

Możesz użyć tej aplikacji jako punktu wyjścia do stworzenia własnej aplikacji na Androida lub skorzystać z niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod Image Embedder 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, aby używać rzadkiego sprawdzania, dzięki czemu będziesz mieć tylko pliki przykładowej aplikacji Image Embedder:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_embedder/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

Te pliki zawierają kod niezbędny do działania przykładowej aplikacji do umieszczania obrazów:

  • ImageEmbedderHelper.kt: inicjalizowanie modułu embedder obrazu i obsługa wyboru modelu i delegata.
  • MainActivity.kt: implementuje aplikację i montuje komponenty interfejsu użytkownika.

Konfiguracja

W tej sekcji opisaliśmy najważniejsze kroki konfiguracji środowiska programistycznego i projektów kodu, które umożliwiają korzystanie z narzędzia do wklejania obrazów. 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

Image Embedder korzysta z biblioteki com.google.mediapipe:tasks-vision. Dodaj tę zależność do pliku build.gradle projektu tworzenia aplikacji na Androida. Zaimportuj wymagane zależności za pomocą tego kodu:

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

Model

Zadanie MediaPipe Image Embedder wymaga wytrenowanego modelu, który jest zgodny z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach usługi Image Embedder 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 funkcji setupImageEmbedder() w pliku ImageEmbedderHelper.kt:

Użyj metody BaseOptions.Builder.setModelAssetPath(), aby określić ścieżkę używaną przez model. Ta metoda jest wywoływana w przykładowym kodzie w następnej sekcji.

Tworzenie zadania

Do utworzenia zadania możesz użyć funkcji createFromOptions. Funkcja createFromOptions akceptuje opcje konfiguracji, które umożliwiają konfigurowanie opcji wtyczki. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Omówienie konfiguracji.

Zadanie Wstawianie obrazów obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i transmisje wideo na żywo. Podczas tworzenia zadania musisz określić tryb wykonywania odpowiadający typowi danych wejściowych. Wybierz kartę odpowiadającą typowi danych wejściowych, aby dowiedzieć się, jak utworzyć zadanie i przeprowadzić wnioskowanie.

Obraz

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.IMAGE)
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

Wideo

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.VIDEO)
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

Transmisja na żywo

ImageEmbedderOptions options =
  ImageEmbedderOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setQuantize(true)
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setResultListener((result, inputImage) -> {
         // Process the embedding result here.
    })
    .build();
imageEmbedder = ImageEmbedder.createFromOptions(context, options);
    

Implementacja przykładowego kodu umożliwia użytkownikowi przełączanie się między trybami przetwarzania. Takie podejście skomplikuje kod tworzenia zadania i może nie być odpowiednie w Twoim przypadku. Ten kod znajdziesz w funkcji setupImageEmbedder() w pliku ImageEmbedderHelper.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
l2_normalize Określa, czy zwrócony wektor cech ma być znormalizowany za pomocą normy L2. Używaj tej opcji tylko wtedy, gdy model nie zawiera już natywnej operacji TFLite L2_NORMALIZATION. W większości przypadków tak jest już w ogóle, więc normalizacja L2 jest osiągana przez wnioskowanie TFLite bez potrzeby stosowania tej opcji. Boolean False
quantize Określa, czy zwrócony wektor dystrybucyjny ma być zaokrąglony do bajtów za pomocą kwantyzacji skalarnej. Zakłada się, że wektory mają długość jednostkową, dlatego wartość dowolnego wymiaru musi mieścić się w zakresie [-1,0, 1,0]. Jeśli nie, użyj opcji l2_normalize. Boolean False
resultListener Ustawia odbiornik wyników tak, aby otrzymywał wyniki umieszczania asynchronicznie, gdy moduł umieszczania obrazu jest w trybie transmisji na żywo. Można go używać tylko wtedy, gdy tryb działania ma wartość LIVE_STREAM. Nie dotyczy Nie ustawiono
errorListener Ustawia opcjonalny odbiornik błędów. Nie dotyczy Nie ustawiono

Przygotuj dane

Wtyczka do wklejania obrazów działa z obrazami, plikami wideo i transmisjami na żywo. Zadanie to obsługuje wstępną obróbkę danych wejściowych, w tym zmianę rozmiaru, obrót i normalizację wartości.

Przed przekazaniem zadania do modułu osadzania obrazów musisz przekonwertować podany obraz lub ramkę na obiekt com.google.mediapipe.framework.image.MPImage.

Obraz

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

// Load an image on the users device as a Bitmap object using BitmapFactory.

// Convert an Androids Bitmap object to a MediaPipes 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 videos metadata, load the METADATA_KEY_DURATION and
// METADATA_KEY_VIDEO_FRAME_COUNT value. Youll need them
// to calculate the timestamp of each frame later.

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

// Convert the Androids Bitmap object to a MediaPipes 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 CameraXs ImageAnalysis to continuously receive frames
// from the devices camera. Configure it to output frames in RGBA_8888
// format to match with what is required by the model.

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

W przykładowym kodzie przygotowanie danych jest obsługiwane w pliku ImageEmbedderHelper.kt.

Uruchamianie zadania

Aby wywołać wnioskowanie, możesz wywołać funkcję embed odpowiadającą bieżącemu trybowi działania. Interfejs API Image Embedder zwraca wektory embeddingu dla podawanego obrazu lub kadru.

Obraz

ImageEmbedderResult embedderResult = imageEmbedder.embed(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.
ImageEmbedderResult embedderResult =
    imageEmbedder.embedForVideo(image, frameTimestampMs);
    

Transmisja na żywo

// Run inference on the frame. The embedding results will be available
// via the `resultListener` provided in the `ImageEmbedderOptions` when
// the image embedder was created.
imageEmbedder.embedAsync(image, frameTimestampMs);
    

Pamiętaj:

  • W trybie wideo lub transmisji na żywo musisz też podać zadaniu Image Embedder sygnaturę czasową ramki wejściowej.
  • Gdy jest wykonywane w trybie obrazu lub filmu, zadanie wstawiania obrazu blokuje bieżący wątek, dopóki nie zakończy przetwarzania obrazu wejściowego lub klatki. Aby uniknąć blokowania bieżącego wątku, przeprowadź przetwarzanie w wątku tła.
  • W trybie transmisji na żywo zadanie osadzania obrazów nie blokuje bieżącego wątku, ale zwraca się natychmiast. Za każdym razem, gdy zakończy przetwarzanie ramki wejściowej, wywoła swojego słuchacza z wynikiem wykrywania. Jeśli funkcja embedAsync zostanie wywołana, gdy zadanie Image Embedder jest zajęte przetwarzaniem innej klatki, zadanie zignoruje nową klatkę wejściową.

W przykładowym kodzie funkcja embed jest zdefiniowana w pliku ImageEmbedderHelper.kt.

Obsługa i wyświetlanie wyników

Po wykonaniu wnioskowania zadanie Image Embedder zwraca obiekt ImageEmbedderResult, który zawiera listę elementów (zmiennych lub skalarnych) dla obrazu wejściowego.

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

ImageEmbedderResult:
  Embedding #0 (sole embedding head):
    float_embedding: {0.0, 0.0, ..., 0.0, 1.0, 0.0, 0.0, 2.0}
    head_index: 0

Ten wynik został uzyskany dzięki umieszczeniu tego obrazu:

Ujęcie średnie egzotycznego kota

Za pomocą funkcji ImageEmbedder.cosineSimilarity możesz porównać podobieństwo 2 wkładników. Przykładowy kod znajdziesz poniżej.

// Compute cosine similarity.
double similarity = ImageEmbedder.cosineSimilarity(
  result.embeddingResult().embeddings().get(0),
  otherResult.embeddingResult().embeddings().get(0));