Zadanie segmentacji obrazów MediaPipe pozwala dzielić obrazy na regiony na podstawie wstępnie zdefiniowanych kategorii do stosowania efektów wizualnych, takich jak rozmycie tła. Z tych instrukcji dowiesz się, jak korzystać z segmentowania obrazów w aplikacjach na Androida. 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 sekcji Omówienie.
Przykładowy kod
Przykład kodu MediaPipe Tasks zawiera 2 proste implementacje aplikacji Image Segmenter na Androida:
- Narzędzie do segmentowania obrazów z maską kategorii
- Narzędzie do segmentowania obrazów z maską ufności
W przykładach używamy aparatu na fizycznym urządzeniu z Androidem, aby segmentować obraz na bieżąco z kamery. Możesz też wybierać obrazy i filmy z galerii urządzenia. Możesz użyć tych aplikacji jako punktu wyjścia dla własnej aplikacji na Androida lub skorzystać z nich podczas modyfikowania istniejącej aplikacji. Przykładowy kod narzędzia Image Segmenter jest hostowany na GitHub.
Podane niżej sekcje dotyczą aplikacji Narzędzie do podziału obrazów na segmenty z maską kategorii.
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:
- Sklonuj repozytorium git za pomocą tego polecenia:
git clone https://github.com/google-ai-edge/mediapipe-samples
- Opcjonalnie skonfiguruj instancję git tak, aby używała rozproszonego procesu płatności, aby mieć tylko pliki dla przykładowej aplikacji do segmentacji obrazów:
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 na Androida.
Kluczowe elementy
Te pliki zawierają kluczowy kod tej przykładowej aplikacji do podziału obrazów na segmenty:
- ImageSegmenterHelper.kt – inicjuje zadanie Segmentacja obrazów i obsługuje model oraz wybór przedstawicieli.
- CameraFragment.kt – zawiera interfejs i kod sterowania kamerą.
- GalleryFragment.kt – udostępnia interfejs i kod sterujący do wybierania plików graficznych i wideo.
- OverlayView.kt – obsługuje i formatuje wyniki podziału na segmenty.
Konfiguracja
W tej sekcji znajdziesz najważniejsze czynności, jakie należy wykonać, aby skonfigurować środowisko programistyczne i projekty kodu związane z korzystaniem z narzędzia do segmentowania obrazó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
Narzędzie do segmentowania obrazów korzysta z 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 segmentacji obrazów MediaPipe wymaga wytrenowanego modelu zgodnego z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach służących do segmentowania obrazów znajdziesz w sekcji przeglądu zadań w sekcji poświęconej modelom.
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()
. Tę metodę omówimy w przykładowym kodzie w następnej sekcji.
W przykładowym kodzie do segmentacji obrazów model jest zdefiniowany w klasie ImageSegmenterHelper.kt
w funkcji setupImageSegmenter()
.
Tworzenie zadania
Aby utworzyć zadanie, możesz użyć funkcji createFromOptions
. Funkcja createFromOptions
akceptuje opcje konfiguracji, w tym typy masek. Więcej informacji o konfigurowaniu zadań znajdziesz w artykule o opcjach konfiguracji.
Zadanie segmentacji obrazów 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ę z typem danych wejściowych, aby zobaczyć, jak utworzyć takie 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)
Implementacja kodu przykładowego narzędzia do segmentacji obrazó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 jest widoczny w klasie ImageSegmenterHelper
przy funkcji setupImageSegmenter()
.
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 |
outputCategoryMask |
Jeśli ma wartość True , dane wyjściowe zawierają maskę podziału jako obraz uint8, w którym każda wartość piksela wskazuje zwycięską kategorię. |
{True, False } |
False |
outputConfidenceMasks |
Jeśli ustawiona jest wartość True , dane wyjściowe zawierają maskę podziału w postaci obrazu z wartością zmiennoprzecinkową, w którym każda wartość zmiennoprzecinkowa reprezentuje mapę wskaźnika ufności kategorii. |
{True, False } |
True |
displayNamesLocale |
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 |
resultListener |
Ustawia detektor wyników, aby asynchronicznie otrzymywać wyniki podziału na segmenty, gdy moduł do segmentacji obrazów działa w trybie transmisji na żywo.
Tego ustawienia można używać tylko wtedy, gdy tryb biegowy 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 segmentowania obrazów obsługuje obrazy, pliki wideo i strumieniową transmisję wideo na żywo. To zadanie obsługuje wstępne przetwarzanie danych wejściowych, w tym zmianę rozmiaru, rotację i normalizację wartości.
Zanim prześlesz obraz lub ramkę do segmentacji obrazów, musisz przekonwertować go 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 narzędzia do segmentacji obrazów przygotowywanie danych jest obsługiwane w klasie ImageSegmenterHelper
przez funkcję segmentLiveStreamFrame()
.
Uruchamianie zadania
Wywołujesz inną funkcję segment
w zależności od używanego trybu biegania.
Funkcja segmentowania obrazów zwraca zidentyfikowane regiony segmentów w obrazie lub ramce wejściowej.
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);
Uwaga:
- Gdy urządzenie działa w trybie wideo lub transmisji na żywo, musisz też podać w zadaniu segmentacji obrazów sygnaturę czasową klatki wejściowej.
- W trybie obrazu lub wideo zadanie segmentowania obrazów blokuje bieżący wątek do momentu zakończenia przetwarzania obrazu wejściowego lub klatki. Aby uniknąć zablokowania interfejsu, przetwarzanie odbywa się w wątku w tle.
- W trybie transmisji na żywo zadanie segmentowania obrazów nie blokuje bieżącego wątku, ale wraca natychmiast. Wywołuje on detektor wyników z wynikiem wykrywania za każdym razem, gdy zakończy przetwarzanie ramki wejściowej. Jeśli funkcja
segmentAsync
zostanie wywołana, gdy zadanie segmentowania obrazów jest zajęte przetwarzaniem innej ramki, zadanie zignoruje nową ramkę wejściową.
W przykładowym kodzie narzędzia do segmentacji obrazów funkcje segment
są zdefiniowane w pliku ImageSegmenterHelper.kt
.
Obsługa i wyświetlanie wyników
Po uruchomieniu wnioskowania zadanie Segmentowania obrazów zwraca obiekt ImageSegmenterResult
zawierający wyniki zadania podziału na segmenty. Zawartość danych wyjściowych zależy od parametru outputType
ustawionego podczas konfigurowania zadania.
W sekcjach poniżej znajdziesz przykłady danych wyjściowych z tego zadania:
Poziom ufności kategorii
Na poniższych obrazach pokazano wizualizację wyników zadania dla maski ufności kategorii. Dane wyjściowe maski ufności zawierają wartości zmiennoprzecinkowe między [0, 1]
.
Oryginalny obraz i wyjście maski ufności kategorii. Obraz źródłowy ze zbioru danych Pascal VOC 2012.
Wartość kategorii
Na poniższych obrazach pokazano wizualizację danych wyjściowych zadania w przypadku maski wartości kategorii. Zakres maski kategorii to [0, 255]
, a każda wartość w pikselu reprezentuje zwycięski indeks kategorii danych wyjściowych modelu. Indeks zwycięskiej kategorii ma najwyższy wynik spośród kategorii rozpoznawanych przez model.
Oryginalny obraz i maska kategorii. Obraz źródłowy ze zbioru danych Pascal VOC 2012.