Przewodnik po klasyfikacji obrazów w Androidzie

Zadanie MediaPipe Image Classifier umożliwia klasyfikację obrazów. Możesz użyć tego zadania, aby określić, co obraz reprezentuje w zbiorze kategorii zdefiniowanych w czasie trenowania. Te instrukcje pokazują, jak używać klasyfikatora obrazów w aplikacjach na Androida. Dostępny jest przykładowy kod opisany w tych instrukcjach włączono GitHub

Aby zobaczyć, jak to zadanie działa, możesz obejrzeć wersję demonstracyjną w przeglądarce. Więcej informacji o funkcjach, modelach i opcjach konfiguracji zapoznaj się z Przeglądem.

Przykładowy kod

Przykładowy kod MediaPipe Tasks to prosta implementacja klasyfikatora obrazów na Androida. W tym przykładzie użyliśmy aparatu w fizycznym urządzeniu z Androidem, stale klasyfikować obiekty, a także korzystać z obrazów i filmów pochodzących galerii urządzeń do statycznego klasyfikowania obiektów.

Możesz użyć tej aplikacji jako punktu wyjścia dla własnej aplikacji na Androida lub odnieść się do niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod klasyfikatora obrazów jest hostowany GitHub

Pobieranie kodu

Poniżej znajdziesz instrukcje tworzenia lokalnej kopii przykładu. za pomocą narzędzia wiersza poleceń git.

Aby pobrać przykładowy kod:

  1. Sklonuj repozytorium git za pomocą tego polecenia:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. Opcjonalnie możesz skonfigurować instancję git tak, aby wykorzystywała rozproszony proces płatności, masz więc tylko pliki z przykładowej aplikacji Image Classifier:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_classification/android
    

Po utworzeniu lokalnej wersji przykładowego kodu możesz zaimportować projekt w Android Studio i uruchom aplikację. Instrukcje znajdziesz w Przewodnik po konfiguracji na Androida

Kluczowe elementy

Te pliki zawierają kluczowy kod dla tego obrazu przykład zastosowania klasyfikacji:

Konfiguracja

W tej sekcji opisujemy najważniejsze czynności związane z konfigurowaniem środowiska programistycznego oraz w projektach kodu, w których używa się klasyfikatora obrazów. Ogólne informacje na temat: skonfigurować środowisko programistyczne do korzystania z zadań MediaPipe, w tym wymagań wersji platformy, patrz Przewodnik po konfiguracji na Androida

Zależności

Klasyfikator obrazów używa biblioteki com.google.mediapipe:tasks-vision. Dodaj to zależności od pliku build.gradle Projekt tworzenia aplikacji na Androida. Zaimportuj wymagane zależności za pomocą: ten kod:

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

Model

Zadanie MediaPipe Image Classifier wymaga wytrenowanego modelu zgodnego z tym zadanie. Więcej informacji o dostępnych wytrenowanych modelach na potrzeby klasyfikatora obrazów znajdziesz tutaj zapoznaj się z omówieniem zadania sekcją Modele.

Wybierz i pobierz model, a następnie zapisz go w katalogu projektu:

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

Użyj metody BaseOptions.Builder.setModelAssetPath(), aby podać ścieżkę używane przez model. Tę metodę przywołaliśmy w przykładzie kodu w następnym .

W przykładowy kod klasyfikatora obrazów, model jest zdefiniowany w ImageClassifierHelper.kt .

Tworzenie zadania

Do utworzenia zadania możesz użyć funkcji createFromOptions. Funkcja createFromOptions akceptuje opcje konfiguracji, w tym uruchomione tryb, język wyświetlanych nazw, maksymalna liczba wyników, próg ufności, oraz listy dozwolonych lub odrzuconych kategorii. Więcej informacji o konfiguracji Więcej informacji znajdziesz w artykule Omówienie konfiguracji.

Zadanie Klasyfikator obrazów obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i transmisje wideo na żywo. Musisz określić tryb działania odpowiadający parametrowi typ danych wejściowych podczas tworzenia zadania. Wybierz kartę odpowiadającą typ danych wejściowych, aby zobaczyć, jak utworzyć zadanie i uruchomić wnioskowanie.

Obraz

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

Wideo

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

Transmisja na żywo

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)
    

Przykładowa implementacja kodu klasyfikatora obrazów pozwala użytkownikowi przełączać się między i przetwarzania danych. Takie podejście sprawia, że kod tworzenia zadań jest bardziej skomplikowany, może nie być odpowiednia w Twoim przypadku użycia. Możesz zobaczyć ten kod w Funkcja setupImageClassifier() ImageClassifierHelper.kt. .

Opcje konfiguracji

To zadanie zawiera te opcje konfiguracji aplikacji na Androida:

Nazwa opcji Opis Zakres wartości Wartość domyślna
runningMode Ustawia tryb działania zadania. Są trzy tryby:

IMAGE: tryb wprowadzania pojedynczego obrazu.

WIDEO: tryb zdekodowanych klatek filmu.

