\n
What I would expect as a correct conversion result is something very similar to the below reference screenshot:\n
Update #1:\nTried some of the available codes & examples on a Huawei device and there are the colors correct! For example the simplest way using ScriptIntrinsicYuvToRGB gives correct colors on the Huawei device but returns greenish image on Samsung. Apparently it's a weird Samsung behaviour.
\nUpdate #2:\nThe HDRViewFinder demo available in google camera samples gives correct color but unfortunately it's renderscript part I can't use on Xamarin.Android platform. Is it possible to somehow rewrite it's hdrmerge code to a native Android code?
\n","author":{"@type":"Person","name":"Ladislav"},"upvoteCount":1,"answerCount":2,"acceptedAnswer":{"@type":"Answer","text":"It took me ages to figure out but problem finally solved!
\nIn the camera capture request settings before capture I had to change the WhiteBalance settings from Auto to Fluorescent and the green tint from final image is gone!
\n","author":{"@type":"Person","name":"Ladislav"},"upvoteCount":0}}}Reputation: 349
On my Samsung Galaxy A54 5G device with Android 14 I am trying the camera2 API and to take image in YUV 420 format. Device only supports JPEG and YUV 420. I tried many of methods to convert from YUV 420 to RGBA bitmap and display/save it but no matter which method, all of them works more or less and returns a correct but a greenish image. Among others I tried the below methods:
As mentioned earlier, all of the above methods are returning a greenish (or yellowish) image, where the greenish is visible mostly on white/gray areas, like the below example taken with my dev app:
What I would expect as a correct conversion result is something very similar to the below reference screenshot:
Update #1: Tried some of the available codes & examples on a Huawei device and there are the colors correct! For example the simplest way using ScriptIntrinsicYuvToRGB gives correct colors on the Huawei device but returns greenish image on Samsung. Apparently it's a weird Samsung behaviour.
Update #2: The HDRViewFinder demo available in google camera samples gives correct color but unfortunately it's renderscript part I can't use on Xamarin.Android platform. Is it possible to somehow rewrite it's hdrmerge code to a native Android code?
Upvotes: 1
Views: 458
Reputation: 349
It took me ages to figure out but problem finally solved!
In the camera capture request settings before capture I had to change the WhiteBalance settings from Auto to Fluorescent and the green tint from final image is gone!
Upvotes: 0
Reputation: 349
Still not the 100% statisfying solution but at least it gives much much better colors after the YUV -> RGB conversion. Plus it is slow for very high resolution images. The below code is a combination of this answer and this renderscript kernel:
case ImageFormatType.Yuv420888:
var planes = img.GetPlanes();
var yPlane = planes[0];
var uPlane = planes[1];
var vPlane = planes[2];
var rgbBytes = new int[img.Height * img.Width];
var idx = 0;
var yBuffer = yPlane.Buffer;
var yPixelStride = yPlane.PixelStride;
var yRowStride = yPlane.RowStride;
var uBuffer = uPlane.Buffer;
var uPixelStride = uPlane.PixelStride;
var uRowStride = uPlane.RowStride;
var vBuffer = vPlane.Buffer;
var vPixelStride = vPlane.PixelStride;
var vRowStride = vPlane.RowStride;
for (var row = 0; row < img.Height; row++) {
for (var col = 0; col < img.Width; col++) {
var Y = (byte)yBuffer.Get(col * yPixelStride + row * yRowStride);
var U = (byte)uBuffer.Get(col / 2 * uPixelStride + row / 2 * uRowStride);
var V = (byte)vBuffer.Get(col / 2 * vPixelStride + row / 2 * vRowStride);
// Convert YUV to RGB, JFIF transform with fixed-point math.
// Formulas can be found here: https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion
// R = Y + 1.402 * (V - 128)
// G = Y - 0.34414 * (U - 128) - 0.71414 * (V - 128)
// B = Y + 1.772 * (U - 128)
var R = Y + 1436 / 1024 * (V - 128);
var G = Y - 46549 / 131072 * (U - 128) - 93604 / 131072 * (V - 128);
var B = Y + 1814 / 1024 * (U - 128);
R = MathUtils.Clamp(R, 0, 255);
G = MathUtils.Clamp(G, 0, 255);
B = MathUtils.Clamp(B, 0, 255);
rgbBytes[idx++] = BitConverter.ToInt32(new byte[] { (byte)B, (byte)G, (byte)R, 0xFF }, 0);
}
}
FinalBitmap = Bitmap.CreateBitmap(rgbBytes, img.Width, img.Height, Bitmap.Config.Argb8888);
img.Close();
break;
Upvotes: 1