目录

下一步


在这里,我们使用TensorFlow Lite解释器检查图像并产生其输出。

这是将神经网络与Android上的TensorFlow Lite结合使用的系列文章中的第三篇。在本系列的第2部分中,我们最后从预训练的模型制作了TensorFlow Lite模型。在这一部分中,我们将创建一个Android应用程序并将该模型导入其中。您将需要上一部分(yolo.tflite)中创建的.tflite文件。

应用程序流程如下:

  1. 选择图像进行分析。
  2. 调整图像大小以匹配所使用的TensorFlow Lite模型的要求。
  3. 输入缓冲区由图像构成。
  4. 具有可选委托的TensorFlow Lite解释器被实例化。
    1. GPU代表将在图形硬件上运行一些计算。
    2. NNAPI委托(Android 8.1和更高版本)可以在GPU,DSP或神经处理单元(NPU)上运行。
  5. 实例化输出缓冲区。
  6. 解释器针对输入运行模型,并将结果放入输出中。

应用程序的源位图可以通过多种不同方式获取:可以从文件系统加载,从设备的摄像头获取,从网络下载或通过其他方式获取。只要图像可以作为位图加载,那么此处显示的其余代码都可以轻松地适用于此。在此示例程序中,我所有的源图像来自图片选择器。

使用空活动模板创建一个新的Android应用程序。创建应用程序之后,我们需要为应用程序执行一些配置步骤。首先,我们将添加对TensorFlow的引用,以便该应用程序具有必要的库,用于将TensorFlow Lite和TensorFlow Lite委托用于CPU和NPU。打开应用程序的build.gradle并将以下内容添加到“依赖项”部分:

implementation 'org.tensorflow:tensorflow-lite:0.0.0-nightly'
implementation 'org.tensorflow:tensorflow-lite-gpu:0.0.0-nightly'
implementation 'org.tensorflow:tensorflow-lite-support:0.0.0-nightly'

保存更改并构建应用程序。如果收到有关所需NDK版本不存在的错误,请参阅本系列的第1部分。如果应用程序生成,则对build.gradle进行其他更改。在“Android”部分中,必须添加一个设置以指示Android Studio不压缩.tflite文件。在文件的android部分中,添加以下行:

aaptOptions {noCompress "tflite"
}

.tflite文件将进入项目的“assets”文件夹中。该文件夹在新项目中不存在。您可以在apps/src/main中的项目中创建文件夹。

将文件yolo.tflite复制到assets文件夹。

我们将从允许用户选择图像并显示它的应用程序开始。为此,activity_main.xml文件仅需要几个元素:用于激活图像选择器的按钮和图像视图。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><ImageViewandroid:id="@+id/selectedImageView"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_marginBottom="64dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><Buttonandroid:id="@+id/selectImageButton"android:text="@string/button_select_image"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="8dp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/selectedImageView" />
</androidx.constraintlayout.widget.ConstraintLayout>

在文件MainActivity.java中,我们添加执行代码。要从此代码引用图像视图,请添加一个名为selectedImageView的字段。

ImageView selectedImageView;

在onCreate()中,在setContentView()后面添加一行代码,将加载的ImageView的实例分配给selectedImageView。

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);selectedImageView = findViewById(R.id.selectedImageView);
}

在布局中定义的按钮将触发打开图像选择器的函数。

final int SELECT_PICTURE = 1;
public void onSelectImageButtonClicked(View view) {Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType("image/*");Intent chooser = Intent.createChooser(intent, "Choose a Picture");startActivityForResult(chooser, SELECT_PICTURE);
}

当用户激活此函数时,系统的图像选择器将打开。用户选择图像后,控制权返回给应用程序。要检索选择,活动必须实现方法onActivityResult()。所选图像的URI在传递给此方法的数据对象内。

public void onActivityResult (int reqCode, int resultCode, Intent data) {super.onActivityResult(reqCode, resultCode, data);if (resultCode == RESULT_OK) {if (reqCode == SELECT_PICTURE) {Uri selectedUri = data.getData();String fileString = selectedUri.getPath();selectedImageView.setImageURI(selectedUri);}}
}

activity_main.xml中定义的按钮尚未附加到任何代码。将以下行添加到按钮的定义:

android:onClick="onSelectImageButtonClicked"

如果立即运行该应用程序,您将看到它能够加载和显示图像。我们想将此图像通过TensorFlow解释器传递。让我们为此准备好代码。YOLO算法有多种实现方式。我在这里使用的那个期望图像被分为13列和13行。此网格内的每个单位均为32x32像素。输入图像将为416x416像素(13 * 32 = 416)。这些值在添加到MainActivity.java的常量中表示。还添加了一个常量,用于保存要加载的.tflite文件的名称,以及一个用于保存TensorFlow Lite解释器的变量。

