Leitfaden zur Bildsegmentierung unter Android

Mit der Aufgabe „MediaPipe-Bildsegmentierung“ können Sie Bilder anhand vordefinierter Kategorien in Regionen unterteilen, um visuelle Effekte wie das Weichzeichnen des Hintergrunds anzuwenden. In dieser Anleitung erfahren Sie, wie Sie den Image Segmenter mit Android-Apps verwenden. Das in dieser Anleitung beschriebene Codebeispiel ist auf GitHub verfügbar. Weitere Informationen zu den Funktionen, Modellen und Konfigurationsoptionen dieser Aufgabe finden Sie in der Übersicht.

Codebeispiel

Das Codebeispiel „MediaPipe Tasks“ enthält zwei einfache Implementierungen einer Image Segmenter-App für Android:

In den Beispielen wird die Kamera eines Android-Geräts verwendet, um die Bildsegmentierung in einem Live-Kamerafeed durchzuführen. Sie können aber auch Bilder und Videos aus der Gerätegalerie auswählen. Sie können die Apps als Ausgangspunkt für Ihre eigene Android-App verwenden oder beim Modifizieren einer vorhandenen App darauf zurückgreifen. Der Beispielcode für die Bildsegmentierung wird auf GitHub gehostet.

Die folgenden Abschnitte beziehen sich auf die Anwendung Bildsegmentierung mit einer Kategoriemaske.

Code herunterladen

In der folgenden Anleitung erfahren Sie, wie Sie mit dem git-Befehlszeilentool eine lokale Kopie des Beispielcodes erstellen.

So laden Sie den Beispielcode herunter:

  1. Klonen Sie das Git-Repository mit dem folgenden Befehl:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Konfigurieren Sie optional die Git-Instanz für die Verwendung von Sparse Checkout, sodass Sie nur die Dateien für die Beispielanwendung „Image Segmenter“ haben:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_segmentation/android
    

Nachdem Sie eine lokale Version des Beispielcodes erstellt haben, können Sie das Projekt in Android Studio importieren und die App ausführen. Eine Anleitung dazu finden Sie im Einrichtungsleitfaden für Android.

Schlüsselkomponenten

Die folgenden Dateien enthalten den wichtigen Code für diese Beispielanwendung für die Bildsegmentierung:

  • ImageSegmenterHelper.kt: Initialisiert die Image Segmenter-Aufgabe und verarbeitet die Modell- und Delegierungsauswahl.
  • CameraFragment.kt: stellt die Benutzeroberfläche und den Steuercode für eine Kamera bereit.
  • GalleryFragment.kt: stellt die Benutzeroberfläche und den Steuercode zum Auswählen von Bild- und Videodateien bereit.
  • OverlayView.kt: Damit werden die Segmentierungsergebnisse verarbeitet und formatiert.

Einrichtung

In diesem Abschnitt werden die wichtigsten Schritte zum Einrichten Ihrer Entwicklungsumgebung und Codeprojekte für die Verwendung von Image Segmenter beschrieben. Allgemeine Informationen zum Einrichten der Entwicklungsumgebung für die Verwendung von MediaPipe-Aufgaben, einschließlich der Anforderungen an die Plattformversion, finden Sie im Einrichtungsleitfaden für Android.

Abhängigkeiten

Image Segmenter verwendet die com.google.mediapipe:tasks-vision-Bibliothek. Fügen Sie diese Abhängigkeit der Datei build.gradle Ihres Android-App-Entwicklungsprojekts hinzu. Importieren Sie die erforderlichen Abhängigkeiten mit dem folgenden Code:

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

Modell

Für die MediaPipe-Bildsegmentierungsaufgabe ist ein trainiertes Modell erforderlich, das mit dieser Aufgabe kompatibel ist. Weitere Informationen zu verfügbaren trainierten Modellen für Image Segmenter finden Sie in der Aufgabenübersicht im Abschnitt „Modelle“.

Wählen Sie das Modell aus, laden Sie es herunter und speichern Sie es dann in Ihrem Projektverzeichnis:

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

Verwenden Sie die Methode BaseOptions.Builder.setModelAssetPath(), um den vom Modell verwendeten Pfad anzugeben. Auf diese Methode wird im Codebeispiel im nächsten Abschnitt verwiesen.

Im Beispielcode von Image Segmenter wird das Modell in der Klasse ImageSegmenterHelper.kt in der Funktion setupImageSegmenter() definiert.

Aufgabe erstellen

Sie können die createFromOptions-Funktion verwenden, um die Aufgabe zu erstellen. Die Funktion createFromOptions akzeptiert Konfigurationsoptionen, einschließlich Maskenausgabetypen. Weitere Informationen zur Aufgabenkonfiguration finden Sie unter Konfigurationsoptionen.

Die Aufgabe zur Bildsegmentierung unterstützt die folgenden Eingabedatentypen: Standbilder, Videodateien und Live-Videostreams. Sie müssen beim Erstellen der Aufgabe den Ausführungsmodus angeben, der Ihrem Eingabedatentyp entspricht. Wählen Sie die Registerkarte für Ihren Eingabedatentyp aus, um zu sehen, wie diese Aufgabe erstellt wird.

Bild

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

Video

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

Livestream

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)
    

Mit der Implementierung des Beispielcodes für die Bildsegmentierung kann der Nutzer zwischen den Verarbeitungsmodi wechseln. Dadurch wird der Code zur Aufgabenerstellung komplizierter und ist für Ihren Anwendungsfall möglicherweise nicht geeignet. Sie finden diesen Code in der Klasse ImageSegmenterHelper der Funktion setupImageSegmenter().

