在Tensorflow-lite Android中将Bitmap转换为ByteBuffer(float)

问题描述 投票:1回答:1

在用于图像分类的tensorflow-lite android演示代码中,首先将图像转换为ByteBuffer格式以获得更好的性能。这种从位图到浮点格式的转换以及随后转换为字节缓冲区似乎是一项昂贵的操作(循环,按位运算符,浮动内存复制等)。我们试图用opencv实现相同的逻辑,以获得一些速度优势。下面的代码工作没有错误;但是由于此转换中存在一些逻辑错误,模型的输出(此数据被输入)似乎是不正确的。模型的输入应该是RGB,数据类型为float [1,197,197,3]。

我们如何使用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 Bitmap到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));
      }
java android opencv tensorflow-lite mappedbytebuffer
1个回答
1
投票
  1. 我相信你的代码中的255/0是一个复制/粘贴错误,而不是真正的代码。
  2. 我想知道纯Java解决方案的时间成本是多少,尤其是当你将它与推理的时间成本进行权衡时。对我而言,对于谷歌的mobilenet_v1_1.0_224稍微大一点的位图,天真浮动缓冲区的准备时间不到推理时间的5%。
  3. 我可以量化tflite模型(使用从.tflite生成.h5文件的相同tflite_convert实用程序。实际上可能有三个量化操作,但我只使用了两个:--inference_input_type=QUANTIZED_UINT8--post_training_quantize。 得到的模型大约是float32 one的25%,这本身就是一项成就。 生成的模型运行速度快两倍(至少在某些设备上)。 并且,结果模型消耗unit8输入。这意味着我们写imgData.putFloat(((val>> 16) & 0xFF) / 255.f)而不是imgData.put((val>> 16) & 0xFF),等等。

顺便说一句,我不认为你的公式是正确的。为了在涉及float32缓冲区时获得最佳精度,我们使用

putFLoat(byteval / 256f)

其中byteval是范围[0:255]中的int。

© www.soinside.com 2019 - 2024. All rights reserved.