Wykrywanie obiektów za pomocą Androida

W tym samouczku pokazano, jak zbudować aplikację na Androida przy użyciu TensorFlow Lite, aby stale wykrywać obiekty w klatkach zarejestrowanych przez kamerę urządzenia. Ta aplikacja jest przeznaczona na fizyczne urządzenie z systemem Android. Jeśli aktualizujesz istniejący projekt, możesz użyć przykładowego kodu jako odniesienia i przejść do instrukcji modyfikowania projektu .

Animowane demo wykrywania obiektów

Przegląd wykrywania obiektów

Wykrywanie obiektów to zadanie uczenia maszynowego polegające na identyfikowaniu obecności i lokalizacji wielu klas obiektów na obrazie. Model wykrywania obiektów jest szkolony na zestawie danych zawierającym zestaw znanych obiektów.

Wyszkolony model otrzymuje ramki obrazu jako dane wejściowe i próbuje kategoryzować elementy obrazów na podstawie zestawu znanych klas, które miał rozpoznawać. Dla każdej ramki obrazu model wykrywania obiektów generuje listę wykrytych obiektów, położenie ramki ograniczającej każdy obiekt oraz wynik wskazujący pewność, że obiekt został prawidłowo sklasyfikowany.

Modele i zbiór danych

W tym samouczku zastosowano modele wyszkolone przy użyciu zestawu danych COCO . COCO to wielkoskalowy zbiór danych do wykrywania obiektów, który zawiera 330 tys. obrazów, 1,5 miliona instancji obiektów i 80 kategorii obiektów.

Masz możliwość użycia jednego z następujących wstępnie wytrenowanych modeli:

  • EfficientDet-Lite0 [Zalecane] – lekki model wykrywania obiektów z ekstraktorem cech BiFPN, predyktorem współdzielonego pudełka i utratą ogniskowej. mAP (średnia średnia precyzja) dla zbioru danych walidacyjnych COCO 2017 wynosi 25,69%.

  • EfficientDet-Lite1 - średniej wielkości model detekcji obiektów EfficientDet. mAP dla zbioru danych walidacyjnych COCO 2017 wynosi 30,55%.

  • EfficientDet-Lite2 - większy model wykrywania obiektów EfficientDet. mAP dla zbioru danych walidacyjnych COCO 2017 wynosi 33,97%.

  • MobileNetV1-SSD – niezwykle lekki model zoptymalizowany do współpracy z TensorFlow Lite w celu wykrywania obiektów. mAP dla zbioru danych walidacyjnych COCO 2017 wynosi 21%.

W tym samouczku model EfficientDet-Lite0 zapewnia dobrą równowagę między rozmiarem a dokładnością.

Pobieraniem, wyodrębnianiem i umieszczaniem modeli w folderze zasobów zarządza automatycznie plik download.gradle , który jest uruchamiany w czasie kompilacji. Nie musisz ręcznie pobierać modeli TFLite do projektu.

Przykład konfiguracji i uruchomienia

Aby skonfigurować aplikację do wykrywania obiektów, pobierz próbkę z GitHub i uruchom ją za pomocą Android Studio . W poniższych sekcjach tego samouczka omówiono odpowiednie sekcje przykładowego kodu, dzięki czemu można je zastosować do własnych aplikacji na Androida.

Wymagania systemowe

  • Android Studio w wersji 2021.1.1 (Bumblebee) lub nowszej.
  • Android SDK w wersji 31 ​​lub nowszej
  • Urządzenie z systemem Android z minimalną wersją systemu operacyjnego SDK 24 (Android 7.0 - Nougat) z włączonym trybem programisty.

Pobierz przykładowy kod

Utwórz lokalną kopię przykładowego kodu. Użyjesz tego kodu, aby utworzyć projekt w Android Studio i uruchomić przykładową aplikację.

Aby sklonować i skonfigurować przykładowy kod:

  1. Sklonuj repozytorium git
    git clone https://github.com/tensorflow/examples.git
    
  2. Opcjonalnie skonfiguruj swoją instancję git tak, aby korzystała z rzadkiego pobierania, aby mieć tylko pliki dla przykładowej aplikacji do wykrywania obiektów:
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/object_detection/android
    

