Android 物件偵測

本教學課程說明如何使用 TensorFlow Lite 建構 Android 應用程式,以持續偵測裝置相機拍攝的影格中的物件。此應用程式專為實體 Android 裝置設計。如果您要更新現有專案,可以使用程式碼範例做為參考,並跳到關於修改專案的指示。

Object detection animated demo

物件偵測總覽

物件偵測是機器學習工作,旨在識別影像中多個類別物件的存在和位置。物件偵測模型會在包含一組已知物件的資料集上訓練。

經過訓練的模型會接收影像影格做為輸入,並嘗試將影像中的項目,從模型經過訓練可辨識的已知類別集中分類。針對每個影像影格,物件偵測模型會輸出偵測到的物件清單、每個物件邊界框的位置,以及指出物件正確分類信賴度的分數。

模型和資料集

本教學課程使用透過 COCO 資料集訓練的模型。COCO 是大規模物件偵測資料集,包含 33 萬張影像、150 萬個物件例項和 80 個物件類別。

您可以選擇使用下列其中一個預先訓練的模型

  • EfficientDet-Lite0 [建議] - 輕量級物件偵測模型,具有 BiFPN 特徵擷取器、共用方塊預測器和焦點損失。COCO 2017 驗證資料集的 mAP (平均精確度均值) 為 25.69%。

  • EfficientDet-Lite1 - 中型 EfficientDet 物件偵測模型。COCO 2017 驗證資料集的 mAP 為 30.55%。

  • EfficientDet-Lite2 - 較大型 EfficientDet 物件偵測模型。COCO 2017 驗證資料集的 mAP 為 33.97%。

  • MobileNetV1-SSD - 極輕量級模型,已針對搭配 TensorFlow Lite 進行物件偵測作業最佳化。COCO 2017 驗證資料集的 mAP 為 21%。

在本教學課程中,EfficientDet-Lite0 模型在大小和準確度之間取得良好的平衡。

模型的下載、解壓縮和放置到 assets 資料夾中的作業,會由 download.gradle 檔案自動管理,此檔案會在建構時執行。您不需要將 TFLite 模型手動下載到專案中。

設定並執行範例

如要設定物件偵測應用程式,請從 GitHub 下載範例,並使用 Android Studio 執行。本教學課程的以下章節將探討程式碼範例的相關章節,以便您可以將其套用至您自己的 Android 應用程式。

系統需求

  • Android Studio 2021.1.1 (Bumblebee) 版或更高版本。
  • Android SDK 版本 31 或更高版本
  • Android 裝置,最低作業系統版本為 SDK 24 (Android 7.0 - Nougat),且已啟用開發人員模式。

取得範例程式碼

建立範例程式碼的本機副本。您將使用此程式碼在 Android Studio 中建立專案,並執行範例應用程式。

如要複製並設定範例程式碼

  1. 複製 git 存放區
    git clone https://github.com/tensorflow/examples.git
    
  2. 或者,您可以設定您的 git 例項以使用稀疏簽出,這樣您就只有物件偵測範例應用程式的檔案
    cd examples
    git sparse-checkout init --cone
    git sparse-checkout set lite/examples/object_detection/android
    

匯入並執行專案

從下載的範例程式碼建立專案、建構專案,然後執行專案。

如要匯入並建構範例程式碼專案

  1. 啟動 Android Studio
  2. 從 Android Studio 中,選取「File (檔案) > New (新增) > Import Project (匯入專案)」。
  3. 導覽至包含 build.gradle 檔案的範例程式碼目錄 (.../examples/lite/examples/object_detection/android/build.gradle),然後選取該目錄。
  4. 如果 Android Studio 要求 Gradle 同步處理,請選擇「OK (確定)」。
  5. 確認您的 Android 裝置已連線至電腦,且已啟用開發人員模式。按一下綠色的 Run (執行) 箭頭。

如果您選取正確的目錄,Android Studio 會建立新專案並建構。此程序可能需要幾分鐘時間,具體取決於電腦的速度,以及您是否曾將 Android Studio 用於其他專案。建構完成時,Android Studio 會在「Build Output (建構輸出)」狀態面板中顯示 BUILD SUCCESSFUL (建構成功) 訊息。

選用:如要透過更新 Android 外掛程式版本來修正建構錯誤

  1. 開啟專案目錄中的 build.gradle 檔案。
  2. 如下所示變更 Android 工具版本

    // from: classpath
    'com.android.tools.build:gradle:4.2.2'
    // to: classpath
    'com.android.tools.build:gradle:4.1.2'
    
  3. 選取「File (檔案) > Sync Project with Gradle Files (將專案與 Gradle 檔案同步處理)」,同步處理專案。

