Leitfaden zur Bildsegmentierung unter Android

Mit der MediaPipe-Aufgabe „Bildsegmentierung“ können Sie Bilder basierend auf vordefinierten Kategorien in Regionen unterteilen, um visuelle Effekte wie das Weichzeichnen des Hintergrunds anzuwenden. In dieser Anleitung erfahren Sie, wie Sie den Bildsegmenter 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 MediaPipe Tasks-Codebeispiel enthält zwei einfache Implementierungen einer Bildsegmentierungs-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 sich an ihnen orientieren, wenn Sie eine vorhandene App ändern. Der Beispielcode für den Bildsegmenter wird auf GitHub gehostet.

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

Code herunterladen

In der folgenden Anleitung wird beschrieben, wie Sie mit dem Befehlszeilentool git 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. Optional können Sie Ihre Git-Instanz so konfigurieren, dass eine spärliche Überprüfung verwendet wird, sodass nur die Dateien für die Beispielanwendung „Image Segmenter“ vorhanden sind:
    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 wichtigsten Code für diese Beispielanwendung zur Bildsegmentierung:

  • ImageSegmenterHelper.kt: Hiermit wird die Aufgabe „Bildsegmentierung“ initialisiert und das Modell und die Auswahl des zuständigen Diensts verwaltet.
  • CameraFragment.kt: Bietet die Benutzeroberfläche und den Steuercode für eine Kamera.
  • GalleryFragment.kt: Bietet die Benutzeroberfläche und den Steuercode zum Auswählen von Bild- und Videodateien.
  • OverlayView.kt: Hier werden die Segmentierungsergebnisse verarbeitet und formatiert.

Einrichtung

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

Abhängigkeiten

Für den Bildsegmentierungstool wird die com.google.mediapipe:tasks-vision-Bibliothek verwendet. 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-Aufgabe „Bildsegmentierung“ ist ein trainiertes Modell erforderlich, das mit dieser Aufgabe kompatibel ist. Weitere Informationen zu verfügbaren trainierten Modellen für den Bildsegmenter finden Sie in der Aufgabenübersicht im Abschnitt „Modelle“.

Wählen Sie das Modell aus, laden Sie es herunter und speichern Sie es 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 für den Bildsegmenter wird das Modell in der Klasse ImageSegmenterHelper.kt in der Funktion setupImageSegmenter() definiert.

Aufgabe erstellen

Sie können die Aufgabe mit der Funktion createFromOptions erstellen. Die Funktion createFromOptions akzeptiert Konfigurationsoptionen, einschließlich Maskierungsausgabetypen. Weitere Informationen zur Aufgabenkonfiguration finden Sie unter Konfigurationsoptionen.

Die Aufgabe „Bildsegmentierung“ unterstützt die folgenden Eingabedatentypen: Standbilder, Videodateien und Live-Videostreams. Sie müssen beim Erstellen der Aufgabe den Ausführungsmodus angeben, der dem Eingabedatentyp entspricht. Wählen Sie den Tab für den Datentyp Ihrer Eingabe aus, um zu sehen, wie Sie diese Aufgabe erstellen.

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 Beispielcodeimplementierung des Bildsegmenters kann der Nutzer zwischen den Verarbeitungsmodi wechseln. Dieser Ansatz macht den Code zum Erstellen von Aufgaben komplizierter und ist möglicherweise nicht für Ihren Anwendungsfall geeignet. Sie finden diesen Code in der Klasse ImageSegmenterHelper unter der Funktion setupImageSegmenter().

Konfigurationsoptionen

Für diese Aufgabe sind die folgenden Konfigurationsoptionen für Android-Apps verfügbar:

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

IMAGE: Der Modus für Eingaben mit einem einzelnen Bild.

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