final String TF_MODEL_NAME = "yolov4.tflite";
final int IMAGE_SEGMENT_ROWS = 13;
final int IMAGE_SEGMENT_COLS = 13;
final int IMAGE_SEGMENT_WIDTH = 32;
final int IMAGE_SEGMENT_HEIGHT = 32;
final int IMAGE_WIDTH = IMAGE_SEGMENT_COLS * IMAGE_SEGMENT_WIDTH; //416
final int IMAGE_HEIGHT = IMAGE_SEGMENT_ROWS * IMAGE_SEGMENT_HEIGHT; //416Interpreter tfLiteInterpreter;

有几种调整图像大小的选项。我将使用TensorFlow ImageProcessor。ImageProcessor带有我们要应用于图像的操作列表。当给定TensorImage时,ImageProcessor将在图像上执行这些操作,并返回一个新的TensorImage准备进行进一步处理。

void processImage(Bitmap sourceImage) {ImageProcessor imageProcessor =new ImageProcessor.Builder().add(new ResizeOp(IMAGE_HEIGHT, IMAGE_WIDTH, ResizeOp.ResizeMethod.BILINEAR)).build();TensorImage tImage = new TensorImage(DataType.FLOAT32);tImage.load(sourceImage);tImage = imageProcessor.process(tImage);//...
}

我们需要使用我们的模型初始化TensorFlow Lite解释器,以便它可以处理该图像。Interpreter类的构造函数接受一个包含模型的字节缓冲区和一个包含要应用于Interpreter实例的选项的对象。对于这些选项,我们添加了一个GPU委托和一个NNAPI委托。如果设备具有用于加速某些操作的兼容硬件,则在运行TF解释器时将使用该硬件。

