在用于图像分类的 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));
}