YUV NV21 转换为 RGB 的困惑

Posted

技术标签:

【中文标题】YUV NV21 转换为 RGB 的困惑【英文标题】:Confusion on YUV NV21 conversion to RGB 【发布时间】:2012-09-10 06:53:51 【问题描述】:

根据http://developer.android.com/reference/android/graphics/ImageFormat.html#NV21,NV21是默认使用的格式。

网上有很多关于 YUV NV21 到 RGB 转换的代码。但是,当我浏览代码时,我怀疑代码的正确性。

第一个分量 V 应该在前,然后是第一个分量 U

根据http://wiki.videolan.org/YUV#NV21,NV21 is like NV12, but with U and V order reversed: it starts with V. 但是,当我通过代码实现时

http://pastebin.com/T0my7zSc - 它假设 U 是第一位的 https://***.com/a/8394202/72437 - 它也假设 U 是第一位的 https://***.com/a/10125048/72437 - 它认为你也是第一位的

R应该是最重要的位置 根据int argb 在Color.java 中的实现,R 假设在最重要的位置。但是,我经历了以下代码实现

http://pastebin.com/T0my7zSc - 它假设 R 是最不重要的位置 https://***.com/a/8394202/72437 - 它假设 R 是最不重要的位置

我想知道,是他们犯了常见的错误,还是我忽略了什么?

目前,我的实现如下。

public static void YUV_NV21_TO_RGB(int[] argb, byte[] yuv, int width, int height) 
    final int frameSize = width * height;

    final int ii = 0;
    final int ij = 0;
    final int di = +1;
    final int dj = +1;

    int a = 0;
    for (int i = 0, ci = ii; i < height; ++i, ci += di) 
        for (int j = 0, cj = ij; j < width; ++j, cj += dj) 
            int y = (0xff & ((int) yuv[ci * width + cj]));
            int v = (0xff & ((int) yuv[frameSize + (ci >> 1) * width + (cj & ~1) + 0]));
            int u = (0xff & ((int) yuv[frameSize + (ci >> 1) * width + (cj & ~1) + 1]));
            y = y < 16 ? 16 : y;

            int r = (int) (1.164f * (y - 16) + 1.596f * (v - 128));
            int g = (int) (1.164f * (y - 16) - 0.813f * (v - 128) - 0.391f * (u - 128));
            int b = (int) (1.164f * (y - 16) + 2.018f * (u - 128));

            r = r < 0 ? 0 : (r > 255 ? 255 : r);
            g = g < 0 ? 0 : (g > 255 ? 255 : g);
            b = b < 0 ? 0 : (b > 255 ? 255 : b);

            argb[a++] = 0xff000000 | (r << 16) | (g << 8) | b;
        
    

【问题讨论】:

对我来说,您的代码完美运行,实际上是唯一不改变任何图片属性(如亮度或颜色)的代码。 在许多接受颜色参数或以 int 形式返回颜色的 android 函数中,它们返回的 R 是最重要的,因此它的 0xAARRGGBB,但是在使用 JNI 时,在 android 位图的实际内存布局中并直接访问 C/C++ 字节,它与 R 是内存中的第一个字节相反,你得到 0xAABBGGRR。 【参考方案1】:

首先,我在图像编码方面并不是很有经验(大约一年前对此有一些有限的了解)。所以,对我的回答持保留态度。

但是,我相信你是对的。我认为在他们的代码中 a) V 和 U 翻转 b) R 和 B 翻转

我有一种感觉,当这两个东西都被翻转时,它会产生与它们没有被翻转一样的结果。这就是为什么您可以在许多地方找到错误代码的原因(最初,有人弄错了,然后将其复制到各处,因为生成的代码可以正常工作(但是,变量命名不正确))。

这是另一个代码示例(与您的代码相同): http://www.41post.com/3470/programming/android-retrieving-the-camera-preview-as-a-pixel-array

【讨论】:

【参考方案2】:

像“最重要位置”这样的术语是模棱两可的,因为它取决于机器的字节序。

当所有数据类型都是 8 位时,有一个简单明确的规范:字节顺序。例如, 无符号字符 rgba[4]; 会将数据存储为 rgba[0] = r; rgba[1] = g; rgba[2] = b; rgba[3] = a;

或 r, g, b, a ,无论处理器的字节顺序如何。

如果你这样做了

int32 颜色 = (r

你会得到 r, g, b, a 在大端系统上,并且 a, r, g, b 在小端系统上。 您是否在具有异构处理器的系统上工作?就像你有一个 CPU 和一个 GPU 一样?他们怎么知道对方正在使用哪个字节序?你最好定义字节顺序。

【讨论】:

阅读问题链接的规范:指定了小端字节序。 另外,该问题被标记为 Android,并且所有支持的 Android 版本都使用 little-endian 硬件。

以上是关于YUV NV21 转换为 RGB 的困惑的主要内容,如果未能解决你的问题,请参考以下文章

初识YUV,实战NV21格式数据转换为Bitmap

将 Android camera2 api YUV_420_888 转换为 RGB

YUV与RGB 以及之间的转换

C语言实现RGB packet格式转YUV(NV21)格式

在 OpenCV 中将 YUV 转换为 BGR 或 RGB

如何在 Android 中有效地动态操作 YUV 相机帧?