在我的Samsung Galaxy A54 5G设备上,运行Android 14,我正在尝试使用camera2 API并以YUV 420格式拍摄图像。设备仅支持 JPEG 和 YUV 420。我尝试了很多方法从 YUV 420 转换为 RGBA 位图并显示/保存它,但无论哪种方法,它们都或多或少地工作并返回一个正确但一个绿色图像。 其中我尝试了以下方法:
如前所述,上述所有方法都会返回绿色(或黄色)图像,其中绿色主要在白色/灰色区域可见,就像下面使用我的开发应用程序拍摄的示例一样:
更新#1: 在华为设备上尝试了一些可用的代码和示例,颜色正确!例如,使用 ScriptIntrinsicYuvToRGB 的最简单方法在华为设备上给出正确的颜色,但在三星设备上返回绿色图像。显然这是三星的奇怪行为。
更新#2: 谷歌相机示例中提供的 HDRViewFinder 演示提供了正确的颜色,但不幸的是它是渲染脚本部分,我无法在 Xamarin.Android 平台上使用。是否有可能以某种方式将其 hdrmerge 代码重写为本机 Android 代码?
仍然不是 100% 令人满意的解决方案,但至少它在 YUV -> RGB 转换后提供了 更好的颜色。另外,对于非常高分辨率的图像来说,速度很慢。下面的代码是 this 答案和 this 渲染脚本内核的组合:
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;
我花了很长时间才弄清楚,但问题终于解决了!
在捕获之前的相机捕获请求设置中,我必须将WhiteBalance设置从Auto更改为Fluorescent,最终图像的绿色色调消失了!