![](/img/trans.png)
[英]Creating a Bitmap ByteBuffer for quantized Tensorflow Lite Model
[英]Converting Bitmap to ByteBuffer (float) in Tensorflow-lite Android
在用於圖像分類的 tensorflow-lite android 演示代碼中,圖像首先被轉換為 ByteBuffer 格式以獲得更好的性能。 這種從位圖到浮點格式的轉換以及隨后到字節緩沖區的轉換似乎是一個昂貴的操作(循環、按位運算符、 float mem-copy 等)。我們試圖用 opencv 實現相同的邏輯以獲得一些速度優勢。以下代碼可以正常工作; 但是由於這個轉換中的一些邏輯錯誤,模型的輸出(這個數據被饋送到)似乎是不正確的。模型的輸入應該是數據類型為 float[1,197,197,3] 的 RGB。
我們如何使用 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();
// 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
是復制/粘貼錯誤,而不是真正的代碼。mobilenet_v1_1.0_224
稍大的位圖,簡單的浮點緩沖區准備時間不到推理時間的 5%。.h5
生成.tflite
文件的相同tflite_convert實用程序。實際上可能有三個量化操作,但我只使用了兩個: --inference_input_type=QUANTIZED_UINT8
和--post_training_quantize
。
imgData.put((val>> 16) & 0xFF)
而不是imgData.putFloat(((val>> 16) & 0xFF) / 255.f)
imgData.put((val>> 16) & 0xFF)
,依此類推。順便說一句,我不認為你的公式是正確的。 為了在涉及 float32 緩沖區時獲得最佳精度,我們使用
putFLoat(byteval / 256f)
其中byteval
是 [0:255] 范圍內的 int。
如所提到的這里使用下面的代碼從這里用於轉換的位圖,以ByteBuffer(float32)
private fun convertBitmapToByteBuffer(bitmap: Bitmap): ByteBuffer? {
val byteBuffer =
ByteBuffer.allocateDirect(4 * BATCH_SIZE * inputSize * inputSize * PIXEL_SIZE)
byteBuffer.order(ByteOrder.nativeOrder())
val intValues = IntArray(inputSize * inputSize)
bitmap.getPixels(intValues, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
var pixel = 0
for (i in 0 until inputSize) {
for (j in 0 until inputSize) {
val `val` = intValues[pixel++]
byteBuffer.putFloat(((`val` shr 16 and 0xFF) - IMAGE_MEAN) / IMAGE_STD)
byteBuffer.putFloat(((`val` shr 8 and 0xFF) - IMAGE_MEAN) / IMAGE_STD)
byteBuffer.putFloat(((`val` and 0xFF) - IMAGE_MEAN) / IMAGE_STD)
}
}
return byteBuffer
}
對於浮點數,mean = 1 和 std = 255.0 函數將是:
fun bitmapToBytebufferWithOpenCV(bitmap: Bitmap): ByteBuffer {
val startTime = SystemClock.uptimeMillis()
val imgData = ByteBuffer.allocateDirect(1 * 257 * 257 * 3 * 4)
imgData.order(ByteOrder.nativeOrder())
val bufmat = Mat()
val newmat = Mat()
Utils.bitmapToMat(bitmap, bufmat)
Imgproc.cvtColor(bufmat, bufmat, Imgproc.COLOR_RGBA2RGB)
val splitImage: List<Mat> = ArrayList(3)
Core.split(bufmat, splitImage)
splitImage[0].convertTo(splitImage[0], CV_32F, 1.0 / 255.0)
splitImage[1].convertTo(splitImage[1], CV_32F, 1.0 / 255.0)
splitImage[2].convertTo(splitImage[2], CV_32F, 1.0 / 255.0)
Core.merge(splitImage, newmat)
val buf = FloatArray(257 * 257 * 3)
newmat.get(0, 0, buf)
for (i in buf.indices) {
imgData.putFloat(buf[i])
}
imgData.rewind()
val endTime = SystemClock.uptimeMillis()
Log.v("Bitwise", (endTime - startTime).toString())
return imgData
}
不幸的是,這比 Sunit 上面寫的 for 循環和按位運算(8ms)稍慢(10ms)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.