YUV420转RGB转换

3
我使用以下公式将RGB矩阵转换为YUV矩阵:

Y  =      (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
Cr = V =  (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128

然后我对矩阵进行了4:2:0色度子采样。我认为我做得正确,我从YUV矩阵中取2x2的子矩阵,将值从小到大排序,并取中间2个值的平均值。

接下来,我使用维基百科上的公式访问了Y、U和V平面:

size.total = size.width * size.height;
y = yuv[position.y * size.width + position.x];
u = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total];
v = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total + (size.total / 4)];

我正在使用OpenCV,所以我尽力最好地解释了这个:

y = src.data[(i*channels)+(j*step)];
u = src.data[(j%4)*step + ((i%2)*channels+1) + max];
v = src.data[(j%4)*step + ((i%2)*channels+2) + max + (max%4)];

src是YUV的子采样矩阵。我解释这个公式的方式正确吗?

以下是我将颜色还原为RGB的方法:

bgr.data[(i*channels)+(j*step)] = (1.164 * (y - 16)) + (2.018 * (u - 128)); // B
bgr.data[(i*channels+1)+(j*step)] = (1.164 * (y - 16)) - (0.813 * (v - 128)) - (0.391 * (u - 128)); // G
bgr.data[(i*channels+2)+(j*step)] = (1.164 * (y - 16)) + (1.596 * (v - 128));   // R

问题是我的图像没有恢复到原来的颜色。
以下是参考用的图片:http://i.stack.imgur.com/vQkpT.jpg(抽样)http://i.stack.imgur.com/Oucc5.jpg(输出)
我看到现在应该从YUV444转换为RGB,但我不太理解我在维基百科上找到的剪辑函数是做什么用的。
C = Y' − 16
D = U − 128
E = V − 128

R = clip(( 298 * C           + 409 * E + 128) >> 8)
G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
B = clip(( 298 * C + 516 * D           + 128) >> 8)

>>符号是否意味着我应该移位?

非常感谢您的帮助和建议!谢谢。

更新

尝试进行YUV444转换,但它只会使我的图像呈现绿色调。

        y = src.data[(i*channels)+(j*step)];
        u = src.data[(j%4)*step + ((i%2)*channels+1) + max];
        v = src.data[(j%4)*step + ((i%2)*channels+2) + max + (max%4)];

        c = y - 16;
        d = u - 128;
        e = v - 128;

        bgr.data[(i*channels+2)+(j*step)] = clip((298*c + 409*e + 128)/256);
        bgr.data[(i*channels+1)+(j*step)] = clip((298*c - 100*d - 208*e + 128)/256);
        bgr.data[(i*channels)+(j*step)] = clip((298*c + 516*d + 128)/256);

以下是我的剪辑函数:

int clip(double value)
{
    return (value > 255) ? 255 : (value < 0) ? 0 : value;
}

该函数的功能是将输入的值限制在0到255之间。


原始图像在这里:http://i.stack.imgur.com/LYW0C.jpg - doc
3个回答

2

当我将WebM帧解码为RGB时,遇到了同样的问题。经过数小时的搜索,我终于找到了解决方案。

从这里获取SCALEYUV函数:http://www.telegraphics.com.au/svn/webpformat/trunk/webpformat.h

然后,要从YUV解码RGB数据,请参阅此文件: http://www.telegraphics.com.au/svn/webpformat/trunk/decode.c

搜索“py = img->planes[0];”,有两种算法可用于转换数据。我只尝试了简单的一种(在“// then fall back to cheaper method.”之后)。

代码中的注释还指向了这个页面:http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC30

对我来说非常有效。


1

由于UV压缩图像,因此您不会完全得到相同的图像。
您没有说明结果是完全错误(即错误)还是不完美。

R = clip(( 298 * C           + 409 * E + 128) >> 8)
G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
B = clip(( 298 * C + 516 * D           + 128) >> 8)

>> 8 是一个位移操作,相当于除以 256。这只是为了让你能够在整数单位上进行所有的算术运算,而不是使用浮点数来提高速度。


1
嗨马丁,谢谢你这么快的回复!我的剪辑函数应该做什么呢? - doc
您需要得到一个在0-255之间的值,所以clip()函数需要检查这个范围。注意不能简单地做(R & 0xff),因为256的值会显示为黑色。 - Martin Beckett
这样的代码应该可以工作,对吧?clip(x) { 如果 x > 255 则 x = 255; 否则如果 (x < 0) 则 x = 0; } - doc
嗯,我的图像现在显示为绿色调。这可能是由于我对子采样或访问YUV值的错误引起的吗? - doc

0

在维基百科上尝试了一些公式,发现了这个混合公式:

byte c = (byte) (y - 16);
byte d = (byte) (u - 128);
byte e = (byte) (v - 128);

byte r = (byte) (c + (1.370705 * (e))); 
byte g = (byte) (c - (0.698001 * (d)) - (0.337633 * (e)));
byte b = (byte) (c + (1.732446 * (d)));

对于我的图像,它能够产生更好的错误提示,只需将一些黑点变成纯绿色(即rgb = 0x00FF00),这对于检测和修正来说更好...

维基来源:https://en.wikipedia.org/wiki/YUV#Y.27UV420p_.28and_Y.27V12_or_YV12.29_to_RGB888_conversion


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接