如要執行專案

  1. 從 Android Studio 中,選取「Run (執行) > Run… (執行…)」,執行專案。
  2. 選取已連線且配備相機的 Android 裝置,以測試應用程式。

接下來的章節將說明您需要對現有專案進行哪些修改,才能將此功能新增至您自己的應用程式,並將此範例應用程式做為參考點。

新增專案依附元件

在您自己的應用程式中,您必須新增特定的專案依附元件,才能執行 TensorFlow Lite 機器學習模型,並存取可將影像等資料轉換為張量資料格式 (可供您使用的模型處理) 的公用程式函式。

範例應用程式使用 TensorFlow Lite Vision Task Library (視覺化任務庫),以便執行物件偵測機器學習模型。以下指示說明如何將必要的程式庫依附元件新增至您自己的 Android 應用程式專案。

以下指示說明如何將必要的專案和模組依附元件新增至您自己的 Android 應用程式專案。

如要新增模組依附元件

  1. 在使用 TensorFlow Lite 的模組中,更新模組的 build.gradle 檔案,以納入下列依附元件。在範例程式碼中,此檔案位於這裡:...examples/lite/examples/object_detection/android/app/build.gradle (程式碼參考)

    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'
    }
    

    專案必須包含 Vision Task Library (tensorflow-lite-task-vision)。圖形處理單元 (GPU) 程式庫 (tensorflow-lite-gpu-delegate-plugin) 提供基礎架構,以便在 GPU 上執行應用程式,而 Delegate (tensorflow-lite-gpu) 則提供相容性清單。

  2. 在 Android Studio 中,選取「File (檔案) > Sync Project with Gradle Files (將專案與 Gradle 檔案同步處理)」,同步處理專案依附元件。

初始化 ML 模型

在您的 Android 應用程式中,您必須先使用參數初始化 TensorFlow Lite 機器學習模型,才能使用模型執行預測。這些初始化參數在物件偵測模型之間保持一致,且可以包含預測的最低準確度門檻等設定。

TensorFlow Lite 模型包含 .tflite 檔案 (內含模型程式碼),而且通常包含標籤檔案 (內含模型預測的類別名稱)。就物件偵測而言,類別是指人、狗、貓或汽車等物件。

此範例會下載 download_models.gradle 中指定的數個模型,而 ObjectDetectorHelper 類別則提供模型的選取器

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"
  }

如要在您的應用程式中初始化模型

  1. .tflite 模型檔案新增至開發專案的 src/main/assets 目錄,例如:EfficientDet-Lite0
  2. 為您模型的檔案名稱設定靜態變數。在範例應用程式中,您將 modelName 變數設為 MODEL_EFFICIENTDETV0,以使用 EfficientDet-Lite0 偵測模型。
  3. 設定模型的選項,例如預測門檻、結果集大小,以及選用的硬體加速委派

    val optionsBuilder =
      ObjectDetector.ObjectDetectorOptions.builder()
        .setScoreThreshold(threshold)
        .setMaxResults(maxResults)
    
  4. 使用此物件中的設定,建構包含模型的 TensorFlow Lite ObjectDetector 物件

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

setupObjectDetector 會設定下列模型參數

  • 偵測門檻
  • 偵測結果的最大數量
  • 要使用的處理執行緒數量 (BaseOptions.builder().setNumThreads(numThreads))
  • 實際模型 (modelName)
  • ObjectDetector 物件 (objectDetector)

設定硬體加速器

在您的應用程式中初始化 TensorFlow Lite 模型時,您可以使用硬體加速功能來加速模型的預測計算。

TensorFlow Lite 委派是軟體模組,可使用行動裝置上的專用處理硬體 (例如圖形處理單元 (GPU)、張量處理單元 (TPU) 和數位訊號處理器 (DSP)) 加速機器學習模型的執行。建議使用委派來執行 TensorFlow Lite 模型,但並非必要。

物件偵測器是使用執行緒上目前的設定初始化,而執行緒正在使用物件偵測器。您可以將 CPU 和 NNAPI 委派與在主要執行緒上建立且在背景執行緒上使用的偵測器搭配使用,但初始化偵測器的執行緒必須使用 GPU 委派。

委派是在 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()
    }
}

如需瞭解如何搭配 TensorFlow Lite 使用硬體加速委派的詳細資訊,請參閱 TensorFlow Lite 委派

準備模型的資料

在您的 Android 應用程式中,您的程式碼會將資料提供給模型進行解譯,方法是將現有資料 (例如影像影格) 轉換為可供模型處理的張量資料格式。您傳遞至模型的張量中的資料,必須具有特定維度或形狀,才能與用於訓練模型的資料格式相符。

