Wykrywanie obiektów w obrazach za pomocą modelu wytrenowanego przez AutoML na Androidzie

Po wytrenowaniu własnego modelu za pomocą AutoML Vision Edge możesz go używać w aplikacji do wykrywania obiektów na obrazach.

Modele wytrenowane za pomocą AutoML Vision Edge można integrować na 2 sposoby: możesz umieścić model w folderze komponentów aplikacji lub pobrać go dynamicznie z Firebase.

Opcje grupowania modeli
Pakiet w aplikacji
  • Model jest częścią pliku APK aplikacji.
  • Model jest dostępny od razu, nawet gdy urządzenie z Androidem jest offline.
  • Nie potrzeba projektu Firebase
Hostowany w Firebase
  • Hostuj model, przesyłając go do Firebase Machine Learning
  • Zmniejsza rozmiar pliku APK
  • Model jest pobierany na żądanie.
  • Push aktualizacji modelu bez ponownego publikowania aplikacji
  • Łatwe testowanie A/B za pomocą Zdalnej konfiguracji Firebase
  • Wymaga projektu Firebase

Zanim zaczniesz

  1. Jeśli chcesz pobrać model, dodaj Firebase do projektu na Androida, jeśli nie zostało to jeszcze zrobione. Nie jest to wymagane, gdy model jest w pakiecie.

  2. Dodaj zależności do biblioteki zadań TensorFlow Lite do pliku Gradle modułu na poziomie aplikacji. Jest to zwykle: app/build.gradle:

    Aby dołączyć model do aplikacji:

    dependencies {
      // ...
      // Object detection with a bundled Auto ML model
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.0.0-nightly-SNAPSHOT'
    }
    

    Aby móc dynamicznym pobierać model z Firebase, dodaj też zależność Firebase ML:

    dependencies {
      // ...
      // Object detection with an Auto ML model deployed to Firebase
      implementation platform('com.google.firebase:firebase-bom:26.1.1')
      implementation 'com.google.firebase:firebase-ml-model-interpreter'
    
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.0.0-nightly'
    }
    

1. Wczytaj model

Konfigurowanie źródła lokalnego modelu

Aby połączyć model z aplikacją:

  1. Wyodrębnij model z archiwum ZIP pobranego z konsoli Google Cloud.
  2. Dołącz model do pakietu aplikacji:
    1. Jeśli w projekcie nie masz folderu komponentów, utwórz go, klikając app/ prawym przyciskiem myszy, a następnie klikając Nowy > Folder > Folder komponentów.
    2. Skopiuj plik modelu tflite z wbudowanymi metadanymi do folderu zasobów.
  3. Aby Gradle nie kompresował pliku modelu podczas kompilowania aplikacji, dodaj do pliku build.gradle aplikacji te informacje:

    android {
        // ...
        aaptOptions {
            noCompress "tflite"
        }
    }
    

    Plik modelu zostanie dodany do pakietu aplikacji i będzie dostępny jako surowy zasób.

Skonfiguruj źródło modelu hostowanego w Firebase

Aby używać modelu hostowanego zdalnie, utwórz obiekt RemoteModel z nazwą przypisaną do modelu podczas jego publikowania:

Java

// Specify the name you assigned when you deployed the model.
FirebaseCustomRemoteModel remoteModel =
        new FirebaseCustomRemoteModel.Builder("your_model").build();

Kotlin

// Specify the name you assigned when you deployed the model.
val remoteModel =
    FirebaseCustomRemoteModel.Builder("your_model_name").build()

Następnie uruchom zadanie pobierania modelu, określając warunki, na jakich chcesz zezwolić na pobieranie. Jeśli model nie jest dostępny na urządzeniu lub jest dostępna nowsza wersja modelu, zadanie asynchronicznie pobierze model z Firebase:

Java

DownloadConditions downloadConditions = new DownloadConditions.Builder()
        .requireWifi()
        .build();
RemoteModelManager.getInstance().download(remoteModel, downloadConditions)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(@NonNull Task<Void> task) {
                // Success.
            }
        });

Kotlin

val downloadConditions = DownloadConditions.Builder()
    .requireWifi()
    .build()
RemoteModelManager.getInstance().download(remoteModel, downloadConditions)
    .addOnSuccessListener {
        // Success.
    }

Wiele aplikacji inicjuje zadanie pobierania w kodzie inicjującym, ale możesz to zrobić w dowolnym momencie, zanim zaczniesz używać modelu.

Tworzenie wykrywacza obiektów na podstawie modelu

Po skonfigurowaniu źródeł modelu utwórz obiekt ObjectDetector na podstawie jednego z nich.

Jeśli masz tylko model w pakiecie lokalnym, utwórz z niego wykrywacz obiektów na podstawie pliku modelu i skonfiguruj próg wyniku pewności, który ma być wymagany (patrz Ocenianie modelu):

Java

// Initialization
ObjectDetectorOptions options = ObjectDetectorOptions.builder()
    .setScoreThreshold(0)  // Evaluate your model in the Google Cloud console
                           // to determine an appropriate value.
    .build();
