Zadanie MediaPipe Image Classifier umożliwia klasyfikowanie obrazów. Za pomocą tego zadania możesz określić, co przedstawia obraz spośród zestawu kategorii zdefiniowanych podczas treningu. Z tych instrukcji dowiesz się, jak korzystać z klasyfikatora obrazów w aplikacjach na Androida. Przykładowy kod opisany w tych instrukcjach jest dostępny na GitHub.
Aby zobaczyć, jak to zadanie działa w praktyce, obejrzyj prezentację internetową. Więcej informacji o możliwościach, modelach i opcjach konfiguracji związanych z tym zadaniem znajdziesz w sekcji Omówienie.
Przykładowy kod
Przykładowy kod MediaPipe Tasks to prosta implementacja aplikacji do klasyfikowania obrazów na Androida. W tym przykładzie do ciągłego klasyfikowania obiektów używana jest kamera na fizycznym urządzeniu z Androidem. Można też używać obrazów i filmów z galerii urządzenia do statycznego klasyfikowania obiektów.
Możesz użyć tej aplikacji jako punktu wyjścia do stworzenia własnej aplikacji na Androida lub skorzystać z niej podczas modyfikowania istniejącej aplikacji. Przykładowy kod usługi Image Classifier jest hostowany na GitHub.
Pobieranie kodu
Z tych instrukcji 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, aby używać rzadkiego sprawdzania, dzięki czemu będziesz mieć tylko pliki przykładowej aplikacji Image Classifier:
cd mediapipe-samples git sparse-checkout init --cone git sparse-checkout set examples/image_classification/android
 
Po utworzeniu lokalnej wersji przykładowego kodu możesz zaimportować projekt do Android Studio i uruchomić aplikację. Instrukcje znajdziesz w przewodniku konfiguracji Androida.
Kluczowe komponenty
Te pliki zawierają kluczowy kod przykładowej aplikacji do klasyfikacji obrazów:
- ImageClassifierHelper.kt – inicjalizuje klasyfikator obrazów i obsługuje model oraz wybór delegata.
 - MainActivity.kt – implementuje aplikację, w tym wywołanie funkcji 
ImageClassificationHelperiClassificationResultsAdapter. - ClassificationResultsAdapter.kt – obsługuje i formatuje wyniki.
 
Konfiguracja
W tej sekcji opisaliśmy najważniejsze kroki konfigurowania środowiska programistycznego i projektów kodu na potrzeby korzystania z klasyfikatora obrazów. Ogólne informacje o konfigurowaniu środowiska programistycznego do korzystania z zadań MediaPipe, w tym wymagania dotyczące wersji platformy, znajdziesz w przewodniku konfiguracji na Androida.
Zależności
Klasyfikator obrazów korzysta z biblioteki com.google.mediapipe:tasks-vision. Dodaj tę zależność do pliku build.gradle w projekcie tworzenia aplikacji na Androida. Zaimportuj wymagane zależności za pomocą tego kodu:
dependencies {
    ...
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}
Model
Zadanie MediaPipe Image Classifier wymaga wytrenowanego modelu zgodnego z tym zadaniem. Więcej informacji o dostępnych wytrenowanych modelach usługi Image Classifier znajdziesz w sekcji Modele w omówieniu zadania.
Wybierz i pobierz model, a potem zapisz go w katalogu projektu:
<dev-project-root>/src/main/assets
Użyj metody BaseOptions.Builder.setModelAssetPath(), aby określić ścieżkę używaną przez model. Ta metoda jest wywoływana w przykładowym kodzie w następnej sekcji.
W przykładowym kodzie klasyfikatora obrazów model jest zdefiniowany w pliku ImageClassifierHelper.kt.
Tworzenie zadania
Do utworzenia zadania możesz użyć funkcji createFromOptions. Funkcja createFromOptions akceptuje opcje konfiguracji, w tym tryb działania, język wyświetlania nazw, maksymalną liczbę wyników, próg ufności oraz listę dozwolonych lub niedozwolonych kategorii. Więcej informacji o opcjach konfiguracji znajdziesz w artykule Omówienie konfiguracji.
Zadanie klasyfikatora obrazów obsługuje 3 typy danych wejściowych: obrazy, pliki wideo i transmisje wideo na żywo. Podczas tworzenia zadania musisz określić tryb wykonywania odpowiadający typowi danych wejściowych. Wybierz kartę odpowiadającą typowi danych wejściowych, aby dowiedzieć się, jak utworzyć zadanie i przeprowadzić 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)
Implementacja przykładowego kodu usługi Image Classifier pozwala użytkownikowi przełączać się między trybami przetwarzania. Takie podejście skomplikuje kod tworzący zadanie i może nie być odpowiednie w Twoim przypadku. Ten kod znajdziesz w funkcji setupImageClassifier() w pliku ImageClassifierHelper.kt.
Opcje konfiguracji
W tym zadaniu dostępne są te opcje konfiguracji aplikacji na Androida:
| Nazwa opcji | Opis | Zakres wartości | Wartość domyślna | 
|---|---|---|---|
runningMode | 
      Ustawia tryb działania zadania. Dostępne są 3 tryby: OBRAZ: tryb dla pojedynczych obrazów wejściowych. FILM: tryb dekodowanych klatek filmu. LIVE_STREAM: tryb transmisji na żywo danych wejściowych, takich jak dane z kamery. W tym trybie należy wywołać metodę resultListener, aby skonfigurować odbiornik, który będzie asynchronicznie odbierał wyniki.  | 
      
      {IMAGE, VIDEO, LIVE_STREAM} | 
      IMAGE | 
      
      
    
