java - 在 Tensorflow-lite Android 中将位图转换为 ByteBuffer(浮点数)
问题描述
在用于图像分类的 tensorflow-lite android 演示代码中,首先将图像转换为 ByteBuffer 格式以获得更好的性能。这种从位图到浮点格式的转换以及随后到字节缓冲区的转换似乎是一项昂贵的操作(循环、位运算符、 float mem-copy 等)。我们试图用 opencv 实现相同的逻辑以获得一些速度优势。以下代码可以正常工作;但由于此转换中的一些逻辑错误,模型的输出(此数据被输入)似乎不正确。模型的输入应该是数据类型为浮点 [1,197,197,3] 的 RGB。
我们如何使用opencv(或任何其他方式)加快位图到字节缓冲区转换的过程?
标准位图到字节缓冲区的转换:-
/** Writes Image data into a {@code ByteBuffer}. */
private void convertBitmapToByteBuffer(Bitmap bitmap) {
if (imgData == null) {
return;
}
imgData.rewind();
bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
long startTime = SystemClock.uptimeMillis();
// Convert the image to floating point.
int pixel = 0;
for (int i = 0; i < getImageSizeX(); ++i) {
for (int j = 0; j < getImageSizeY(); ++j) {
final int val = intValues[pixel++];
imgData.putFloat(((val>> 16) & 0xFF) / 255.f);
imgData.putFloat(((val>> 8) & 0xFF) / 255.f);
imgData.putFloat((val & 0xFF) / 255.f);
}
}
long endTime = SystemClock.uptimeMillis();
Log.d(TAG, "Timecost to put values into ByteBuffer: " + Long.toString(endTime - startTime));
}
OpenCV 位图到 ByteBuffer :-
/** Writes Image data into a {@code ByteBuffer}. */
private void convertBitmapToByteBuffer(Bitmap bitmap) {
if (imgData == null) {
return;
}
imgData.rewind();
bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
long startTime = SystemClock.uptimeMillis();
Mat bufmat = new Mat(197,197,CV_8UC3);
Mat newmat = new Mat(197,197,CV_32FC3);
Utils.bitmapToMat(bitmap,bufmat);
Imgproc.cvtColor(bufmat,bufmat,Imgproc.COLOR_RGBA2RGB);
List<Mat> sp_im = new ArrayList<Mat>(3);
Core.split(bufmat,sp_im);
sp_im.get(0).convertTo(sp_im.get(0),CV_32F,1.0/255/0);
sp_im.get(1).convertTo(sp_im.get(1),CV_32F,1.0/255.0);
sp_im.get(2).convertTo(sp_im.get(2),CV_32F,1.0/255.0);
Core.merge(sp_im,newmat);
//bufmat.convertTo(newmat,CV_32FC3,1.0/255.0);
float buf[] = new float[197*197*3];
newmat.get(0,0,buf);
//imgData.wrap(buf).order(ByteOrder.nativeOrder()).getFloat();
imgData.order(ByteOrder.nativeOrder()).asFloatBuffer().put(buf);
long endTime = SystemClock.uptimeMillis();
Log.d(TAG, "Timecost to put values into ByteBuffer: " + Long.toString(endTime - startTime));
}
解决方案
- 我相信
255/0
您的代码中存在复制/粘贴错误,而不是真实代码。 - 我想知道纯 Java 解决方案的时间成本是多少,尤其是当您将其与推理的时间成本进行权衡时。对我来说,使用 Google 的稍大一点的位图
mobilenet_v1_1.0_224
,天真的浮点缓冲区准备时间不到推理时间的 5%。 - 我可以量化 tflite 模型(使用相同的tflite_convert实用程序
.tflite
从.h5
.--inference_input_type=QUANTIZED_UINT8
--post_training_quantize
- 生成的模型大约是 float32 模型的 25%,这本身就是一项成就。
- 生成的模型运行速度大约快两倍(至少在某些设备上)。
- 并且,生成的模型消耗unit8输入。这意味着不是
imgData.putFloat(((val>> 16) & 0xFF) / 255.f)
我们写imgData.put((val>> 16) & 0xFF)
,等等。
顺便说一句,我不认为你的公式是正确的。为了在涉及 float32 缓冲区时获得最佳精度,我们使用
putFLoat(byteval / 256f)
其中byteval
int 在 [0:255] 范围内。
推荐阅读
- microsoft-graph-api - 尝试使用 MS Graph API 创建 apload 会话时出现 HTTP 错误 405
- python - 遍历文件夹中的文件名并使用 Python 重命名
- java - 滚动时将 ImageView 和 headed 视图固定在顶部,并使其他视图在 android 中可滚动
- c - 在 /dev/mem 上使用 mmap 时内存使用量是否翻倍?
- python - 选择文件成功执行但没有在机器人框架中上传文件
- class - 如何在类中获取类型参数的擦除类型
- laravel - Livewire 是否替换了 Laravel 中的 Vue.js/React.js?
- javascript - 为什么我从两种形式的相同数学表达式 [javascript] 中得到不同的结果?
- python - 组合多个列表以获得给定条件的整数
- python - ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败:无法获取本地颁发者证书 (_ssl.c:1123)