适用于 Android 的图片分类指南

借助 MediaPipe Image Classifier 任务,您可以对图片进行分类。您可以使用此任务从训练时定义的一组类别中确定一张图片代表什么。这些说明介绍了如何使用图像分类器 支持 Android 应用这些说明中介绍的代码示例可供使用 已开启 GitHub

您可以通过查看网页演示来了解此任务的实际效果。 如需详细了解功能、模型和配置选项 部分,请参阅概览

代码示例

MediaPipe Tasks 示例代码是图像分类器的简单实现 Android 版应用。该示例使用 Android 实体设备上的相机 对对象进行连续分类,也可以使用 以便对对象进行静态分类。

您可以用该应用作为基础来开发自己的 Android 应用,也可以指代该应用 对现有应用进行了修改。图像分类器示例代码托管在 GitHub

下载代码

以下说明介绍了如何创建示例的本地副本 使用 git 命令行工具运行 git 代码库。

<ph type="x-smartling-placeholder">

如需下载示例代码,请执行以下操作:

  1. 使用以下命令克隆 git 代码库:
    git clone https://github.com/google-ai-edge/mediapipe-samples
    
  2. (可选)将您的 Git 实例配置为使用稀疏检出, 因此您只有图像分类器示例应用的文件:
    cd mediapipe
    git sparse-checkout init --cone
    git sparse-checkout set examples/image_classification/android
    

创建示例代码的本地版本后,您可以导入项目 进入 Android Studio 并运行应用。有关说明,请参阅 Android 版设置指南

关键组件

以下文件包含此图片的关键代码 分类示例应用:

设置

本部分介绍了设置开发环境和 代码项目使用图像分类器。有关 设置开发环境以使用 MediaPipe 任务,包括 平台版本要求,请参阅 Android 版设置指南

<ph type="x-smartling-placeholder">

依赖项

图片分类器使用 com.google.mediapipe:tasks-vision 库。添加此项 依赖项的 build.gradle 文件 Android 应用开发项目。使用以下代码导入所需的依赖项: 以下代码:

dependencies {
    ...
    implementation 'com.google.mediapipe:tasks-vision:latest.release'
}

型号

MediaPipe 图像分类器任务需要一个与此分类兼容的经过训练的模型 任务。如需详细了解适用于图片分类器的经过训练的模型,请参阅 任务概览的“模型”部分

选择并下载模型,然后将其存储在项目目录中:

<dev-project-root>/src/main/assets

使用 BaseOptions.Builder.setModelAssetPath() 方法指定路径 模型所用的指标。下一部分的代码示例将引用此方法 部分。

在 图片分类器示例代码 该模型在 ImageClassifierHelper.kt 中定义, 文件。

创建任务

您可以使用 createFromOptions 函数创建任务。通过 “createFromOptions”函数接受配置选项,包括正在运行的 模式、显示名称语言区域、结果数上限、置信度阈值 以及类别许可名单或拒绝名单如需详细了解配置 选项,请参阅配置概览

图片分类器任务支持 3 种输入数据类型:静态图片、视频文件、 和直播视频流您需要指定与 输入数据类型。选择与 输入数据类型,了解如何创建任务并运行推理。

映像

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.IMAGE)
    .setMaxResults(5)
    .build();
imageClassifier = ImageClassifier.createFromOptions(context, options);
    

视频

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.VIDEO)
    .setMaxResults(5)
    .build();
imageClassifier = ImageClassifier.createFromOptions(context, options);
    

直播

ImageClassifierOptions options =
  ImageClassifierOptions.builder()
    .setBaseOptions(
      BaseOptions.builder().setModelAssetPath("model.tflite").build())
    .setRunningMode(RunningMode.LIVE_STREAM)
    .setMaxResults(5)
    .setResultListener((result, inputImage) -> {
         // Process the classification result here.
    })
    .setErrorListener((result, inputImage) -> {
         // Process the classification errors here.
    })
    .build()
imageClassifier = ImageClassifier.createFromOptions(context, options)
    

图像分类器示例代码实现允许用户在 处理模式这种方法使得任务创建代码更加复杂, 可能不适合您的用例。您可以在 setupImageClassifier() 函数 ImageClassifierHelper.kt 文件。

配置选项

此任务具有以下适用于 Android 应用的配置选项:

选项名称 说明 值范围 默认值
runningMode 设置任务的运行模式。有三个 模式:

IMAGE:单图输入的模式。

VIDEO:视频已解码帧的模式。