Zaimportuj i uruchom projekt

Utwórz projekt na podstawie pobranego przykładowego kodu, skompiluj projekt, a następnie uruchom go.

Aby zaimportować i zbudować przykładowy projekt kodu:

  1. Uruchom Android Studio .
  2. W Android Studio wybierz opcję Plik > Nowy > Importuj projekt .
  3. Przejdź do przykładowego katalogu kodu zawierającego plik build.gradle ( .../examples/lite/examples/object_detection/android/build.gradle ) i wybierz ten katalog.
  4. Jeśli Android Studio zażąda synchronizacji stopniowej, wybierz OK.
  5. Upewnij się, że Twoje urządzenie z Androidem jest podłączone do komputera i włączony jest tryb programisty. Kliknij zieloną strzałkę Run .

Jeśli wybierzesz właściwy katalog, Android Studio utworzy nowy projekt i go zbuduje. Ten proces może zająć kilka minut, w zależności od szybkości komputera i tego, czy korzystałeś z Android Studio w innych projektach. Po zakończeniu kompilacji Android Studio wyświetla komunikat BUILD SUCCESSFUL w panelu stanu wyników kompilacji .

Opcjonalnie: Aby naprawić błędy kompilacji, aktualizując wersję wtyczki Androida:

  1. Otwórz plik build.gradle w katalogu projektu.
  2. Zmień wersję narzędzi Androida w następujący sposób:

    // from: classpath
    'com.android.tools.build:gradle:4.2.2'
    // to: classpath
    'com.android.tools.build:gradle:4.1.2'
    
  3. Zsynchronizuj projekt, wybierając: Plik > Synchronizuj projekt z plikami Gradle .

Aby uruchomić projekt:

  1. W Android Studio uruchom projekt, wybierając opcję Uruchom > Uruchom… .
  2. Wybierz podłączone urządzenie z Androidem i kamerą, aby przetestować aplikację.

W kolejnych sekcjach przedstawiono modyfikacje, które należy wprowadzić w istniejącym projekcie, aby dodać tę funkcjonalność do własnej aplikacji, używając tej przykładowej aplikacji jako punktu odniesienia.

Dodaj zależności projektu

We własnej aplikacji musisz dodać określone zależności projektu, aby uruchomić modele uczenia maszynowego TensorFlow Lite i uzyskać dostęp do funkcji narzędziowych, które konwertują dane, takie jak obrazy, do formatu danych tensorowych, który może być przetwarzany przez używany model.

Przykładowa aplikacja wykorzystuje bibliotekę zadań TensorFlow Lite do celów wizyjnych , aby umożliwić wykonanie modelu uczenia maszynowego polegającego na wykrywaniu obiektów. Poniższe instrukcje wyjaśniają, jak dodać wymagane zależności bibliotek do własnego projektu aplikacji dla systemu Android.

Poniższe instrukcje wyjaśniają, jak dodać wymagane zależności projektu i modułu do własnego projektu aplikacji dla systemu Android.

Aby dodać zależności modułów:

  1. W module korzystającym z TensorFlow Lite zaktualizuj plik build.gradle modułu, aby uwzględnić następujące zależności. W przykładowym kodzie plik ten znajduje się tutaj: ...examples/lite/examples/object_detection/android/app/build.gradle ( odniesienie do kodu )

    dependencies {
      ...
      implementation 'org.tensorflow:tensorflow-lite-task-vision:0.4.0'
      // Import the GPU delegate plugin Library for GPU inference
      implementation 'org.tensorflow:tensorflow-lite-gpu-delegate-plugin:0.4.0'
      implementation 'org.tensorflow:tensorflow-lite-gpu:2.9.0'
    }
    

    Projekt musi zawierać bibliotekę zadań Vision ( tensorflow-lite-task-vision ). Biblioteka jednostek przetwarzania grafiki (GPU) ( tensorflow-lite-gpu-delegate-plugin ) zapewnia infrastrukturę do uruchamiania aplikacji na GPU, a Delegate ( tensorflow-lite-gpu ) udostępnia listę kompatybilności.

  2. W Android Studio zsynchronizuj zależności projektu, wybierając: Plik > Synchronizuj projekt z plikami Gradle .

Zainicjuj model ML

