YUV420转RGB
Posted
技术标签:
【中文标题】YUV420转RGB【英文标题】:YUV420 to RGB conversion 【发布时间】:2011-09-27 12:04:50 【问题描述】:我使用这个公式将一个 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 个值的平均值。
然后我使用来自 Wikipedia 的公式来访问 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,但我不太明白剪辑函数在我在 Wiki 上找到的示例中的作用。
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)
>>是否意味着我应该移位?
如果有任何帮助/cmets,我将不胜感激!谢谢
更新
尝试进行 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);
还有我的剪辑功能: 整数剪辑(双值) 返回(值 > 255)? 255:(值
【问题讨论】:
原图在这里:i.stack.imgur.com/LYW0C.jpg 【参考方案1】:在将 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];”,有两种算法可以转换数据。我只尝试了简单的方法(在“// 然后回退到更便宜的方法”之后)。
代码中的注释也参考这个页面:http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC30
非常适合我。
【讨论】:
【参考方案2】:由于 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。这只是为了让您以整数单位而不是浮点数进行所有算术运算
【讨论】:
嗨,马丁,感谢您这么快的回复!我的剪辑功能到底应该做什么? 您需要以 0-255 之间的值结束,因此 clip() 需要检查此范围。请注意,您不能只做 (R & 0xff),因为 256 的值将显示为黑色 这样的东西会起作用,对吧?剪辑(x) 如果 x > 255 x = 255;否则,如果(x 嗯,我的图像现在显示为绿色。这可能是由于我的子采样错误或我如何访问 YUV 值造成的吗?【参考方案3】:正在试验 wiki 上的公式,发现混合公式:
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
【讨论】:
以上是关于YUV420转RGB的主要内容,如果未能解决你的问题,请参考以下文章
YV12和I420的区别 yuv420和yuv420p的区别(转)
2023-02-24:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,采用YUV420P转YUV420SP的方式。