Leitfaden zur Bildklassifizierung für Android

Mit der Aufgabe „MediaPipe-Bildklassifikator“ können Sie Bilder klassifizieren. Mit dieser Aufgabe können Sie ermitteln, was ein Bild in einer Reihe von Kategorien darstellt, die beim Training definiert wurden. In dieser Anleitung erfahren Sie, wie Sie den Bildklassifikator mit Android-Apps verwenden. Der in dieser Anleitung beschriebene Code ist auf GitHub verfügbar.

In der Web-Demo können Sie sich diese Aufgabe in Aktion ansehen. Weitere Informationen zu den Funktionen, Modellen und Konfigurationsoptionen dieser Aufgabe finden Sie in der Übersicht.

Codebeispiel

Der Beispielcode für MediaPipe Tasks ist eine einfache Implementierung einer Bildklassifizierungs-App für Android. Im Beispiel wird die Kamera eines physischen Android-Geräts verwendet, um Objekte kontinuierlich zu klassifizieren. Außerdem können Bilder und Videos aus der Gerätegalerie verwendet werden, um Objekte statisch zu klassifizieren.

Sie können die App als Ausgangspunkt für Ihre eigene Android-App verwenden oder sich an ihr orientieren, wenn Sie eine vorhandene App ändern. Der Beispielcode für den Bildklassifikator wird auf GitHub gehostet.

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 für die Verwendung einer spärlichen Überprüfung konfigurieren, sodass nur die Dateien für die Beispielanwendung „Image Classifier“ vorhanden sind:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_classification/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 Bildklassifizierung:

Einrichtung

In diesem Abschnitt werden die wichtigsten Schritte zur Einrichtung Ihrer Entwicklungsumgebung und zur Erstellung von Codeprojekten für die Verwendung des Bildklassifikators 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

Der Bildklassifikator 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-Bildklassifizierungsaufgabe ist ein trainiertes Modell erforderlich, das mit dieser Aufgabe kompatibel ist. Weitere Informationen zu verfügbaren trainierten Modellen für den Bildklassifikator 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 Bildklassifikator wird das Modell in der Datei ImageClassifierHelper.kt definiert.

Aufgabe erstellen

Sie können die Aufgabe mit der Funktion createFromOptions erstellen. Die Funktion createFromOptions akzeptiert Konfigurationsoptionen wie den Ausführungsmodus, die Sprache für Anzeigenamen, die maximale Anzahl von Ergebnissen, den Konfidenzgrenzwert und eine Zulassungs- oder Sperrliste für Kategorien. Weitere Informationen zu den Konfigurationsoptionen finden Sie unter Konfigurationsübersicht.

Die Aufgabe „Bildklassifikator“ unterstützt drei Eingabedatentypen: Standbilder, Videodateien und Live-Videostreams. Sie müssen beim Erstellen der Aufgabe den Ausführungsmodus angeben, der dem Datentyp der Eingabe entspricht. Wählen Sie den Tab für den Datentyp Ihrer Eingabedaten aus, um zu erfahren, wie Sie die Aufgabe erstellen und die Inferenz ausführen.

Bild

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.IMAGE)
    .setMaxResults(5)
    .build();
imageClassifier = ImageClassifier.createFromOptions(context, options);
    

Video

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.VIDEO)
    .setMaxResults(5)
    .build();
imageClassifier = ImageClassifier.createFromOptions(context, options);
    

Livestream

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setMaxResults(5)
    .setResultListener((result, inputImage) -> {
         // Process the classification result here.
    })
    .setErrorListener((result, inputImage) -> {
         // Process the classification errors here.
    })
    .build()
imageClassifier = ImageClassifier.createFromOptions(context, options)
    