LIVE_STREAM: Der Modus für einen Livestream von Eingabedaten, z. B. von einer Kamera. In diesem Modus muss resultListener aufgerufen werden, um einen Listener für den asynchronen Empfang von Ergebnissen einzurichten.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
outputCategoryMask Wenn dieser Wert auf True festgelegt ist, enthält die Ausgabe eine Segmentierungsmaske als uint8-Bild, bei der jeder Pixelwert den Wert der Gewinnerkategorie angibt. {True, False} False
outputConfidenceMasks Wenn dieser Parameter auf True festgelegt ist, enthält die Ausgabe eine Segmentierungsmaske als Bild mit Gleitkommawerten. Dabei steht jeder Gleitkommawert für die Konfidenzkarte der Kategorie. {True, False} True
displayNamesLocale Legt die Sprache der Labels fest, die für die Anzeigenamen verwendet werden, die in den Metadaten des Modells der Aufgabe angegeben sind, sofern verfügbar. Der Standardwert ist en für Englisch. Mit der TensorFlow Lite Metadata Writer API können Sie den Metadaten eines benutzerdefinierten Modells lokalisierte Labels hinzufügen. Gebietscode de
resultListener Legt fest, dass der Ergebnisempfänger die Segmentierungsergebnisse asynchron empfängt, wenn sich der Bildsegmenter im Modus LIVE_STREAM befindet. Kann nur verwendet werden, wenn der Ausführungsmodus auf LIVE_STREAM festgelegt ist.
errorListener Legt einen optionalen Fehler-Listener fest. Nicht festgelegt

Daten vorbereiten

Der Bildsegmentierungstool funktioniert mit Bildern, Videodateien und Livestreams. Die Aufgabe übernimmt die Vorverarbeitung der Dateneingabe, einschließlich Größenänderung, Drehung 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 Bildsegmenter übergeben.

Bild

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

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

Livestream

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

Im Beispielcode für den Bildsegmenter wird die Datenvorbereitung in der Klasse ImageSegmenterHelper über die Funktion segmentLiveStreamFrame() ausgeführt.

Aufgabe ausführen

Je nach verwendetem Ausführungsmodus wird eine andere segment-Funktion aufgerufen. Die Funktion „Bildsegmentierung“ gibt die erkannten Segmentregionen im Eingabebild oder -frame 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:

  • Wenn Sie den Video- oder Livestream-Modus verwenden, müssen Sie der Aufgabe „Image Segmenter“ auch den Zeitstempel des Eingabeframes angeben.
  • Wenn die Ausführung im Bild- oder Videomodus erfolgt, blockiert die Aufgabe „Image Segmenter“ den aktuellen Thread, bis die Verarbeitung des Eingabebilds oder ‑frames abgeschlossen ist. Führen Sie die Verarbeitung in einem Hintergrund-Thread aus, um die Benutzeroberfläche nicht zu blockieren.
  • Wenn die Ausführung im Livestream-Modus erfolgt, blockiert die Aufgabe „Bildsegmentierung“ den aktuellen Thread nicht, sondern gibt sofort eine Rückgabe zurück. Jedes Mal, wenn die Verarbeitung eines Eingabeframes abgeschlossen ist, wird der Ergebnis-Listener mit dem Erkennungsergebnis aufgerufen. Wenn die Funktion segmentAsync aufgerufen wird, während die Aufgabe „Bildsegmentierung“ gerade einen anderen Frame verarbeitet, wird der neue Eingabeframe ignoriert.

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

Ergebnisse verarbeiten und anzeigen

Nach der Ausführung der Inferenz gibt die Aufgabe „Bildsegmentierung“ ein ImageSegmenterResult-Objekt zurück, das die Ergebnisse der Segmentierungsaufgabe enthält. Der Inhalt der Ausgabe hängt von der outputType ab, die Sie beim Konfigurieren der Aufgabe festgelegt haben.

In den folgenden Abschnitten finden Sie Beispiele für die Ausgabedaten dieser Aufgabe:

Kategoriesicherheit

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

Zwei Mädchen reiten auf einem Pferd und ein Mädchen geht neben dem Pferd Die Bildmaske, die die Form der Mädchen und des Pferdes aus dem vorherigen Foto umreißt. Der Umriss der linken Hälfte des Bildes wird erfasst, die rechte Hälfte jedoch nicht.

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

Kategoriewert

Die folgenden Bilder zeigen eine Visualisierung der Aufgabenausgabe für eine Kategoriewertmaske. Der Bereich der Kategoriemaske ist [0, 255] und jeder Pixelwert entspricht dem Index der Gewinnerkategorie der Modellausgabe. Der Index der Gewinnerkategorie hat die höchste Punktzahl unter den Kategorien, die das Modell erkennen kann.

Zwei Mädchen reiten auf einem Pferd und ein Mädchen geht neben dem Pferd Die Bildmaske, die die Form der Mädchen und des Pferdes aus dem vorherigen Bild umreißt. Die Form aller drei Mädchen und des Pferdes ist korrekt maskiert.

Originalbild und Kategoriemaskenausgabe. Quellbild aus dem Pascal VOC 2012-Dataset.