I’m trying to convert YUV_420_888 images into bitmaps, coming from the camera2 preview. But the output image has incorrect colors.
Next is the test code I’m running to generate the bitmap. Is test code only, so please don’t do any code review about not relevant factors such as the bitmap is being recycled, or the RenderScript is continuously been created. This code is just to test the conversion from YUV to RGB and nothing more.
Other factors, the code is meant to run from API 22 and above, therefore using RenderScript specific ScriptIntrinsicYuvToRGB should be sufficient, without having to use old manual conversions which where necessary only in previous Android versions due to lack of proper YUV_420_888 support.
As RenderScript already offers a dedicated ScriptIntrinsicYuvToRGB which is meant to handle all types of YUV conversions, I think the problem could be in how I get the YUV byte data from the Image object, but I can't figure where the issue is.
To view the output bitmap in Android Studio, place a breakpoint in bitmap.recycle(), so before it gets recycled you can look at it in the Variables Debug Window by using the “view bitmap” option.
Please let me know if anyone can spot what’s wrong with the conversion:
@Override
public void onImageAvailable(ImageReader reader)
{
RenderScript rs = RenderScript.create(this.mContext);
final Image image = reader.acquireLatestImage();
final Image.Plane[] planes = image.getPlanes();
final ByteBuffer planeY = planes[0].getBuffer();
final ByteBuffer planeU = planes[1].getBuffer();
final ByteBuffer planeV = planes[2].getBuffer();
// Get the YUV planes data
final int Yb = planeY.rewind().remaining();
final int Ub = planeU.rewind().remaining();
final int Vb = planeV.rewind().remaining();
final ByteBuffer yuvData = ByteBuffer.allocateDirect(Yb + Ub + Vb);
planeY.get(yuvData.array(), 0, Yb);
planeU.get(yuvData.array(), Yb, Vb);
planeV.get(yuvData.array(), Yb + Vb, Ub);
// Initialize Renderscript
Type.Builder yuvType = new Type.Builder(rs, Element.YUV(rs))
.setX(image.getWidth())
.setY(image.getHeight())
.setYuvFormat(ImageFormat.YUV_420_888);
final Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs))
.setX(image.getWidth())
.setY(image.getHeight());
Allocation yuvAllocation = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
Allocation rgbAllocation = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
// Convert
yuvAllocation.copyFromUnchecked(yuvData.array());
ScriptIntrinsicYuvToRGB scriptYuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.YUV(rs));
scriptYuvToRgb.setInput(yuvAllocation);
scriptYuvToRgb.forEach(rgbAllocation);
// Get the bitmap
Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
rgbAllocation.copyTo(bitmap);
// Release
bitmap.recycle();
yuvAllocation.destroy();
rgbAllocation.destroy();
rs.destroy();
image.close();
}