TensorFlow on Android(4): 输入数据预处理和Inference

2024-02-10 20:48

本文主要是介绍TensorFlow on Android(4): 输入数据预处理和Inference,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Graph,Op, Tensor

在开始输入数据之前,我们先简单讲一下TensorFlow中的一些概念

一个 TensorFlow 的计算任务, 叫做Graph, 一个Graph由很多节点(Op)组成, Op通过Tensor获取输入,Op完成计算以后再通过Tensor把输出传递到下一个节点。

Tensor一般来说是一个数组(1维或多维),我们用Feed操作将一个Tensor的数据输入到一个Op, 用Fetch操作将Op的输出提取到Tensor当中

那么回到我们的项目中来,为了进行物体的识别,我们要做就是相应的Op中输入图片数据, 然后从相应的Op提取识别结果

我们在这里可以找到我们使用的模型的大致架构
enter image description here
那么可以这样说, 我们向名为“image_tensor”的Op中输入图片数据, 然后从多个Op中获取识别结果,这样的Op有4个

  • “detection_boxes”, 输出识别物体的矩形框
  • “detection_scores”, 输出识别物体的Confidence, 用来衡量识别得准确性有多大
  • “detection_classes”, 识别物体的种类
  • “num_detections”, 识别物体的数量

明白了我们该怎么做以后, 我们开始写代码吧!

设计界面

首先我们需要设计一个界面, 有一个Button用来呼出相册, 以及一个ImageView来显示图片和识别结果, 大致是这样的
enter image description here

然后我们需要写一些代码来实现从相册从提取图片,并显示在ImageView上面
因为这些代码都很简单,而且很多现成代码可以参考,这里就不再详述了。

数据预处理

在将图片数据Feed到我们的模型之前,我们还需要对图片数据进行一些处理,将它转换为我们模型能够识别和处理的数据。我们用Bitmap作为最原始的输入数据,我们需要做下面的一些处理:

第一步是图片尺寸, 每一个图片的长宽都是不一样的,但是我们希望把所有的输入图片都处理成一样的尺寸,比如说300X300,所以我们需要写一些图片尺寸转换的代码,这样的代码如果自己不会写,在网上也可以找到很多现成的代码,下面也是从开源的代码里面参考来的转换函数:

public class Utils {
public static Matrix getImageTransformationMatrix(final int srcWidth,final int srcHeight,final int dstWidth,final int dstHeight,final int applyRotation,final boolean maintainAspectRatio) {final Matrix matrix = new Matrix();if (applyRotation != 0) {matrix.postTranslate(-srcWidth / 2.0f, -srcHeight / 2.0f);matrix.postRotate(applyRotation);}final boolean transpose = (Math.abs(applyRotation) + 90) % 180 == 0;final int inWidth = transpose ? srcHeight : srcWidth;final int inHeight = transpose ? srcWidth : srcHeight;if (inWidth != dstWidth || inHeight != dstHeight) {final float scaleFactorX = dstWidth / (float) inWidth;final float scaleFactorY = dstHeight / (float) inHeight;if (maintainAspectRatio) {final float scaleFactor = Math.max(scaleFactorX, scaleFactorY);matrix.postScale(scaleFactor, scaleFactor);} else {matrix.postScale(scaleFactorX, scaleFactorY);}}if (applyRotation != 0) {matrix.postTranslate(dstWidth / 2.0f, dstHeight / 2.0f);}return matrix;}
}

这个函数会返回进行图片尺寸转换所需要的Matrix对象,这很有用,我们在后面可视化识别结果的时候用的着。然后我们通过下面的代码来完成转换

Bitmap bitmapInput = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
final Matrix originToInput = Utils.getImageTransformationMatrix(originImage.getWidth(), originImage.getHeight(), 300, 300,0, false);
final Canvas canvas = new Canvas(bitmapInput);
canvas.drawBitmap(originImage, originToInput, null);

第二步是将二维的位图数据转换为一维的数组, 我们的模型接受的输入是由图片的像素点RGB值组成的一维数组, 比如说有2个像素点(用(R,G,B)表示),(1,2,3),(4,5,6),那么正确的输入数组应该是[1, 2, 3, 4, 5, 6], 我们可以通过下面的代码来完成

int[] pixels = new int[300 * 300];
bitmapInput.getPixels(pixels, 0, bitmapInput.getWidth(), 0, 0, bitmapInput.getWidth(), bitmapInput.getHeight());
byte[] byteInput = new byte[pixels.length * 3];
for (int i = 0; i < pixels.length; ++i) {byteInput[i * 3 + 2] = (byte) (pixels[i] & 0xFF);byteInput[i * 3 + 1] = (byte) ((pixels[i] >> 8) & 0xFF);byteInput[i * 3 + 0] = (byte) ((pixels[i] >> 16) & 0xFF);}

我们先通过getPixels获取位图所有像素的一维数组,再通过位操作分别提取每个像素的RGB值,然后赋值到byteInput数组的相应位置中, byteInput数组就是处理好的,准备Inference的数据了

Inference

我们通过调用TensorFlowInferenceInterface的Feed方法来向模型中输入数据

inferenceInterface.feed("image_tensor", byteInput, 1, 300, 300, 3);

这个代码的意思是向名为“image_tensor”的Op输入相应的数据: 图片数据,值为 byteInput; batch_size, 我们输入的是一张图片的数据,所以值为1; 图片的高和宽,都是300;通道数,因为我们使用RGB,所以值为3

