Android Camera2 YUV_420_888 图像到 RGBA 位图转换会产生绿色图像

问题描述 投票:0回答:2

在我的Samsung Galaxy A54 5G设备上,运行Android 14,我正在尝试使用camera2 API并以YUV 420格式拍摄图像。设备仅支持 JPEG 和 YUV 420。我尝试了很多方法从 YUV 420 转换为 RGBA 位图并显示/保存它,但无论哪种方法,它们都或多或少地工作并返回一个正确但一个绿色图像。 其中我尝试了以下方法:

如前所述,上述所有方法都会返回绿色(或黄色)图像,其中绿色主要在白色/灰色区域可见,就像下面使用我的开发应用程序拍摄的示例一样:

我期望的正确转换结果与下面的参考屏幕截图非常相似:

更新#1: 在华为设备上尝试了一些可用的代码和示例,颜色正确!例如,使用 ScriptIntrinsicYuvToRGB 的最简单方法在华为设备上给出正确的颜色,但在三星设备上返回绿色图像。显然这是三星的奇怪行为。

更新#2: 谷歌相机示例中提供的 HDRViewFinder 演示提供了正确的颜色,但不幸的是它是渲染脚本部分,我无法在 Xamarin.Android 平台上使用。是否有可能以某种方式将其 hdrmerge 代码重写为本机 Android 代码?

android-bitmap android-camera2 yuv format-conversion
2个回答
0
投票

仍然不是 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;

0
投票

我花了很长时间才弄清楚,但问题终于解决了!

在捕获之前的相机捕获请求设置中,我必须将WhiteBalance设置从Auto更改为Fluorescent,最终图像的绿色色调消失了!

© www.soinside.com 2019 - 2024. All rights reserved.