我需要对位图进行标准化并将其存储在TensorImage中。有没有什么方法可以做到这一点?

3

位图仅包含整数值(0-255)。我需要将每个像素值除以255。该位图转换为TensorImage,并在将其传递给预测输出的解释器时调用getBuffer()。 在中间某个位置,我必须将每个RGB像素除以255。恐怕还有一个缺点,即getBuffer()函数返回一个字节缓冲区。 我找不到关于TensorFlow Lite函数的很多文档。因此,我不确定tflite.run()是否只能接受字节缓冲区。 我正在使用Java编码,并且是Android AppD的新手。 请帮忙,因为这种归一化对于预测正确的值非常重要。

这是将位图调整大小后转换为TensorImage的代码。在这里,我需要将每个像素值除以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 保存输出结果。


ImageProcessor类中还有其他运算符,您可以使用NormalizeOp。请参阅https://www.tensorflow.org/lite/inference_with_metadata/lite_support#imageprocessor_architecture。 - Farmaker
5个回答

3
我可以使用以下链接构建适当的函数-
  1. 将位图转换为Tensorflow-lite Android中的ByteBuffer(float)

  2. https://heartbeat.fritz.ai/image-classification-on-android-with-tensorflow-lite-and-camerax-4f72e8fdca79

第二个链接是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 是位图图像。


0

我找到了答案:

private TensorImage resizePic(Bitmap bp) {
    ImageProcessor imageProcessor =
            new ImageProcessor.Builder()
                    .add(new ResizeOp(60, 60, ResizeOp.ResizeMethod.BILINEAR))
                    .add(new NormalizeOp(0f, 255f))
                    .build();
    TensorImage tImage = new TensorImage(DataType.FLOAT32);
    tImage.load(sourceBitmap);
    System.out.println("tensorImage0: " + tImage.getTensorBuffer().getFloatArray()[0]);
    tImage = imageProcessor.process(tImage);
    System.out.println("tensorImage1: " + tImage.getTensorBuffer().getFloatArray()[0]);
    return tImage;
}

终端:
System.out: tensorImage0: 232.0
System.out: tensorImage1: 0.9254902

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Kunal Varpe

0

你的第一个参考示例使用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毫秒。


0

此处所述,请使用此处中的以下代码将位图转换为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;
}

0
在训练模型时不要对图像进行归一化处理。因此,当你部署应用程序时,没有必要对位图图像进行归一化处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接