displayNamesLocale | 
      Określa język etykiet, których należy używać do wyświetlanych nazw podanych w metadanych modelu zadania (jeśli są dostępne). Wartość domyślna to en w przypadku języka angielskiego. Możesz dodawać zlokalizowane etykiety do metadanych modelu niestandardowego, korzystając z interfejsu TensorFlow Lite Metadata Writer API. |  
      Kod języka | en | 
maxResults | 
      Określa opcjonalną maksymalną liczbę najlepszych wyników klasyfikacji do zwrócenia. Jeśli wartość jest mniejsza od 0, zwracane są wszystkie dostępne wyniki. | dowolne liczby dodatnie. | -1 | 
    
scoreThreshold | 
      Ustawia próg wyniku prognozy, który zastępuje próg podany w metadanych modelu (jeśli takie istnieją). Wyniki poniżej tej wartości są odrzucane. | Dowolna liczba zmiennych typu float | Nie ustawiono | 
categoryAllowlist | 
      Ustawia opcjonalną listę dozwolonych nazw kategorii. Jeśli wyniki klasyfikacji nie są puste, a nazwa kategorii nie znajduje się w tym zbiorze, zostaną odfiltrowane. Powtarzające się lub nieznane nazwy kategorii są ignorowane.
Ta opcja jest wzajemnie wykluczająca się z opcją categoryDenylist. Użycie obu spowoduje błąd. | 
      dowolne ciągi znaków; | Nie ustawiono | 
categoryDenylist | 
      Ustawia opcjonalną listę nazw kategorii, które są niedozwolone. Jeśli nie jest pusty, wyniki klasyfikacji, których nazwa kategorii znajduje się w tym zbiorze, zostaną odfiltrowane. Powtarzające się lub nieznane nazwy kategorii są ignorowane. Ta opcja jest wzajemnie wykluczająca się z opcją categoryAllowlist, a użycie obu spowoduje błąd. | 
      dowolne ciągi znaków; | Nie ustawiono | 
resultListener | 
      Spowoduje, że odbiorca wyników będzie otrzymywać wyniki klasyfikacji asynchronicznie, gdy klasyfikator obrazów będzie w trybie transmisji na żywo. Można go używać tylko wtedy, gdy tryb działania ma wartość LIVE_STREAM. | 
      Nie dotyczy | Nie ustawiono | 
errorListener | 
      Ustawia opcjonalny odbiornik błędów. | Nie dotyczy | Nie ustawiono | 
Przygotuj dane
Klasyfikator obrazów działa z obrazami, plikami wideo i transmisjami na żywo. Zadanie to obsługuje wstępną obróbkę danych wejściowych, w tym zmianę rozmiaru, obrót i normalizację wartości.
Przed przekazaniem go do usługi Image Classifier musisz przekonwertować podany obraz lub kadr 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 usługi Image Classifier przygotowanie danych odbywa się w pliku ImageClassifierHelper.kt.
Uruchamianie zadania
Aby wywołać wnioskowanie, możesz wywołać funkcję classify odpowiadającą bieżącemu trybowi działania. Interfejs API klasyfikatora obrazu zwraca możliwe kategorie obiektu na obrazie wejściowym lub w ramce.
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:
- W trybie wideo lub transmisji na żywo musisz też podać zadaniu klasyfikatora obrazów sygnaturę czasową ramki wejściowej.
 - W trybie obrazu lub wideo zadanie klasyfikatora obrazów blokuje bieżący wątek, dopóki nie przetworzy wejściowego obrazu lub klatki. Aby uniknąć blokowania interfejsu użytkownika, przeprowadź przetwarzanie w wątku w tle.
 - W trybie transmisji na żywo zadanie klasyfikatora obrazów nie blokuje bieżącego wątku, ale zwraca wynik natychmiast. Za każdym razem, gdy zakończy przetwarzanie ramki wejściowej, wywoła swojego słuchacza z wynikiem wykrywania. Jeśli funkcja 
classifyAsynczostanie wywołana, gdy zadanie Klasyfikator obrazów przetwarza inny kadr, zadanie zignoruje nowy kadr wejściowy. 
W przykładowym kodzie usługi Image Classifier funkcje classify są zdefiniowane w pliku ImageClassifierHelper.kt.
Obsługa i wyświetlanie wyników
Po przeprowadzeniu wnioskowania zadanie Klasyfikator obrazów zwraca obiekt ImageClassifierResult, który zawiera listę możliwych kategorii obiektów na obrazie lub klatce wejściowej.
Poniżej znajdziesz przykład danych wyjściowych z 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 został uzyskany przez uruchomienie Klasyfikatora ptaków w przypadku:
 
W przykładowym kodzie usługi Image Classifier klasa ClassificationResultsAdapter w pliku 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]
        }
    }
}