Mit der Beispielcodeimplementierung des Bildklassifikators 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 Funktion setupImageClassifier() der Datei ImageClassifierHelper.kt.

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
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
maxResults Legt die optionale maximale Anzahl der Klassifizierungsergebnisse mit der höchsten Punktzahl fest, die zurückgegeben werden sollen. Wenn der Wert kleiner als 0 ist, werden alle verfügbaren Ergebnisse zurückgegeben. Beliebige positive Zahlen -1
scoreThreshold Legt den Schwellenwert für die Vorhersagebewertung fest, der den in den Modellmetadaten angegebenen Wert (falls vorhanden) überschreibt. Ergebnisse unter diesem Wert werden abgelehnt. Beliebiger Float Nicht festgelegt
categoryAllowlist Legt die optionale Liste der zulässigen Kategorienamen fest. Wenn die Liste nicht leer ist, werden Klassifizierungsergebnisse herausgefiltert, deren Kategoriename nicht in dieser Liste enthalten ist. Doppelte oder unbekannte Kategorienamen werden ignoriert. Diese Option schließt categoryDenylist aus. Die Verwendung beider Optionen führt zu einem Fehler. Beliebige Strings Nicht festgelegt
categoryDenylist Hiermit wird eine optionale Liste der nicht zulässigen Kategorienamen festgelegt. Wenn der Wert nicht leer ist, werden Klassifizierungsergebnisse herausgefiltert, deren Kategoriename in diesem Set enthalten ist. Doppelte oder unbekannte Kategorienamen werden ignoriert. Diese Option schließt categoryAllowlist aus. Die Verwendung beider Optionen führt zu einem Fehler. Beliebige Strings Nicht festgelegt
resultListener Legt fest, dass der Ergebnisempfänger die Klassifizierungsergebnisse asynchron empfängt, wenn sich der Bildklassifikator im Livestream-Modus befindet. Kann nur verwendet werden, wenn der Ausführungsmodus auf LIVE_STREAM festgelegt ist. Nicht festgelegt
errorListener Legt einen optionalen Fehler-Listener fest. Nicht festgelegt

Daten vorbereiten

Der Bildklassifikator funktioniert mit Bildern, Videodateien und Livestream-Videos. 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 Bildklassifikator ü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 Bildklassifikator wird die Datenvorbereitung in der Datei ImageClassifierHelper.kt ausgeführt.

Aufgabe ausführen

Sie können die classify-Funktion aufrufen, die dem aktuellen Laufmodus entspricht, um Inferenzen auszulösen. Die Image Classifier API gibt die möglichen Kategorien für das Objekt im Eingabebild oder -frame zurück.

Bild

ImageClassifierResult classifierResult = imageClassifier.classify(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.
ImageClassifierResult classifierResult =
    imageClassifier.classifyForVideo(image, frameTimestampMs);
    

Livestream

// Run inference on the frame. The classifications results will be available 
// via the `resultListener` provided in the `ImageClassifierOptions` when 
// the image classifier was created.
imageClassifier.classifyAsync(image, frameTimestampMs);
    

Wichtige Hinweise:

  • Wenn Sie die Funktion im Video- oder Livestream-Modus ausführen, müssen Sie der Aufgabe „Bildklassifikator“ auch den Zeitstempel des Eingabeframes angeben.
  • Wenn die Ausführung im Bild- oder Videomodus erfolgt, blockiert die Aufgabe „Bildklassifikator“ 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 „Bildklassifikator“ den aktuellen Thread nicht, sondern gibt sofort eine Antwort zurück. Jedes Mal, wenn die Verarbeitung eines Eingabeframes abgeschlossen ist, wird der Ergebnis-Listener mit dem Erkennungsergebnis aufgerufen. Wenn die Funktion classifyAsync aufgerufen wird, während die Aufgabe „Bildklassifikator“ gerade einen anderen Frame verarbeitet, wird der neue Eingabeframe ignoriert.

Im Beispielcode für den Bildklassifikator sind die classify-Funktionen in der Datei ImageClassifierHelper.kt definiert.

Ergebnisse verarbeiten und anzeigen

Nach der Ausführung der Inferenz gibt die Aufgabe „Bildklassifikator“ ein ImageClassifierResult-Objekt zurück, das die Liste der möglichen Kategorien für die Objekte im Eingabebild oder -frame enthält.

Im Folgenden finden Sie ein Beispiel für die Ausgabedaten dieser Aufgabe:

ImageClassifierResult:
 Classifications #0 (single classification head):
  head index: 0
  category #0:
   category name: "/m/01bwb9"
   display name: "Passer domesticus"
   score: 0.91406
   index: 671
  category #1:
   category name: "/m/01bwbt"
   display name: "Passer montanus"
   score: 0.00391
   index: 670

Dieses Ergebnis wurde mit dem Vogelklassifikator für folgende Bilder erzielt:

Nahaufnahme eines Hausspatzes

Im Beispielcode für die Bildklassifizierung werden die Ergebnisse in der Datei ClassificationResultsAdapter.kt von der Klasse ClassificationResultsAdapter verarbeitet:

fun updateResults(imageClassifierResult: ImageClassifierResult? = null) {
    categories = MutableList(adapterSize) { null }
    if (imageClassifierResult != null) {
        val sortedCategories = imageClassifierResult.classificationResult()
            .classifications()[0].categories().sortedBy { it.index() }
        val min = kotlin.math.min(sortedCategories.size, categories.size)
        for (i in 0 until min) {
            categories[i] = sortedCategories[i]
        }
    }
}