ObjectDetector objectDetector = ObjectDetector.createFromFileAndOptions(context, modelFile, options);

Kotlin

// Initialization
val options = ObjectDetectorOptions.builder()
    .setScoreThreshold(0)  // Evaluate your model in the Google Cloud console
                           // to determine an appropriate value.
    .build()
val objectDetector = ObjectDetector.createFromFileAndOptions(context, modelFile, options)

Jeśli model jest hostowany zdalnie, przed jego uruchomieniem musisz sprawdzić, czy został pobrany. Stan zadania pobierania modelu możesz sprawdzić za pomocą metody isModelDownloaded() menedżera modeli.

Chociaż musisz to potwierdzić tylko przed uruchomieniem detektora obiektów, jeśli masz model hostowany zdalnie i model wbudowany lokalnie, warto wykonać tę weryfikację podczas tworzenia instancji detektora obiektów: utwórz detektor obiektów z modelu zdalnego, jeśli został pobrany, a w przeciwnym razie – z modelu lokalnego.

Java

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener(new OnSuccessListener<Boolean>() {
            @Override
            public void onSuccess(Boolean isDownloaded) {
            }
        });

Kotlin

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener { success ->

        }

Jeśli masz tylko model hostowany zdalnie, wyłącz funkcje związane z modelem (np. wygaszaj lub ukryj część interfejsu użytkownika), dopóki nie potwierdzisz, że model został pobrany. Możesz to zrobić, dołączając listenera do metody download() menedżera modelu.

Gdy model zostanie pobrany, utwórz detektor obiektów na podstawie pliku modelu:

Java

FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
        .addOnCompleteListener(new OnCompleteListener<File>() {
            @Override
            public void onComplete(@NonNull Task<File> task) {
                File modelFile = task.getResult();
                if (modelFile != null) {
                    ObjectDetectorOptions options = ObjectDetectorOptions.builder()
                            .setScoreThreshold(0)
                            .build();
                    objectDetector = ObjectDetector.createFromFileAndOptions(
                            getApplicationContext(), modelFile.getPath(), options);
                }
            }
        });

Kotlin

FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
        .addOnSuccessListener { modelFile ->
            val options = ObjectDetectorOptions.builder()
                    .setScoreThreshold(0f)
                    .build()
            objectDetector = ObjectDetector.createFromFileAndOptions(
                    applicationContext, modelFile.path, options)
        }

2. Przygotowywanie obrazu wejściowego

Następnie dla każdego obrazu, który chcesz otagować, utwórz obiekt TensorImage na podstawie obrazu. Obiekt TensorImage możesz utworzyć z Bitmap przy użyciu metody fromBitmap:

Java

TensorImage image = TensorImage.fromBitmap(bitmap);

Kotlin

val image = TensorImage.fromBitmap(bitmap)

Jeśli dane obrazu nie są w formacie Bitmap, możesz załadować tablicę pikseli w sposób opisany w dokumentacji TensorFlow Lite.

3. Uruchom detektor obiektów

Aby wykryć obiekty na obrazie, prześlij obiekt TensorImage do metody detect() w klasie ObjectDetector.

Java

List<Detection> results = objectDetector.detect(image);

Kotlin

val results = objectDetector.detect(image)

4. Uzyskiwanie informacji o oznaczonych obiektach

Jeśli operacja wykrywania obiektów zakończy się powodzeniem, zwróci listę obiektów Detection. Każdy obiekt Detection reprezentuje coś, co zostało wykryte na obrazie. Możesz pobrać pole ograniczające i etykiety każdego obiektu.

Przykład:

Java

for (Detection result : results) {
    RectF bounds = result.getBoundingBox();
    List<Category> labels = result.getCategories();
}

Kotlin

for (result in results) {
    val bounds = result.getBoundingBox()
    val labels = result.getCategories()
}

Wskazówki dotyczące zwiększania skuteczności w czasie rzeczywistym

Jeśli chcesz oznaczać obrazy w aplikacji w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:

  • Ogranicz wywołania do etykietowania obrazów. Jeśli podczas działania mechanizmu oznaczania obrazów stanie się dostępna nowa klatka wideo, upuść ją. Przykładem jest klasa VisionProcessorBase w przykładowej aplikacji krótkiego wprowadzenia.
  • Jeśli używasz danych wyjściowych etykietowania obrazu do nakładania grafiki na obraz wejściowy, najpierw uzyskaj wynik, a następnie renderuj obraz i nałóż go w jednym kroku. Dzięki temu renderowanie na powierzchni wyświetlania będzie odbywać się tylko raz na każdą klatkę wejściową. Aby zobaczyć przykład, otwórz klasy CameraSourcePreview GraphicOverlay w przykładowej aplikacji krótkiego wprowadzenia.
  • Jeśli używasz interfejsu Camera2 API, rób zdjęcia w formacie ImageFormat.YUV_420_888.

    Jeśli używasz starszej wersji interfejsu Camera API, rób zdjęcia w formacie ImageFormat.NV21.