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 zasobów aplikacji lub pobrać go dynamicznie z Firebase.

Opcje grupowania modeli
W pakiecie w aplikacji
  • Model jest częścią pliku APK aplikacji.
  • Model jest dostępny od razu, nawet gdy urządzenie z Androidem jest offline.
  • Nie musisz tworzyć 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 połączyć model z aplikacją:

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

    Aby móc dynamicznie 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 z komponentami, utwórz go, klikając prawym przyciskiem folder app/, a następnie 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 dołączony do pakietu aplikacji i będzie dostępny jako surowy zasób.

Konfigurowanie źródła modelu hostowanego w Firebase

Aby użyć modelu hostowanego zdalnie, utwórz obiekt RemoteModel, podając 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 pobiera go asynchronicznie 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ć, korzystając z 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. Przygotuj obraz wejściowy

Następnie dla każdego obrazu, który chcesz otagować, utwórz obiekt TensorImage. Obiekt TensorImage możesz utworzyć z obiektu Bitmap, korzystając z 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. Uruchamianie detektora 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 etykietowania obrazu pojawi się nowa klatka wideo, odrzuć 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. W ten sposób renderujesz na powierzchni wyświetlacza tylko raz w przypadku każdej ramki wejściowej. 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.