void prepareInterpreter() throws IOException {if(tfLiteInterpreter == null) {GpuDelegate gpuDelegage = new GpuDelegate();Interpreter.Options options = new Interpreter.Options();options.addDelegate(gpuDelegage);//Only add the NNAPI delegate of this were build for Android P or later.if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {NnApiDelegate nnApiDelegate = new NnApiDelegate();options.addDelegate(nnApiDelegate);}MappedByteBuffer tfLiteModel = FileUtil.loadMappedFile(this, TF_MODEL_NAME);tfLiteInterpreter = new Interpreter(tfLiteModel, options);}
}

您可能还记得张量通常表示为数组。在processImage函数中,创建了一些缓冲区以接收来自网络模型的输出。

float[][][][][] buf0 = new float[1][52][52][3][85];
float[][][][][] buf1 = new float[1][26][26][3][85];
float[][][][][] buf2 = new float[1][13][13][3][85];

这些多维数组一开始可能看起来有些吓人。如何处理这些数组中的数据?

让我们关注三个数组中的最后一个。某些网络模型可以同时处理感兴趣的数据集的多个实例。您可能还记得,该算法将416x416像素的图像分为13行和13列。数组的第二维和第三维用于图像的行和列。在这些网格的每个网格中,该算法最多可以为在特定网格位置识别的对象检测3个边界框。尺寸3的第四个维度适用于这些边界框中的每一个。最后一个维度是85个元素。列表中的前四项用于定义边界框坐标(x,y,宽度,高度)。此列表中的第五个元素是介于0和1之间的值,表示框是对象匹配项的置信度。

对于我在这里使用的YOLO的实现,最多可以识别80种类型的对象。YOLO还有其他实现可以检测其他一些元素。有时,您可以通过最后一个维度中的元素数量来猜测网络所标识的项目数量。但是,不要依赖于此。要知道哪个位置代表哪些对象,您需要查阅所用网络的文档。这些值的含义和解释将在本系列的下一部分中详细讨论。

这些值打包在一个HashMap中并传递到TensorFlow Lite解释器。

//...
HashMap<Integer, Object> outputBuffers = new HashMap<Integer, Object>();
outputBuffers.put(0, buf0);
outputBuffers.put(1, buf1);
outputBuffers.put(2, buf2);tfLiteInterpreter.runForMultipleInputsOutputs(new Object[]{tImage.getBuffer()}, outputBuffers);

执行YOLO神经网络的行是runForMultipleInputsOutputs()。如果只有一个输入和输出,则将使用名为run()的函数的调用。结果存储在第二个参数中传递的数组中。

网络运行并产生输出,但是要使这些输出有用或有意义,我们需要知道如何解释它们。为了测试,我使用了这张图片。

挖掘一个输出数组,我得到了一系列数字。让我们检查一下前四个。

00: 0.32  01: 0.46   02: 0.71   03: 0.46

前四个数字是用于匹配以及宽度和高度的X和Y坐标。值从-1到1缩放。必须将它们调整为0到416才能将它们转换为像素尺寸。

数组的其余大多数值均为0.0。对于我正在寻找非零值的结果,在位置19遇到

12: 0.00   13: 0.00   14: 0.00   15: 0.00
16: 0.00   17: 0.00   18: 0.00   19: 0.91
20: 0.00   21: 0.00   22: 0.00   23: 0.00

数组的整个元素为85个元素,但是在这种情况下,其余的值也为零,因此省略。从位置5开始的值是该神经网络可以识别的每类物品的置信度。如果从值位置减去5,我们将得到对象类的索引。对于使该值与对象匹配的类列表,我们将查看位置14(19-5 = 14)。

00: person        01: bicycle       02: car          03: motorbike
04: airplane      05: bus           06: train        07: truck
08: boat          09: traffic light 10: fire hydrant 11: stop sign
12: parking meter 13: bench         14: bird         15: cat
16: dog           17: horse         18: sheep

在这种情况下,程序已识别出一只鸟。

下一步

现在,我们已经成功地在图像上运行了模型,是时候对模型的输出进行一些有趣的操作了。继续阅读下一篇文章,以了解如何解释这些结果并为其创建可视化效果。

使用Tensorflow Lite创建一个Android AI应用相关推荐

  1. 使用Eclipse创建一个Android程序方法

    要编写Android程序,需要安装JDK.Eclipse和Android SDK. Android SDK的安装路径不要在program file或program file(x86)下,否则在debu ...

  2. 从零开始创建一个Android主屏幕Widget

    登录 / 注册 IT168首页 手机 整机 DIY硬件 摄影 消费数码 数字家电 企业IT 企业商用 办公 互动 社区 全部频道 IT168技术开发频道 IT168首页 > 技术开发 >  ...

  3. 基于TensorFlow Lite实现的Android花卉识别应用

    介绍 本教程将在Android设备上使用TensorFlow Lite运行图像识别模型,具体包括: 使用TensorFlow Lite Model Maker训练自定义的图像分类器 利用Android ...

  4. android compile使用方法,自己创建一个android studio在线依赖compile

    相信大家在使用AS(android studio)的时候添加依赖的时候有没见过如下方式: 很酷炫本人将教你如何做到. 1.    使用 jcenter()实现- 在创建的时候as自动帮我导入了 1.  ...

  5. Android入门-新手如何成功创建一个Android小应用

    原文链接:http://android.eoe.cn/topic/overview 第一课程:Building Your First App [本课内容简介]欢迎加入到安卓应用的开发大潮中!这门课程会 ...

  6. 创建一个Android Cardboard 360 Video Viewer

    建立 在开始构建视频查看器应用程序之前,您将需要通过Git将Cardboard Android SDK克隆到计算机上. 您可以在本系列的上一篇文章中找到有关此操作的说明. 对于我们的示例,使用最低AP ...

  7. 使用Handler创建一个Android秒表应用

    本文所有代码都放在以下链接中:https://github.com/MADMAX110/Stopwatch 0.应用是一个有活动.布局和其他资源组成的集合.其中一个活动是应用的主活动.每个应用都有一个 ...

  8. android 锁屏应用,创建一个Android锁屏应用。

    小编典典 是的,有可能. 这是来自GitHub 的简单锁屏源代码 创建一个像锁一样工作的应用程序没什么大不了的,但是正如您在谈到Home键问题时所说的,我建议您继续开发并尽可能多地开发该应用程序,唯一 ...

  9. 创建一个Android模拟器

    在开发这些手机应用程序时,开发环境一般都提供了模拟器,与真实设备是一样的.可以通过Android SDK and AVD Manager创建模拟器. 2.1.1              创建模拟器 ...

最新文章

  1. 菜鸟成长日记(一)之WMIC简单命令应用
  2. 【堆栈应用一】一个数divided=几个最小质因数的乘积
  3. sysbench压测服务器及结果解读(重点)
  4. 如何在MyEclipse中显示行数
  5. PHP 基础 自动类型转换之比较运算符
  6. vim中如何设置多行注释和删除注释
  7. 获取某一数据库的所有存储过程的名字
  8. Linus Torvalds的安全性,Facebook的AI工具等
  9. spring boot如何创建一个start_如何创建一个简单的Spring应用?
  10. 设置页面包含子页面iframe用法
  11. Android线上轻量级APM性能监测方案
  12. 安装python3.5.0出现0x80072eff错误_我在网上用WINDOWS UPDATE更新WINDOWS,出现错误:0x80072EFF,该怎么办?...
  13. SQL Server 数据库修复专家SQLRescue
  14. 从键盘输入一个英文字母,进行大小写字母转换,并输出。
  15. redis加锁和解锁
  16. 4种公众号文章编辑器亲测对比
  17. C++在视图中显示缩略图
  18. 创龙Xilinx Zynq-7000系列SoC高性能处理器SATA接口
  19. 3个月GMV近4000万,雅鹿在快手找到了品牌自播风向标
  20. 安道麦完成名称统一,挂牌深交所交易

热门文章

  1. github代码虚拟服务器,把github代码自动部署到服务器
  2. java 取余_JAVA面试解析(有赞)
  3. web 前端 如何分享到instagram_面对前端的后端化趋势,2020该如何学习web前端?
  4. python etree详解_使用lxml.etree解析python alexa结果
  5. java 日本时区_java时区时间ZoneOffset, ZoneId,OffsetTime,OffsetDateTi
  6. eclipse32位python版下载_python之(3)Python Eclipse+PyDec下载和安装教程(超级详细)...
  7. 值得收藏的品牌案例—到集设,灵感即到
  8. pandas打印某一列_Pandas数据分析教程
  9. NanoLog软件架构
  10. (3)Linux进程调度-进程切换