W aplikacji na Androida musisz zainicjować model uczenia maszynowego TensorFlow Lite z parametrami, zanim uruchomisz prognozy z modelem. Te parametry inicjalizacji są spójne we wszystkich modelach wykrywania obiektów i mogą obejmować ustawienia, takie jak minimalne progi dokładności przewidywań.

Model TensorFlow Lite zawiera plik .tflite zawierający kod modelu i często zawiera plik etykiet zawierający nazwy klas przewidywanych przez model. W przypadku detekcji obiektów klasami są obiekty takie jak osoba, pies, kot czy samochód.

W tym przykładzie pobieranych jest kilka modeli określonych w download_models.gradle , a klasa ObjectDetectorHelper udostępnia selektor modeli:

val modelName =
  when (currentModel) {
    MODEL_MOBILENETV1 -> "mobilenetv1.tflite"
    MODEL_EFFICIENTDETV0 -> "efficientdet-lite0.tflite"
    MODEL_EFFICIENTDETV1 -> "efficientdet-lite1.tflite"
    MODEL_EFFICIENTDETV2 -> "efficientdet-lite2.tflite"
    else -> "mobilenetv1.tflite"
  }

Aby zainicjować model w aplikacji:

  1. Dodaj plik modelu .tflite do katalogu src/main/assets swojego projektu deweloperskiego, na przykład: EfficientDet-Lite0 .
  2. Ustaw zmienną statyczną dla nazwy pliku modelu. W przykładowej aplikacji ustaw zmienną modelName na MODEL_EFFICIENTDETV0 , aby użyć modelu wykrywania EfficientDet-Lite0.
  3. Ustaw opcje modelu, takie jak próg przewidywania, rozmiar zestawu wyników i opcjonalnie delegaty przyspieszenia sprzętowego:

    val optionsBuilder =
      ObjectDetector.ObjectDetectorOptions.builder()
        .setScoreThreshold(threshold)
        .setMaxResults(maxResults)
    
  4. Użyj ustawień z tego obiektu, aby skonstruować obiekt TensorFlow Lite ObjectDetector zawierający model:

    objectDetector =
      ObjectDetector.createFromFileAndOptions(
        context, modelName, optionsBuilder.build())
    

setupObjectDetector konfiguruje następujące parametry modelu:

  • Próg detekcji
  • Maksymalna liczba wyników wykrywania
  • Liczba wątków przetwarzania do wykorzystania ( BaseOptions.builder().setNumThreads(numThreads) )
  • Rzeczywisty model ( modelName )
  • Obiekt ObjectDetector ( objectDetector )

Skonfiguruj akcelerator sprzętowy

Podczas inicjowania modelu TensorFlow Lite w aplikacji możesz użyć funkcji przyspieszania sprzętowego, aby przyspieszyć obliczenia predykcyjne modelu.

Delegaci TensorFlow Lite to moduły oprogramowania, które przyspieszają wykonywanie modeli uczenia maszynowego przy użyciu specjalistycznego sprzętu przetwarzającego na urządzeniu mobilnym, takiego jak jednostki przetwarzania grafiki (GPU), jednostki przetwarzania Tensor (TPU) i procesory sygnału cyfrowego (DSP). Zalecane jest używanie delegatów do uruchamiania modeli TensorFlow Lite, ale nie jest to wymagane.

Detektor obiektów jest inicjowany przy użyciu bieżących ustawień wątku, który go używa. Można używać delegatów CPU i NNAPI z detektorami utworzonymi w wątku głównym i używanymi w wątku tła, ale wątek, który zainicjował detektor, musi używać delegata GPU.

Delegaty są ustawiane w funkcji ObjectDetectionHelper.setupObjectDetector() :

when (currentDelegate) {
    DELEGATE_CPU -> {
        // Default
    }
    DELEGATE_GPU -> {
        if (CompatibilityList().isDelegateSupportedOnThisDevice) {
            baseOptionsBuilder.useGpu()
        } else {
            objectDetectorListener?.onError("GPU is not supported on this device")
        }
    }
    DELEGATE_NNAPI -> {
        baseOptionsBuilder.useNnapi()
    }
}