Konfigurationsoptionen

Diese Aufgabe umfasst die folgenden Konfigurationsoptionen für Android-Apps:

Option Beschreibung Wertebereich Standardwert
runningMode Legt den Ausführungsmodus für die Task fest. Es gibt drei Modi:

IMAGE: Der Modus für Einzelbildeingaben.

VIDEO: Der Modus für decodierte Frames eines Videos.

LIVE_STREAM: Der Modus für einen Livestream der Eingabedaten, z. B. von einer Kamera. In diesem Modus muss resultListener aufgerufen werden, um einen Listener einzurichten, der die Ergebnisse asynchron empfängt.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
outputCategoryMask Wenn True festgelegt ist, enthält die Ausgabe eine Segmentierungsmaske als uint8-Bild, wobei jeder Pixelwert den Wert der erfolgreichen Kategorie angibt. {True, False} False
outputConfidenceMasks Wenn True festgelegt ist, enthält die Ausgabe eine Segmentierungsmaske als Gleitkommazahlbild, wobei jeder Gleitkommawert die Konfidenzwertzuordnung der Kategorie darstellt. {True, False} True
displayNamesLocale Legt die Sprache von Labels fest, die für Anzeigenamen bereitgestellt werden, die in den Metadaten des Aufgabenmodells angegeben sind, sofern verfügbar. Der Standardwert für Englisch ist en. Mit der TensorFlow Lite Metadata Writer API können Sie den Metadaten eines benutzerdefinierten Modells lokalisierte Labels hinzufügen. Sprachcode en
resultListener Legt den Ergebnis-Listener so fest, dass die Segmentierungsergebnisse asynchron empfangen werden, wenn sich der Bildsegmentierer im Livestream-Modus befindet. Kann nur verwendet werden, wenn der Laufmodus auf LIVE_STREAM festgelegt ist
errorListener Legt einen optionalen Fehler-Listener fest. Nicht festgelegt

Daten vorbereiten

Der Image Segmenter kann mit Bildern, Videodateien und Livestream-Videos verwendet werden. Die Aufgabe übernimmt die Vorverarbeitung der Dateneingabe, einschließlich Größenanpassung, Rotation und Wertnormalisierung.

Sie müssen das Eingabebild oder den Eingabeframe in ein com.google.mediapipe.framework.image.MPImage-Objekt konvertieren, bevor Sie es an den Image Segmenter übergeben.

Bild

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();
    

Video

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();
    

Livestream

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();
    

Im Beispielcode für die Image Segmentierung erfolgt die Datenvorbereitung in der Klasse ImageSegmenterHelper von der segmentLiveStreamFrame()-Funktion.

Task ausführen

Sie rufen je nach verwendetem Ausführungsmodus eine andere segment-Funktion auf. Die Funktion „Image Segmenter“ gibt die identifizierten Segmentbereiche innerhalb des Eingabebilds oder ‐frames zurück.

Bild

ImageSegmenterResult segmenterResult = imagesegmenter.segment(image);
    

Video

// 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);
    

Livestream

// 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);
    

Wichtige Hinweise:

  • Im Video- oder Livestreammodus müssen Sie auch den Zeitstempel des Eingabeframes für die Aufgabe zur Bildsegmentierung angeben.
  • Im Bild- oder Videomodus blockiert die Aufgabe zur Bildsegmentierung den aktuellen Thread, bis die Verarbeitung des Eingabebilds oder -frames abgeschlossen ist. Führen Sie die Verarbeitung in einem Hintergrundthread aus, damit die Benutzeroberfläche nicht blockiert wird.
  • Im Livestreammodus blockiert die Aufgabe zur Bildsegmentierung nicht den aktuellen Thread, sondern wird sofort zurückgegeben. Jedes Mal, wenn ein Eingabeframe verarbeitet wurde, ruft er seinen Ergebnis-Listener mit dem Erkennungsergebnis auf. Wenn die Funktion segmentAsync aufgerufen wird, während die Aufgabe zur Bildsegmentierung einen weiteren Frame verarbeitet, wird der neue Eingabeframe von der Aufgabe ignoriert.

Im Beispielcode für die Bildsegmentierung sind die segment-Funktionen in der Datei ImageSegmenterHelper.kt definiert.

Ergebnisse verarbeiten und anzeigen

Nach der Inferenz gibt die Aufgabe zur Segmentierung von Bildern ein ImageSegmenterResult-Objekt zurück, das die Ergebnisse der Segmentierungsaufgabe enthält. Der Inhalt der Ausgabe hängt von dem outputType ab, den Sie bei der Konfiguration der Aufgabe festgelegt haben.

Die folgenden Abschnitte enthalten Beispiele für die Ausgabedaten dieser Aufgabe:

Kategorie Konfidenz

Die folgenden Bilder zeigen eine Visualisierung der Aufgabenausgabe für eine Kategorie-Konfidenzmaske. Die Ausgabe der Konfidenzmaske enthält Gleitkommawerte zwischen [0, 1].

Ausgabe der Originalbild- und Kategorie-Konfidenzmaske. Quellbild aus dem Dataset Pascal VOC 2012.

Kategoriewert

Die folgenden Bilder zeigen eine Visualisierung der Aufgabenausgabe für eine Kategoriewertmaske. Der Kategoriemaskenbereich ist [0, 255] und jeder Pixelwert stellt den erfolgreichen Kategorieindex der Modellausgabe dar. Der Index der erfolgreichen Kategorie hat den höchsten Wert unter den Kategorien, die das Modell erkennen kann.

Ausgabe des Originalbilds und der Kategoriemaske. Quellbild aus dem Dataset Pascal VOC 2012.