使用 Android 进行目标检测

本教程将向您展示如何使用 TensorFlow Lite 构建 Android 应用程序,以持续检测设备摄像头捕获的帧中的对象。此应用程序专为物理 Android 设备设计。如果您要更新现有项目,可以使用代码示例作为参考,并跳到有关 修改项目 的说明。

Object detection animated demo

目标检测概述

目标检测是机器学习任务,用于识别图像中多个类别对象的出现和位置。目标检测模型是在包含一组已知对象的训练数据集上进行训练的。

训练后的模型接收图像帧作为输入,并尝试从其训练识别的一组已知类别中对图像中的项目进行分类。对于每个图像帧,目标检测模型输出它检测到的对象的列表、每个对象的边界框的位置以及指示对象被正确分类的置信度的分数。

模型和数据集

本教程使用在 COCO 数据集 上训练的模型。COCO 是一个大型目标检测数据集,包含 330K 张图像、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 或更高版本
  • 具有最低操作系统版本 SDK 24(Android 7.0 - 牛轧糖)且已启用开发者模式的 Android 设备。

获取示例代码

创建示例代码的本地副本。您将使用此代码在 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 中,选择 **文件 > 新建 > 导入项目**。
  3. 导航到包含 build.gradle 文件的示例代码目录 (.../examples/lite/examples/object_detection/android/build.gradle) 并选择该目录。
  4. 如果 Android Studio 请求 Gradle 同步,请选择确定。
  5. 确保您的 Android 设备已连接到您的计算机并且已启用开发者模式。单击绿色的 运行 箭头。

如果您选择了正确的目录,Android Studio 将创建一个新项目并构建它。此过程可能需要几分钟,具体取决于计算机的速度以及您是否已将 Android Studio 用于其他项目。构建完成后,Android Studio 将在 **构建输出** 状态面板中显示 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. 通过选择以下内容来同步项目:**文件 > 将项目与 Gradle 文件同步**。

要运行项目

  1. 在 Android Studio 中,通过选择 **运行 > 运行…** 来运行项目。
  2. 选择连接的具有摄像头的 Android 设备以测试应用程序。

接下来的部分将向您展示需要对现有项目进行的修改,以便使用此示例应用程序作为参考点,将此功能添加到您自己的应用程序中。

添加项目依赖项

在您自己的应用程序中,您必须添加特定的项目依赖项才能运行 TensorFlow Lite 机器学习模型,并访问将图像等数据转换为张量数据格式的实用程序函数,该格式可以由您使用的模型进行处理。

示例应用程序使用 TensorFlow Lite 视觉任务库 来启用对象检测机器学习模型的执行。以下说明解释了如何将所需的库依赖项添加到您自己的 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'
    }
    

    该项目必须包含视觉任务库 (tensorflow-lite-task-vision)。图形处理单元 (GPU) 库 (tensorflow-lite-gpu-delegate-plugin) 提供在 GPU 上运行应用程序的基础结构,而 Delegate (tensorflow-lite-gpu) 提供兼容性列表。

  2. 在 Android Studio 中,通过选择以下内容来同步项目依赖项:**文件 > 将项目与 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 任务库视觉 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 类中,imageAnalyzer bindCameraUseCases 函数中的对象会在应用程序连接到相机时自动将数据传递给模型以进行预测。

该应用程序使用 cameraProvider.bindToLifecycle() 方法来处理相机选择器、预览窗口和 ML 模型处理。该 ObjectDetectorHelper.kt 类负责将图像数据传递到模型中。要运行模型并从图像数据生成预测

  • 通过将图像数据传递给您的预测函数来运行预测

    val results = objectDetector?.detect(tensorImage)
    

TensorFlow Lite 解释器对象接收这些数据,将其与模型进行匹配,并生成预测列表。为了对模型进行连续的数据处理,请使用 runForMultipleInputsOutputs() 方法,这样系统就不会为每次预测运行创建和删除解释器对象。

处理模型输出

在您的 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 之间的预测分数(作为浮点数),表示预测的置信度,其中 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 开发人员指南 中了解有关在移动应用程序中实现机器学习的更多信息。