接下来我们分配一些数组(Tensor)来准备接受Inference的结果,我们只取物体位置, 分数,物体类型的数据, 在这里我们最多取前100个识别结果:

float[] boxes = new float[100 * 4];
float[] scores = new float[100];
float[] classes = new float[100];

因为一个矩形框(box)是由(top,left, botton,right)的4元组表示的,所以boxes数组的大小应该是 100X4。分配好数组以后, 我们就可以开始inference, 并从相应的Op里面提取识别结果, 代码如下:

inferenceInterface.run(new String[]{"detection_boxes", "detection_scores","detection_classes"}, false);
float[] boxes = new float[MAX_RESULTS * 4];
float[] scores = new float[MAX_RESULTS];
float[] classes = new float[MAX_RESULTS];
inferenceInterface.fetch("detection_boxes", boxes);
inferenceInterface.fetch("detection_scores", scores);
inferenceInterface.fetch("detection_classes", classes);

我们使用TensorFlowInferenceInterface的Run方法来启动从之前用Feed注册的输入节点(image_tensor)到由参数指定的输出节点(detection_boxes, detection_scores,detection_classes)的Inference, 对我们来说,就是从输入的图片数据,识别出物体的位置,类别,和分数。然后我们用 Fetch方法来提取相应的输出数据。

现在我们已经得到了识别结果,接下来准备把结果可视化吧!

这篇关于TensorFlow on Android(4): 输入数据预处理和Inference的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/698043

相关文章

8种快速易用的Python Matplotlib数据可视化方法汇总(附源码)

《8种快速易用的PythonMatplotlib数据可视化方法汇总(附源码)》你是否曾经面对一堆复杂的数据,却不知道如何让它们变得直观易懂?别慌,Python的Matplotlib库是你数据可视化的... 目录引言1. 折线图(Line Plot)——趋势分析2. 柱状图(Bar Chart)——对比分析3

Spring Boot 整合 Redis 实现数据缓存案例详解

《SpringBoot整合Redis实现数据缓存案例详解》Springboot缓存,默认使用的是ConcurrentMap的方式来实现的,然而我们在项目中并不会这么使用,本文介绍SpringB... 目录1.添加 Maven 依赖2.配置Redis属性3.创建 redisCacheManager4.使用Sp

Python Pandas高效处理Excel数据完整指南

《PythonPandas高效处理Excel数据完整指南》在数据驱动的时代,Excel仍是大量企业存储核心数据的工具,Python的Pandas库凭借其向量化计算、内存优化和丰富的数据处理接口,成为... 目录一、环境搭建与数据读取1.1 基础环境配置1.2 数据高效载入技巧二、数据清洗核心战术2.1 缺失

Python处理超大规模数据的4大方法详解

《Python处理超大规模数据的4大方法详解》在数据的奇妙世界里,数据量就像滚雪球一样,越变越大,从最初的GB级别的小数据堆,逐渐演变成TB级别的数据大山,所以本文我们就来看看Python处理... 目录1. Mars:数据处理界的 “变形金刚”2. Dask:分布式计算的 “指挥家”3. CuPy:GPU

使用Vue-ECharts实现数据可视化图表功能

《使用Vue-ECharts实现数据可视化图表功能》在前端开发中,经常会遇到需要展示数据可视化的需求,比如柱状图、折线图、饼图等,这类需求不仅要求我们准确地将数据呈现出来,还需要兼顾美观与交互体验,所... 目录前言为什么选择 vue-ECharts?1. 基于 ECharts,功能强大2. 更符合 Vue

Java如何根据word模板导出数据

《Java如何根据word模板导出数据》这篇文章主要为大家详细介绍了Java如何实现根据word模板导出数据,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... pom.XML文件导入依赖 <dependency> <groupId>cn.afterturn</groupId>

Python实现获取带合并单元格的表格数据

《Python实现获取带合并单元格的表格数据》由于在日常运维中经常出现一些合并单元格的表格,如果要获取数据比较麻烦,所以本文我们就来聊聊如何使用Python实现获取带合并单元格的表格数据吧... 由于在日常运维中经常出现一些合并单元格的表格,如果要获取数据比较麻烦,现将将封装成类,并通过调用list_exc

Mysql数据库中数据的操作CRUD详解

《Mysql数据库中数据的操作CRUD详解》:本文主要介绍Mysql数据库中数据的操作(CRUD),详细描述对Mysql数据库中数据的操作(CRUD),包括插入、修改、删除数据,还有查询数据,包括... 目录一、插入数据(insert)1.插入数据的语法2.注意事项二、修改数据(update)1.语法2.有

SpringBoot实现接口数据加解密的三种实战方案

《SpringBoot实现接口数据加解密的三种实战方案》在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取,SpringBoot提供了多种优雅的加解密实现方案,本文将从原... 目录一、为什么需要接口数据加解密?二、核心加解密算法选择1. 对称加密(AES)2. 非对称加密(R

详解如何在SpringBoot控制器中处理用户数据

《详解如何在SpringBoot控制器中处理用户数据》在SpringBoot应用开发中,控制器(Controller)扮演着至关重要的角色,它负责接收用户请求、处理数据并返回响应,本文将深入浅出地讲解... 目录一、获取请求参数1.1 获取查询参数1.2 获取路径参数二、处理表单提交2.1 处理表单数据三、