此程式碼範例中使用的 EfficientDet-Lite0 模型接受代表影像的張量,其維度為 320 x 320,每個像素有三個通道 (紅、藍和綠)。張量中的每個值都是介於 0 到 255 之間的單一位元組。因此,如要在新影像上執行預測,您的應用程式必須將該影像資料轉換為該大小和形狀的張量資料物件。TensorFlow Lite Task Library Vision API 會為您處理資料轉換。

應用程式會使用 ImageAnalysis 物件,從相機擷取影像。此物件會使用來自相機的點陣圖呼叫 detectObject 函式。ImageProcessor 會自動調整資料大小並旋轉資料,使其符合模型的影像資料需求。然後,影像會轉換為 TensorImage 物件。

如要準備來自相機子系統的資料,以便由 ML 模型處理

  1. 建構 ImageAnalysis 物件,以擷取所需格式的影像

    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. 將分析器連線至相機子系統,並建立點陣圖緩衝區以包含從相機收到的資料

    .also {
      it.setAnalyzer(cameraExecutor) {
        image -> if (!::bitmapBuffer.isInitialized)
        { bitmapBuffer = Bitmap.createBitmap( image.width, image.height,
        Bitmap.Config.ARGB_8888 ) } detectObjects(image)
        }
      }
    
  3. 擷取模型所需的特定影像資料,並傳遞影像旋轉資訊

    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. 完成任何最終資料轉換,並將影像資料新增至 TensorImage 物件,如範例應用程式的 ObjectDetectorHelper.detect() 方法所示

    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))
    

執行預測

在您的 Android 應用程式中,一旦您建立具有正確格式影像資料的 TensorImage 物件,您就可以針對該資料執行模型,以產生預測或推論

在範例應用程式的 fragments/CameraFragment.kt 類別中,bindCameraUseCases 函式中的 imageAnalyzer 物件,會在應用程式連線至相機時,自動將資料傳遞至模型以進行預測。

應用程式會使用 cameraProvider.bindToLifecycle() 方法來處理相機選取器、預覽視窗和 ML 模型處理。ObjectDetectorHelper.kt 類別會處理將影像資料傳遞至模型。如要執行模型並從影像資料產生預測

  • 將影像資料傳遞至您的預測函式,以執行預測

    val results = objectDetector?.detect(tensorImage)
    

TensorFlow Lite Interpreter 物件會接收此資料,並針對模型執行資料,然後產生預測清單。如要持續處理模型資料,請使用 runForMultipleInputsOutputs() 方法,讓系統不會針對每次預測執行建立然後移除 Interpreter 物件。

處理模型輸出

在您的 Android 應用程式中,在您針對物件偵測模型執行影像資料之後,模型會產生預測清單,您的應用程式程式碼必須處理這些預測,方法是執行其他業務邏輯、向使用者顯示結果,或採取其他動作。

任何指定的 TensorFlow Lite 模型的輸出,都會因其產生的預測數量 (單一或多個) 以及每個預測的描述性資訊而異。就物件偵測模型而言,預測通常包含邊界框的資料,指出在影像中偵測到物件的位置。在範例程式碼中,結果會傳遞至 CameraFragment.kt 中的 onResults 函式,此函式的作用是物件偵測程序中的 DetectorListener。

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

對於此範例中使用的模型,每個預測都包含物件的邊界框位置、物件的標籤,以及介於 0 和 1 之間的預測分數 (以 Float 表示),代表預測的信賴度,其中 1 是最高信賴度評級。一般而言,分數低於 50% (0.5) 的預測會被視為不明確。不過,如何處理低值預測結果取決於您和應用程式的需求。

如要處理模型預測結果

  1. 使用監聽器模式,將結果傳遞至您的應用程式程式碼或使用者介面物件。範例應用程式使用此模式,將偵測結果從 ObjectDetectorHelper 物件傳遞至 CameraFragment 物件

    objectDetectorListener.onResults(
    // instance of CameraFragment
        results,
        inferenceTime,
        tensorImage.height,
        tensorImage.width)
    
  2. 對結果採取行動,例如向使用者顯示預測。此範例會在 CameraPreview 物件上繪製疊加層以顯示結果

    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()
        }
    }
    

一旦模型傳回預測結果,您的應用程式就可以對該預測採取行動,方法是向使用者呈現結果或執行其他邏輯。就範例程式碼而言,應用程式會在已識別的物件周圍繪製邊界框,並在螢幕上顯示類別名稱。

後續步驟

  • 探索 TensorFlow Lite 在範例中的各種用途。
  • 模型章節中,進一步瞭解如何搭配 TensorFlow Lite 使用機器學習模型。
  • TensorFlow Lite 開發人員指南中,進一步瞭解如何在行動應用程式中實作機器學習。