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 używać go w aplikacji do wykrywania obiektów na obrazach.

Modele wytrenowane w AutoML Vision Edge można zintegrować na 2 sposoby: możesz dołączyć model, umieszczając go w folderze zasobów aplikacji, lub możesz pobrać go dynamicznie z Firebase.

Opcje pakietów modeli
Dołączone do aplikacji
  • Model jest częścią pliku APK aplikacji.
  • Model jest dostępny od razu, nawet gdy urządzenie z Androidem jest offline.
  • Nie musisz mieć projektu Firebase
Hostowane w Firebase
  • Hostuj model, przesyłając go do Firebase Machine Learning.
  • Zmniejsza rozmiar pliku APK
  • Model jest pobierany na żądanie
  • Wysyłanie aktualizacji modelu bez ponownego publikowania aplikacji
  • Łatwe testy A/B dzięki Zdalnej konfiguracji Firebase
  • Wymaga projektu Firebase

Zanim zaczniesz

  1. Jeśli chcesz pobrać model, pamiętaj, aby dodać Firebase do projektu na Androida, jeśli jeszcze tego nie zrobisz. Nie jest to wymagane, gdy dołączasz model.

  2. Dodaj zależności biblioteki zadań TensorFlow Lite do pliku Gradle na poziomie aplikacji modułu, który zwykle znajduje się w tym miejscu: app/build.gradle

    W przypadku łączenia modelu z aplikacją:

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

    Aby 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. Wczytywanie modelu

Konfigurowanie źródła modelu lokalnego

Aby połączyć model z aplikacją:

  1. Wyodrębnij model z pobranego z Google Cloudkonsoli archiwum ZIP.
  2. Dołącz model do pakietu aplikacji:
    1. Jeśli w projekcie nie masz folderu z komponentami, utwórz go, klikając prawym przyciskiem myszy folder app/, a następnie wybierając Nowy > Folder > Folder z komponentami.
    2. Skopiuj plik modelu tflite z umieszczonymi metadanymi do folderu assets.
  3. Aby mieć pewność, że Gradle nie skompresuje pliku modelu podczas kompilowania aplikacji, dodaj do pliku build.gradle ten ciąg:

    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 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 rozpocznij pobieranie modelu, określając warunki, w których chcesz zezwolić na pobieranie. Jeśli modelu nie ma na urządzeniu lub dostępna jest nowsza wersja, 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 rozpoczyna pobieranie w kodzie inicjującym, ale możesz to zrobić w dowolnym momencie przed użyciem modelu.

Tworzenie detektora obiektów na podstawie modelu

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

Jeśli masz tylko model dołączony lokalnie, utwórz detektor obiektów z pliku modelu i skonfiguruj próg wyniku ufności, który chcesz wymagać (patrz Ocena 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 masz model 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 potwierdzić to tylko przed uruchomieniem detektora obiektów, jeśli masz zarówno model hostowany zdalnie, jak i model dołączony lokalnie, warto przeprowadzić to sprawdzenie 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. wyszarz lub ukryj część interfejsu, dopóki nie potwierdzisz, że model został pobrany. Możesz to zrobić, dołączając odbiornik do metody download() menedżera modeli.

Gdy model zostanie pobrany, utwórz detektor obiektów z 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 oznaczyć etykietą, utwórz obiekt TensorImage z obrazu. Możesz utworzyć obiekt TensorImage z obiektu Bitmap za pomocą 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 wczytać tablicę pikseli zgodnie z opisem w dokumentacji TensorFlow Lite.

3. Uruchamianie detektora obiektów

Aby wykryć obiekty na obrazie, przekaż obiekt TensorImage do metody detect() klasy 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 się powiedzie, zwraca listę obiektów Detection. Każdy obiekt Detection reprezentuje coś, co zostało wykryte na obrazie. Możesz uzyskać ramkę ograniczającą każdego obiektu i jego etykiety.

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 działającej w czasie rzeczywistym, postępuj zgodnie z tymi wskazówkami, aby uzyskać najlepszą liczbę klatek na sekundę:

  • Ograniczanie liczby wywołań narzędzia do etykietowania obrazów. Jeśli podczas działania narzędzia do etykietowania obrazów pojawi się nowa klatka wideo, odrzuć ją. Przykład znajdziesz w klasie VisionProcessorBase w przykładowej aplikacji z krótkiego wprowadzenia.
  • Jeśli używasz danych wyjściowych narzędzia do etykietowania obrazów, aby nakładać grafikę na obraz wejściowy, najpierw uzyskaj wynik, a następnie wyrenderuj obraz i nałóż na niego grafikę w jednym kroku. Dzięki temu renderowanie na powierzchnię wyświetlania odbywa się tylko raz dla każdej ramki wejściowej. Przykład znajdziesz w klasach CameraSourcePreview GraphicOverlay w przykładowej aplikacji z krótkiego wprowadzenia.
  • Jeśli używasz interfejsu Camera2 API, rób zdjęcia w formacie ImageFormat.YUV_420_888.

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