Przewodnik po segmentacji obrazów na Androidzie

Zadanie MediaPipe Image segmenter umożliwia podział obrazów na regiony na podstawie wstępnie zdefiniowanych kategorii, w których można zastosować efekty wizualne, np. rozmycie tła. Te jak używać segmentacji obrazów w aplikacjach na Androida. Kod przykład opisany w tych instrukcjach jest dostępny na GitHub Więcej informacji o funkcjach, modelach i opcjach konfiguracji zapoznaj się z Przeglądem.

Przykładowy kod

Przykładowy kod MediaPipe Tasks zawiera dwie proste implementacje interfejsu Aplikacja do segmentowania obrazów na Androida:

Aparatem w fizycznym urządzeniu z Androidem jest aparat, segmentacji obrazu w kamerze lub wybrać obrazy i z galerii na urządzeniu. Możesz ich używać jako punktu wyjścia Twoją własną aplikację na Androida lub przywoływać się do nich podczas modyfikowania istniejącej aplikacji. Przykładowy kod segmentacji obrazów jest hostowany GitHub

W sekcjach poniżej Segmenter obrazów z maską kategorii .

Pobieranie kodu

Poniżej znajdziesz instrukcje tworzenia lokalnej kopii przykładu. 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 możesz skonfigurować instancję git tak, aby wykorzystywała rozproszony proces płatności, masz więc tylko pliki przykładowej aplikacji Image Segmenter:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_segmentation/android
    

Po utworzeniu lokalnej wersji przykładowego kodu możesz zaimportować projekt w Android Studio i uruchom aplikację. Instrukcje znajdziesz w Przewodnik po konfiguracji na Androida

Kluczowe elementy

Te pliki zawierają kluczowy kod dla tego obrazu przykładowa aplikacja do podziału na segmenty:

  • ImageSegmenterHelper.kt – Inicjuje zadanie segmentacji obrazów oraz obsługuje model i przekazuje dostęp do niego wyboru.
  • CameraFragment.kt – Zawiera interfejs użytkownika i kod sterujący kamery.
  • GalleryFragment.kt – Zawiera interfejs użytkownika i kod sterujący do wyboru obrazów i filmów .
  • OverlayView.kt – Obsługuje i formatuje wyniki segmentacji.

Konfiguracja

W tej sekcji opisujemy najważniejsze czynności związane z konfigurowaniem środowiska programistycznego oraz w projektach kodu, w których można używać segmentowania obrazów. Ogólne informacje na temat: skonfigurować środowisko programistyczne do korzystania z zadań MediaPipe, w tym wymagań wersji platformy, patrz Przewodnik po konfiguracji na Androida

Zależności

Segmentacja obrazów korzysta z biblioteki com.google.mediapipe:tasks-vision. Dodaj to zależności od pliku build.gradle Projekt tworzenia aplikacji na Androida. Zaimportuj wymagane zależności za pomocą: ten kod:

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

Model

Zadanie MediaPipe Image segmenter wymaga wytrenowanego modelu zgodnego z tym zadanie. Więcej informacji na temat dostępnych wytrenowanych modeli dla narzędzia do segmentowania obrazów znajdziesz w artykule zapoznaj się z omówieniem zadania sekcją Modele.

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

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

Użyj metody BaseOptions.Builder.setModelAssetPath(), aby podać ścieżkę używane przez model. Tę metodę przywołaliśmy w przykładzie kodu w następnym .

W segmentatorze obrazów przykładowy kod, model jest zdefiniowany w ImageSegmenterHelper.kt w funkcji setupImageSegmenter().

Tworzenie zadania

Do utworzenia zadania możesz użyć funkcji createFromOptions. Funkcja createFromOptions akceptuje opcje konfiguracji, w tym dane wyjściowe maski . Więcej informacji o konfigurowaniu zadań znajdziesz w artykule Opcje konfiguracji:

Zadanie segmentacji obrazów obsługuje te typy danych wejściowych: obrazy, plików wideo i transmisji wideo na żywo. Musisz określić tryb uruchamiania odpowiadający typowi danych wejściowych podczas tworzenia zadania. Wybierz kartę dla typu danych wejściowych, aby zobaczyć, jak utworzyć to zadanie.

Obraz

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.IMAGE)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .build();
imagesegmenter = ImageSegmenter.createFromOptions(context, options);
    

Wideo

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.VIDEO)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .build();
imagesegmenter = ImageSegmenter.createFromOptions(context, options);
    

Transmisja na żywo

ImageSegmenterOptions options =
  ImageSegmenterOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setOutputCategoryMask(true)
    .setOutputConfidenceMasks(false)
    .setResultListener((result, inputImage) -> {
         // Process the segmentation result here.
    })
    .setErrorListener((result, inputImage) -> {
         // Process the segmentation errors here.
    })
    .build()
imagesegmenter = ImageSegmenter.createFromOptions(context, options)
    

Przykładowa implementacja kodu segmentacji obrazów pozwala użytkownikowi przełączać się między i przetwarzania danych. Takie podejście sprawia, że kod tworzenia zadań jest bardziej skomplikowany, może nie być odpowiednia w Twoim przypadku użycia. Możesz zobaczyć ten kod w ImageSegmenterHelper przez funkcję setupImageSegmenter().

Opcje konfiguracji

To zadanie zawiera te opcje konfiguracji aplikacji na Androida:

Nazwa opcji Opis Zakres wartości Wartość domyślna
runningMode Ustawia tryb działania zadania. Są trzy tryby:

IMAGE: tryb wprowadzania pojedynczego obrazu.

WIDEO: tryb zdekodowanych klatek filmu.

LIVE_STREAM: tryb transmisji danych wejściowych na przykład z kamery. W tym trybie detektor wyników musi mieć wartość wywołano, aby skonfigurować detektor i otrzymywać wyniki asynchronicznie.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
outputCategoryMask Jeśli ma wartość True, dane wyjściowe będą zawierały maskę podziału na segmenty. jako obraz uint8, gdzie każda wartość w pikselach wskazuje zwycięską kategorię . {True, False} False
outputConfidenceMasks Jeśli ma wartość True, dane wyjściowe będą zawierały maskę podziału na segmenty. jako obraz wartości zmiennoprzecinkowej, gdzie każda wartość zmiennoprzecinkowa odzwierciedla poziom ufności punktację danej kategorii. {True, False} True
displayNamesLocale Ustawia język etykiet, które mają być używane w przypadku nazw wyświetlanych w kolumnie metadane modelu zadania, jeśli są dostępne. Wartość domyślna to en dla Angielski. Do metadanych modelu niestandardowego możesz dodać zlokalizowane etykiety za pomocą interfejsu TensorFlow Lite Metadata Writer API. Kod języka en
resultListener Konfiguruje detektor wyników, który ma otrzymywać wyniki segmentacji asynchronicznie, gdy segmenter obrazów działa w trybie LIVE_STREAM. Tej opcji można używać tylko wtedy, gdy tryb działania jest ustawiony na LIVE_STREAM Nie dotyczy Nie dotyczy
errorListener Ustawia opcjonalny detektor błędów. Nie dotyczy Nie ustawiono

Przygotuj dane

Narzędzie do podziału obrazów działa z obrazami, plikami wideo i transmisjami wideo na żywo. Zadanie obsługuje wstępne przetwarzanie danych wejściowych, w tym zmianę rozmiaru, obrót i wartość ich normalizację.

Musisz przekonwertować obraz lub klatkę wejściową do com.google.mediapipe.framework.image.MPImage obiekt przed przekazaniem do Segmentowanie obrazów.

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 segmentacji obrazów przygotowanie danych odbywa się w sekcji ImageSegmenterHelper przez funkcję segmentLiveStreamFrame().

Uruchamianie zadania

W zależności od używanego trybu uruchamiania wywołasz inną funkcję segment. Funkcja segmentowania obrazów zwraca zidentyfikowane regiony segmentu w obrębie argumentu obrazu lub ramki.

Obraz

ImageSegmenterResult segmenterResult = imagesegmenter.segment(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.
ImageSegmenterResult segmenterResult =
    imagesegmenter.segmentForVideo(image, frameTimestampMs);
    

Transmisja na żywo

// Run inference on the frame. The segmentations results will be available via
// the `resultListener` provided in the `ImageSegmenterOptions` when the image
// segmenter was created.
imagesegmenter.segmentAsync(image, frameTimestampMs);
    

Pamiętaj:

  • Gdy pracujesz w trybie wideo lub w trybie transmisji na żywo, musisz też podaj sygnaturę czasową ramki wejściowej zadania segmentacji obrazów.
  • W trybie obrazu lub wideo zadanie segmentacji obrazów blokuje bieżący wątek do czasu zakończenia przetwarzania obrazu wejściowego lub ramki. Aby uniknąć blokowania interfejsu użytkownika, wykonaj przetwarzanie w w wątku w tle.
  • W trybie transmisji na żywo zadanie segmentacji obrazów nie blokuje w bieżącym wątku, ale wraca natychmiast. Wywoła swój wynik detektor z wynikiem wykrywania za każdym razem, gdy zakończy przetwarzanie ramki wejściowej. Jeśli funkcja segmentAsync jest wywoływana podczas segmentowania obrazów zadanie jest zajęte przetwarzaniem innej ramki, zadanie zignoruje nową ramkę wejściową.

W przykładowym kodzie segmentacji obrazów funkcje segment są zdefiniowane w sekcji ImageSegmenterHelper.kt. .

Obsługa i wyświetlanie wyników

Po przeprowadzeniu wnioskowania zadanie segmentacji obrazów zwraca wartość ImageSegmenterResult. który zawiera wyniki zadania segmentacji. Zawartość dane wyjściowe zależą od parametru outputType ustawionego podczas skonfigurowano zadanie.

W sekcjach poniżej znajdziesz przykłady danych wyjściowych z tego zadania:

Poziom ufności kategorii

Te obrazy przedstawiają wizualizację danych wyjściowych zadania dla kategorii maską ufności. Dane wyjściowe maski ufności zawierają wartości zmiennoprzecinkowe między [0, 1]

Oryginalny obraz i maska zaufania kategorii. Obraz źródłowy z Pascal VOC 2012 w zbiorze danych.

Wartość kategorii

Te obrazy przedstawiają wizualizację danych wyjściowych zadania dla kategorii maską wartości. Zakres maski kategorii wynosi [0, 255] i każda wartość piksela reprezentuje indeks zwycięskiej kategorii danych wyjściowych modelu. Zwycięska kategoria indeks ma najwyższy wynik spośród kategorii, które model może rozpoznać.

Oryginalny obraz i maska kategorii. Obraz źródłowy z Pascal VOC 2012 w zbiorze danych.