LIVE_STREAM: tryb transmisji danych wejściowych na przykład z kamery. W tym trybie detektor wyników musi mieć wartość wywołano, aby skonfigurować detektor i otrzymywać wyniki asynchronicznie.
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
displayNamesLocale Ustawia język etykiet, które mają być używane w przypadku nazw wyświetlanych w kolumnie metadane modelu zadania, jeśli są dostępne. Wartość domyślna to en dla Angielski. Do metadanych modelu niestandardowego możesz dodać zlokalizowane etykiety za pomocą interfejsu TensorFlow Lite Metadata Writer API. Kod języka en
maxResults Ustawia opcjonalną maksymalną liczbę wyników klasyfikacji na . Jeśli < 0 – zostaną zwrócone wszystkie dostępne wyniki. Dowolne liczby dodatnie -1
scoreThreshold Ustawia próg wyniku prognozy, który zastępuje próg podany w polu metadane modelu (jeśli występują). Wyniki poniżej tej wartości zostały odrzucone. Dowolna liczba zmiennoprzecinkowa Nie ustawiono
categoryAllowlist Ustawia opcjonalną listę dozwolonych nazw kategorii. Jeśli pole nie jest puste, wyniki klasyfikacji, których nazwa kategorii nie znajduje się w tym zbiorze, zostaną zostały odfiltrowane. Zduplikowane lub nieznane nazwy kategorii są ignorowane. Ta opcja nie działa z usługą categoryDenylist i korzysta z funkcji skutkuje to błędem. Dowolne ciągi Nie ustawiono
categoryDenylist Ustawia opcjonalną listę nazw kategorii, które nie są dozwolone. Jeśli niepuste, wyniki klasyfikacji, których nazwa kategorii znajduje się w tym zbiorze, zostaną odfiltrowane na zewnątrz. Zduplikowane lub nieznane nazwy kategorii są ignorowane. Ta opcja jest wzajemna tylko w polu categoryAllowlist, co spowoduje błąd. Dowolne ciągi Nie ustawiono
resultListener Konfiguruje detektor wyników, aby otrzymywać wyniki klasyfikacji asynchronicznie, gdy w transmisji na żywo działa Klasyfikator obrazów. i trybu uzyskiwania zgody. Tej opcji można używać tylko wtedy, gdy tryb działania jest ustawiony na LIVE_STREAM Nie dotyczy Nie ustawiono
errorListener Ustawia opcjonalny detektor błędów. Nie dotyczy Nie ustawiono

Przygotuj dane

Klasyfikator obrazów działa z obrazami, plikami wideo i transmisjami wideo na żywo. Zadanie obsługuje wstępne przetwarzanie danych wejściowych, w tym zmianę rozmiaru, obrót i wartość ich normalizację.

Musisz przekonwertować obraz lub klatkę wejściową do com.google.mediapipe.framework.image.MPImage obiekt przed przekazaniem do Klasyfikator obrazów.

Obraz

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

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

Transmisja na żywo

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

W Przykładowy kod klasyfikatora obrazów. Przygotowanie danych odbywa się tutaj: ImageClassifierHelper.kt .

Uruchamianie zadania

Aby aktywować wnioskowanie, możesz wywołać funkcję classify odpowiadającą Twojemu trybowi działającemu. Interfejs Image Classifier API zwraca możliwe kategorie obiektu w obrazie lub ramce wejściowej.

Obraz

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

Transmisja na żywo

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

Pamiętaj:

  • Gdy pracujesz w trybie wideo lub w trybie transmisji na żywo, musisz też podaj sygnaturę czasową ramki wejściowej do zadania Klasyfikator obrazów.
  • W trybie obrazu lub wideo zadanie Klasyfikator obrazów blokuje bieżący wątek do czasu zakończenia przetwarzania obrazu wejściowego lub ramki. Aby uniknąć blokowania interfejsu użytkownika, wykonaj przetwarzanie w w wątku w tle.
  • W trybie transmisji na żywo zadanie klasyfikacji obrazów nie jest blokowane. w bieżącym wątku, ale wraca natychmiast. Wywoła swój wynik detektor z wynikiem wykrywania za każdym razem, gdy zakończy przetwarzanie ramki wejściowej. Jeśli funkcja classifyAsync jest wywoływana przy użyciu klasyfikatora obrazów zadanie jest zajęte przetwarzaniem innej ramki, zadanie zignoruje nową ramkę wejściową.

W Przykładowy kod klasyfikatora obrazów, funkcje classify są zdefiniowane w ImageClassifierHelper.kt. .

Obsługa i wyświetlanie wyników

Po uruchomieniu wnioskowania zadanie Klasyfikator obrazów zwraca obiekt ImageClassifierResult zawierający listę możliwych kategorii obiektów w obrazie lub ramce wejściowej.

Poniżej znajdziesz przykładowe dane wyjściowe tego zadania:

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

Ten wynik uzyskano po uruchomieniu Bird Classifier. dnia:

W Przykładowy kod klasyfikatora obrazów, klasa ClassificationResultsAdapter w tagu ClassificationResultsAdapter.kt. obsługuje wyniki:

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]
        }
    }
}