我需要规范化位图并将其存储在 TensorImage 中。有什么办法吗?

I need to normalize a bitmap and store it in a TensorImage. Is there any way to do this?

位图仅包含整数值 (0-255)。我需要将每个像素值除以 255。位图被转换为 TensorImage,然后在将其传递给预测输出的解释器时调用 getBuffer()。(tflite.run()) 在中间的某个地方,我必须将每个 RGB 像素除以 255。恐怕还有另一个缺点,因为 getBuffer() 函数 returns 是一个字节缓冲区。 我找不到很多关于 TensorFlow lite 函数的文档。所以我不确定 tflite.run() 是否只能接受字节缓冲区。 我在 Java 编码并且是 Android AppD 的新手。 请提供帮助,因为这种标准化对于预测正确的值至关重要。

这是调整大小后将位图转换为张量图像的代码。在这里我需要将每个像素值除以 255 但我很困惑。

 private TensorImage resizePic(Bitmap bp) {
        ImageProcessor imageProcessor =
                new ImageProcessor.Builder()
                        .add(new ResizeOp(60, 60, ResizeOp.ResizeMethod.BILINEAR))
                        .build();
        TensorImage tImage = new TensorImage(DataType.FLOAT32);
        tImage.load(bp);
        tImage = imageProcessor.process(tImage);
        return tImage;
    }

这是运行模型的行

tflite.run(tImage.getBuffer(), probabilityBuffer.getBuffer());

probabilityBuffer 保存输出。

我能够使用以下 links-

构建合适的函数
  1. https://heartbeat.fritz.ai/image-classification-on-android-with-tensorflow-lite-and-camerax-4f72e8fdca79

第二个 link 在 Kotlin 中。这是代码:

private ByteBuffer convertBitmapToByteBuffer(Bitmap bp) {
        ByteBuffer imgData = ByteBuffer.allocateDirect(Float.BYTES*60*60*3);
        imgData.order(ByteOrder.nativeOrder());
        Bitmap bitmap = Bitmap.createScaledBitmap(bp,60,60,true);
        int [] intValues = new int[60*60];
        bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());

        // Convert the image to floating point.
        int pixel = 0;

        for (int i = 0; i < 60; ++i) {
            for (int j = 0; j < 60; ++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);
            }
        }
        return imgData;
    }

这里,60是我要求的输入图片的高度和宽度。此外,此方法不需要使用 TensorImage。所以 tflite.run() 的最终调用看起来像这样:

tflite.run(convertBitmapToByteBuffer(bp), probabilityBuffer.getBuffer());

这里,bp是位图图像。

训练模型时不要对图像进行归一化。因此,当您部署应用程序时,无需规范化位图图像。

您的第一个参考资料给出了使用 Opencv 进行转换的示例。这是我想出的有效方法:

private ByteBuffer getImageDataForTfliteModelOpencv(Bitmap input) {
    if (input == null) {
        return null;
    }
    // Allocate output ByteBuffer
    ByteBuffer output = ByteBuffer.allocateDirect(1 * TFL_IMAGE_SIZE *
            TFL_IMAGE_SIZE * 3 * Float.BYTES);
    //
    output.order(ByteOrder.nativeOrder());
    output.rewind();

    Mat bufmat = new Mat();
    Mat newmat = new Mat(TFL_IMAGE_SIZE, TFL_IMAGE_SIZE, CvType.CV_32FC3);

    Utils.bitmapToMat(input, bufmat);
    Imgproc.cvtColor(bufmat, bufmat, Imgproc.COLOR_RGBA2RGB);
    bufmat.convertTo(newmat, CvType.CV_32FC3, 1.0/255.0);
    //
    // Write the image float data to the output ByteBuffer
    float buf[] = new float[TFL_IMAGE_SIZE * TFL_IMAGE_SIZE * 3];
    newmat.get(0,0, buf); // Get the float data
    output.asFloatBuffer().put(buf); // Write it as a stream of bytes
    return output;
}

然后可以轻松地将返回的 ByteBuffer 加载到 TensorBuffer 中。我测试了这两种方法,对于 112x112 图像,这种 Opencv 方法快了大约 50 毫秒。

如前所述 here use the below code from here 用于将位图转换为 ByteBuffer(float32)

private ByteBuffer convertBitmapToByteBuffer(Bitmap bitmap) {
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4 * BATCH_SIZE * inputSize * inputSize * PIXEL_SIZE);
    byteBuffer.order(ByteOrder.nativeOrder());
    int[] intValues = new int[inputSize * inputSize];
    bitmap.getPixels(intValues, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
    int pixel = 0;
    for (int i = 0; i < inputSize; ++i) {
        for (int j = 0; j < inputSize; ++j) {
            final int val = intValues[pixel++];
            byteBuffer.putFloat((((val >> 16) & 0xFF)-IMAGE_MEAN)/IMAGE_STD);
            byteBuffer.putFloat((((val >> 8) & 0xFF)-IMAGE_MEAN)/IMAGE_STD);
            byteBuffer.putFloat((((val) & 0xFF)-IMAGE_MEAN)/IMAGE_STD);
        }
    }
    return byteBuffer;
}