Aby uzyskać więcej informacji na temat używania delegatów akceleracji sprzętowej z TensorFlow Lite, zobacz Delegaty TensorFlow Lite .

Przygotuj dane do modelu

W aplikacji na Androida kod dostarcza dane do modelu w celu interpretacji, przekształcając istniejące dane, takie jak klatki obrazu, w format danych Tensor, który może być przetwarzany przez model. Dane w Tensorze przekazywane do modelu muszą mieć określone wymiary lub kształt pasujący do formatu danych używanych do uczenia modelu.

Model EfficientDet-Lite0 użyty w tym przykładzie kodu akceptuje tensory reprezentujące obrazy o wymiarach 320 x 320 z trzema kanałami (czerwony, niebieski i zielony) na piksel. Każda wartość w tensorze to pojedynczy bajt z zakresu od 0 do 255. Aby zatem uruchomić prognozy dla nowych obrazów, aplikacja musi przekształcić dane obrazu w obiekty danych Tensor o odpowiednim rozmiarze i kształcie. Interfejs API Vision Library zadań TensorFlow Lite obsługuje transformację danych za Ciebie.

Aplikacja używa obiektu ImageAnalysis do pobierania obrazów z aparatu. Obiekt ten wywołuje funkcję detectObject z bitmapą z kamery. Rozmiar danych jest automatycznie zmieniany i obracany przez ImageProcessor , tak aby spełniały wymagania dotyczące danych obrazu modelu. Obraz jest następnie tłumaczony na obiekt TensorImage .

Aby przygotować dane z podsystemu kamery do przetwarzania przez model ML:

  1. Zbuduj obiekt ImageAnalysis , aby wyodrębnić obrazy w wymaganym formacie:

    imageAnalyzer =
        ImageAnalysis.Builder()
            .setTargetAspectRatio(AspectRatio.RATIO_4_3)
            .setTargetRotation(fragmentCameraBinding.viewFinder.display.rotation)
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
            .setOutputImageFormat(OUTPUT_IMAGE_FORMAT_RGBA_8888)
            .build()
            ...
    
  2. Podłącz analizator do podsystemu kamery i utwórz bufor mapy bitowej, który będzie zawierał dane otrzymane z kamery:

    .also {
      it.setAnalyzer(cameraExecutor) {
        image -> if (!::bitmapBuffer.isInitialized)
        { bitmapBuffer = Bitmap.createBitmap( image.width, image.height,
        Bitmap.Config.ARGB_8888 ) } detectObjects(image)
        }
      }
    
  3. Wyodrębnij określone dane obrazu potrzebne modelowi i przekaż informacje o obrocie obrazu:

    private fun detectObjects(image: ImageProxy) {
      //Copy out RGB bits to the shared bitmap buffer
      image.use {bitmapBuffer.copyPixelsFromBuffer(image.planes[0].buffer) }
        val imageRotation = image.imageInfo.rotationDegrees
        objectDetectorHelper.detect(bitmapBuffer, imageRotation)
      }
    
  4. Dokończ wszelkie końcowe transformacje danych i dodaj dane obrazu do obiektu TensorImage , jak pokazano w metodzie ObjectDetectorHelper.detect() przykładowej aplikacji:

    val imageProcessor = ImageProcessor.Builder().add(Rot90Op(-imageRotation / 90)).build()
    // Preprocess the image and convert it into a TensorImage for detection.
    val tensorImage = imageProcessor.process(TensorImage.fromBitmap(image))
    

Uruchom prognozy

Gdy w aplikacji na Androida utworzysz obiekt TensorImage z danymi obrazu w odpowiednim formacie, możesz uruchomić model na podstawie tych danych, aby uzyskać prognozę lub wnioskowanie .

W klasie fragments/CameraFragment.kt przykładowej aplikacji obiekt imageAnalyzer w funkcji bindCameraUseCases automatycznie przekazuje dane do modelu w celu przewidywania, gdy aplikacja jest połączona z kamerą.

Aplikacja korzysta z metody cameraProvider.bindToLifecycle() do obsługi selektora kamery, okna podglądu i przetwarzania modelu ML. Klasa ObjectDetectorHelper.kt obsługuje przekazywanie danych obrazu do modelu. Aby uruchomić model i wygenerować prognozy na podstawie danych obrazu:

  • Uruchom prognozę, przekazując dane obrazu do funkcji przewidywania:

    val results = objectDetector?.detect(tensorImage)
    

