Zadanie MediaPipe Image Segmenter umożliwia dzielenie obrazów na regiony na podstawie zdefiniowanych wstępnie kategorii, aby stosować efekty wizualne, takie jak rozmycie tła. Z tych instrukcji dowiesz się, jak używać narzędzia do dzielenia obrazu w przypadku aplikacji na Androida. Przykład kodu opisany w tych instrukcjach jest dostępny na GitHub. 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 zawiera 2 proste implementacje aplikacji Image Segmenter na Androida:
Przykłady wykorzystują kamerę na fizycznym urządzeniu z Androidem do segmentacji obrazu na podstawie strumienia z kamery na żywo. Możesz też wybrać obrazy i filmy z galerii urządzenia. Możesz użyć tych aplikacji jako punktu wyjścia do utworzenia własnej aplikacji na Androida lub skorzystać z nich podczas modyfikowania istniejącej aplikacji. Przykładowy kod Image Segmenter jest hostowany na GitHub.
Poniższe sekcje odnoszą się do aplikacji Image Segmenter z maską kategorii.
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:
- Sklonuj repozytorium Git za pomocą tego polecenia:
git clone https://github.com/google-ai-edge/mediapipe-samples
- Opcjonalnie skonfiguruj instancję git do korzystania z rzadkiego sprawdzania, aby mieć 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 do Android Studio i uruchomić aplikację. Instrukcje znajdziesz w przewodniku konfiguracji Androida.
Kluczowe komponenty
Te pliki zawierają kluczowy kod przykładowej aplikacji do segmentacji obrazu:
- ImageSegmenterHelper.kt – inicjuje zadanie segmentacji obrazu i obsługuje model oraz wybór delegata.
- CameraFragment.kt – zawiera interfejs użytkownika i kod sterujący kamerą.
- GalleryFragment.kt – zawiera interfejs użytkownika i kod sterujący do wybierania plików z obrazami i filmami.
- OverlayView.kt – obsługuje i formatuje wyniki podziału na segmenty.
Konfiguracja
Ta sekcja zawiera opis kluczowych kroków konfiguracji środowiska programistycznego i projektów kodu, które umożliwiają korzystanie z narzędzia Image Segmenter. 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
Narzędzie do podziału obrazu korzysta z biblioteki com.google.mediapipe:tasks-vision
. Dodaj tę zależność do pliku build.gradle
w projekcie 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 Segmenter wymaga wytrenowanego modelu zgodnego z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach usługi Image Segmenter 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
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.
W przykładowym kodzie segmentacji obrazu model jest zdefiniowany w klasie ImageSegmenterHelper.kt
w funkcji setupImageSegmenter()
.
Tworzenie zadania
Do utworzenia zadania możesz użyć funkcji createFromOptions
. Funkcja createFromOptions
akceptuje opcje konfiguracji, w tym typy danych wyjściowych maski. Więcej informacji o konfigurowaniu zadań znajdziesz w artykule Opcje konfiguracji.
Zadanie segmentacji obrazu obsługuje te typy danych wejściowych: obrazy, pliki wideo i strumienie wideo na żywo. Podczas tworzenia zadania musisz określić tryb wykonywania odpowiadający typowi danych wejściowych. Aby dowiedzieć się, jak utworzyć to zadanie, wybierz kartę odpowiadającą wybranemu typowi danych wejściowych.
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)
Implementacja przykładowego kodu segmentacji obrazu 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 możesz zobaczyć w klasie ImageSegmenterHelper
w funkcji setupImageSegmenter()
.
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 |
outputCategoryMask |
Jeśli ustawisz tę opcję na True , dane wyjściowe będą zawierać maskę segmentacji w postaci obrazu uint8, w którym każda wartość piksela wskazuje zwycięską kategorię. |
{True, False } |
False |
outputConfidenceMasks |
Jeśli ustawisz tę opcję na True , dane wyjściowe będą zawierać maskę segmentacji w postaci obrazu z wartością zmiennoprzecinkową, gdzie każda wartość zmiennoprzecinkowa reprezentuje mapę współczynnika zaufania danej kategorii. |
{True, False } |
True |
displayNamesLocale |
Określa język etykiet, których należy używać do wyświetlanych nazw podanych w metadanych modelu zadania (jeśli są dostępne). Wartość domyślna to en w przypadku języka angielskiego. Możesz dodawać zlokalizowane etykiety do metadanych modelu niestandardowego, korzystając z interfejsu TensorFlow Lite Metadata Writer API. |
Kod języka | en |
resultListener |
Ustawia odbiornik wyników tak, aby asynchronicznie otrzymywał wyniki podziału na segmenty, gdy segmentator obrazu jest w trybie LIVE_STREAM .
Można go używać tylko wtedy, gdy tryb działania ma wartość LIVE_STREAM . |
Nie dotyczy | Nie dotyczy |
errorListener |
Ustawia opcjonalny odbiornik błędów. | Nie dotyczy | Nie ustawiono |
Przygotuj dane
Narzędzie do dzielenia obrazu 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 do segmentatora obrazu obraz wejściowy lub jego ramka musi zostać przekonwertowana 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 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 value. You’ll need them // 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() Image mpImage = new MediaImageBuilder(mediaImage).build();
W przykładowym kodzie Image Segmenter przygotowanie danych jest obsługiwane w klasie ImageSegmenterHelper
za pomocą funkcji segmentLiveStreamFrame()
.
Uruchamianie zadania
W zależności od trybu działania wywoływana jest inna funkcja segment
.
Funkcja ImageSegmenter zwraca zidentyfikowane obszary segmentu w wejściowym obrazie lub klatce.
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:
- W trybie wideo lub strumienia na żywo musisz też podać zadaniu segmentacji obrazu sygnaturę czasową ramki wejściowej.
- W trybie obrazu lub wideo zadanie segmentacji obrazu blokuje bieżący wątek, dopóki nie przetworzy wejściowego obrazu lub klatki. Aby uniknąć blokowania interfejsu użytkownika, przeprowadź przetwarzanie w wątku w tle.
- W trybie transmisji na żywo zadanie ImageSegmenter nie blokuje bieżącego wątku, ale zwraca wynik natychmiast. Za każdym razem, gdy zakończy przetwarzanie ramki wejściowej, wywoła swojego słuchacza z wynikiem wykrywania. Jeśli funkcja
segmentAsync
zostanie wywołana, gdy zadanie segmentacji obrazu będzie przetwarzać inną klatkę, zadanie zignoruje nową klatkę wejściową.
W przykładowym kodzie Image Segmenter funkcje segment
są zdefiniowane w pliku ImageSegmenterHelper.kt
.
Obsługa i wyświetlanie wyników
Po przeprowadzeniu wnioskowania zadanie segmentacji obrazu zwraca obiekt ImageSegmenterResult
, który zawiera wyniki zadania segmentacji. Treść danych wyjściowych zależy od wartości outputType
ustawionej podczas konfigurowania zadania.
W następnych sekcjach znajdziesz przykłady danych wyjściowych z tego zadania:
Poziom ufności kategorii
Na poniższych obrazach widać wizualizację danych wyjściowych zadania dotyczącego maski ufności kategorii. Wyjście maski ufności zawiera wartości zmiennoprzecinkowe z zakresu [0, 1]
.
Wyjście maski oryginalnego obrazu i pewności kategorii. Obraz źródłowy z danych Pascal VOC 2012.
Wartość kategorii
Na poniższych obrazach widać wizualizację danych wyjściowych zadania w przypadku maski wartości kategorii. Zakres maski kategorii to [0, 255]
, a każda wartość piksela reprezentuje zwycięski indeks kategorii w wyniku modelu. Wybrany indeks kategorii ma najwyższą wartość spośród kategorii rozpoznawanych przez model.
Wyjście oryginalnej maski obrazu i kategorii. Obraz źródłowy z danych Pascal VOC 2012.