3

I am trying to use a tflite model in my android app. The problem arises when I have to create a ByteBuffer out of the Bitmap and use it as Input to the model.

Problem: Bitmap is ARGB_8888 (32 bit) whereas I need (8 bit) grayscale image.

Method to convert Bitmap to ByteBuffer:

mImgData = ByteBuffer
                .allocateDirect(4 * 28 * 28 * 1);

private void convertBitmapToByteBuffer(Bitmap bitmap) throws NullPointerException {
    if (mImgData == null) {
        throw new NullPointerException("Error: ByteBuffer not initialized.");
    }

    mImgData.rewind();

    for (int i = 0; i < DIM_IMG_SIZE_WIDTH; i++) {
        for (int j = 0; j < DIM_IMG_SIZE_HEIGHT; j++) {
            int pixelIntensity = bitmap.getPixel(i, j);
            unpackPixel(pixelIntensity, i, j);
            Log.d(TAG, String.format("convertBitmapToByteBuffer: %d -> %f", pixelIntensity, convertToGrayScale(pixelIntensity)));
            mImgData.putFloat(convertToGrayScale(pixelIntensity));
        }
    }

}

private float convertToGrayScale(int color) {
    return (((color >> 16) & 0xFF) + ((color >> 8) & 0xFF) + (color & 0xFF)) / 3.0f / 255.0f;
}

However, all the pixel values are either -1 or -16777216. Note that that unpackPixel method mentioned here doesn't work, since all values have the same int value anyway. (Posted with changes below for reference.)

private void unpackPixel(int pixel, int row, int col) {
    short red,green,blue;
    red = (short) ((pixel >> 16) & 0xFF);
    green = (short) ((pixel >> 8) & 0xFF);
    blue = (short) ((pixel >> 0) & 0xFF);
}
code
  • 2,115
  • 1
  • 22
  • 46

1 Answers1

2

You can call Color.red() or green/blue on the pixel value and it will return the gray intensity. Then just put it in the byte buffer using putFloat(). Also getting all pixel values in a single array using bitmap.getPixels() is comparatively faster than bitmap.getPixel(i, j). Here's how I am doing it to load grayscale images in my tflite model:

private ByteBuffer getByteBuffer(Bitmap bitmap){
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    ByteBuffer mImgData = ByteBuffer
            .allocateDirect(4 * width * height);
    mImgData.order(ByteOrder.nativeOrder());
    int[] pixels = new int[width*height];
    bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
    for (int pixel : pixels) {
        mImgData.putFloat((float) Color.red(pixel));
    }
    return mImgData;
}

If you need normalized values just divide by 255:

float value = (float) Color.red(pixel)/255.0f;
mImgData.putFloat(value);

You can then use this in your interpreter as:

ByteBuffer input = getByteBuffer(bitmap);
tflite.run(input, outputValue);

Hope this helps people looking for this in the future!