Obiekt interpretera TensorFlow Lite odbiera te dane, porównuje je z modelem i generuje listę przewidywań. Do ciągłego przetwarzania danych przez model należy zastosować metodę runForMultipleInputsOutputs() , dzięki czemu obiekty Interpretera nie będą tworzone, a następnie usuwane przez system przy każdym przebiegu predykcji.

Obsługuj dane wyjściowe modelu

W aplikacji na Androida po porównaniu danych obrazu z modelem wykrywania obiektów generowana jest lista przewidywań, które kod aplikacji musi obsłużyć, wykonując dodatkową logikę biznesową, wyświetlając wyniki użytkownikowi lub podejmując inne działania.

Dane wyjściowe dowolnego modelu TensorFlow Lite różnią się pod względem liczby generowanych przez niego prognoz (jednej lub wielu) oraz informacji opisowych dla każdej prognozy. W przypadku modelu wykrywania obiektów przewidywania zazwyczaj obejmują dane dla ramki ograniczającej, która wskazuje, gdzie na obrazie wykryto obiekt. W przykładowym kodzie wyniki są przekazywane do funkcji onResults w CameraFragment.kt , która pełni rolę DetectorListener w procesie wykrywania obiektu.

interface DetectorListener {
  fun onError(error: String)
  fun onResults(
    results: MutableList<Detection>?,
    inferenceTime: Long,
    imageHeight: Int,
    imageWidth: Int
  )
}

W przypadku modelu użytego w tym przykładzie każda predykcja zawiera lokalizację obwiedni obiektu, etykietę obiektu oraz wynik przewidywania od 0 do 1 jako wartość zmiennoprzecinkowa reprezentującą pewność przewidywania, gdzie 1 oznacza najwyższy wskaźnik pewności . Ogólnie przewidywania z wynikiem poniżej 50% (0,5) uważa się za niejednoznaczne. Jednak sposób obsługi wyników przewidywania o niskiej wartości zależy od Ciebie i potrzeb Twojej aplikacji.

Aby obsłużyć wyniki przewidywania modelu:

  1. Użyj wzorca odbiornika, aby przekazać wyniki do kodu aplikacji lub obiektów interfejsu użytkownika. Przykładowa aplikacja używa tego wzorca do przekazywania wyników wykrywania z obiektu ObjectDetectorHelper do obiektu CameraFragment :

    objectDetectorListener.onResults(
    // instance of CameraFragment
        results,
        inferenceTime,
        tensorImage.height,
        tensorImage.width)
    
  2. Działaj na podstawie wyników, na przykład wyświetlając prognozę użytkownikowi. Przykład rysuje nakładkę na obiekcie CameraPreview, aby pokazać wynik:

    override fun onResults(
      results: MutableList<Detection>?,
      inferenceTime: Long,
      imageHeight: Int,
      imageWidth: Int
    ) {
        activity?.runOnUiThread {
            fragmentCameraBinding.bottomSheetLayout.inferenceTimeVal.text =
                String.format("%d ms", inferenceTime)
    
            // Pass necessary information to OverlayView for drawing on the canvas
            fragmentCameraBinding.overlay.setResults(
                results ?: LinkedList<Detection>(),
                imageHeight,
                imageWidth
            )
    
            // Force a redraw
            fragmentCameraBinding.overlay.invalidate()
        }
    }
    

Gdy model zwróci wynik przewidywania, aplikacja może zastosować się do tej przewidywania, prezentując wynik użytkownikowi lub wykonując dodatkową logikę. W przypadku przykładowego kodu aplikacja rysuje ramkę wokół zidentyfikowanego obiektu i wyświetla na ekranie nazwę klasy.

Następne kroki

  • Zapoznaj się z różnymi zastosowaniami TensorFlow Lite w przykładach .
  • Dowiedz się więcej o korzystaniu z modeli uczenia maszynowego w TensorFlow Lite w sekcji Modele .
  • Dowiedz się więcej o wdrażaniu uczenia maszynowego w aplikacji mobilnej w Przewodniku programisty TensorFlow Lite .