LIVE_STREAM:输入流媒体直播模式 例如来自相机的数据。在此模式下,resultListener 必须为 调用以设置监听器以接收结果 异步执行。
{IMAGE, VIDEO, LIVE_STREAM} IMAGE
displayNamesLocale 设置要用于 任务模型的元数据(如果有)。默认值为 en, 英语。您可以向自定义模型的元数据中添加本地化标签 使用 TensorFlow Lite Metadata Writer API 语言区域代码 en
maxResults 将评分最高的分类结果的可选数量上限设置为 return。如果 <0,则返回所有可用的结果。 任何正数 -1
scoreThreshold 设置预测分数阈值,以替换 模型元数据(如果有)。低于此值的结果将被拒绝。 任意浮点数 未设置
categoryAllowlist 设置允许的类别名称的可选列表。如果不为空, 类别名称未包含在此集合中的分类结果 已滤除。重复或未知的类别名称会被忽略。 此选项与 categoryDenylist 互斥,使用 都会导致错误。 任何字符串 未设置
categoryDenylist 设置不允许使用的类别名称的可选列表。如果 非空,类别名称在此集中的分类结果将被滤除 。重复或未知的类别名称会被忽略。这个选项 categoryAllowlist 不包含,同时使用这两个元素会导致错误。 任何字符串 未设置
resultListener 设置结果监听器以接收分类结果 当图像分类器在直播中时异步执行 模式。仅在跑步模式设为“LIVE_STREAM”时才能使用 不适用 未设置
errorListener 设置一个可选的错误监听器。 不适用 未设置

准备数据

图片分类器适用于图片、视频文件和直播视频。任务 处理数据输入预处理,包括调整大小、旋转和值 标准化。

您需要将输入图片或帧转换为 com.google.mediapipe.framework.image.MPImage 对象,然后再将其传递给 图像分类器。

映像

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load an image on the users device as a Bitmap object using BitmapFactory.

// Convert an Androids Bitmap object to a MediaPipes Image object.
Image mpImage = new BitmapImageBuilder(bitmap).build();
    

视频

import com.google.mediapipe.framework.image.BitmapImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Load a video file on the user's device using MediaMetadataRetriever

// From the videos metadata, load the METADATA_KEY_DURATION and
// METADATA_KEY_VIDEO_FRAME_COUNT value. Youll need them
// to calculate the timestamp of each frame later.

// Loop through the video and load each frame as a Bitmap object.

// Convert the Androids Bitmap object to a MediaPipes Image object.
Image mpImage = new BitmapImageBuilder(frame).build();
    

直播

import com.google.mediapipe.framework.image.MediaImageBuilder;
import com.google.mediapipe.framework.image.MPImage;

// Create a CameraXs ImageAnalysis to continuously receive frames 
// from the devices camera. Configure it to output frames in RGBA_8888
// format to match with what is required by the model.

// For each Androids ImageProxy object received from the ImageAnalysis, 
// extract the encapsulated Androids Image object and convert it to 
// a MediaPipes Image object.
android.media.Image mediaImage = imageProxy.getImage()
Image mpImage = new MediaImageBuilder(mediaImage).build();
    

在 图像分类器示例代码,数据准备在 ImageClassifierHelper.kt 文件。

运行任务

您可以调用与跑步模式对应的 classify 函数来触发推断。Image Classifier API 会返回输入图片或帧中对象的可能类别。

映像

ImageClassifierResult classifierResult = imageClassifier.classify(image);
    

视频

// Calculate the timestamp in milliseconds of the current frame.
long frame_timestamp_ms = 1000 * video_duration * frame_index / frame_count;

// Run inference on the frame.
ImageClassifierResult classifierResult =
    imageClassifier.classifyForVideo(image, frameTimestampMs);
    

直播

// Run inference on the frame. The classifications results will be available 
// via the `resultListener` provided in the `ImageClassifierOptions` when 
// the image classifier was created.
imageClassifier.classifyAsync(image, frameTimestampMs);
    

请注意以下几点:

  • 在视频模式或直播模式下投放广告时,您还必须 为图像分类器任务提供输入帧的时间戳。
  • 在图片模式或视频模式下运行时,图片分类器任务 阻塞当前线程,直到它处理完输入图像,或者 帧。为避免阻塞界面,请在 后台线程。
  • 在直播模式下运行时,图像分类器任务不会阻塞 当前线程,但会立即返回。它将调用其结果 并在每次处理完一个监听器后将带有检测结果的监听器 输入帧。如果在图片分类器调用时调用 classifyAsync 函数, 任务正忙于处理另一个帧,则该任务会忽略新的输入帧。

在 图片分类器示例代码,classify 函数在 ImageClassifierHelper.kt 文件。

处理和显示结果

进行推理时,图像分类器任务会返回一个 ImageClassifierResult 对象,其中包含输入图片或帧中对象的可能类别列表。

以下示例展示了此任务的输出数据:

ImageClassifierResult:
 Classifications #0 (single classification head):
  head index: 0
  category #0:
   category name: "/m/01bwb9"
   display name: "Passer domesticus"
   score: 0.91406
   index: 671
  category #1:
   category name: "/m/01bwbt"
   display name: "Passer montanus"
   score: 0.00391
   index: 670

此结果是通过运行 Bird Classifier 获得的 日期:

在 图片分类器示例代码,即ClassificationResultsAdapter ClassificationResultsAdapter.kt 文件会处理这些结果:

fun updateResults(imageClassifierResult: ImageClassifierResult? = null) {
    categories = MutableList(adapterSize) { null }
    if (imageClassifierResult != null) {
        val sortedCategories = imageClassifierResult.classificationResult()
            .classifications()[0].categories().sortedBy { it.index() }
        val min = kotlin.math.min(sortedCategories.size, categories.size)
        for (i in 0 until min) {
            categories[i] = sortedCategories[i]
        }
    }
}