在 Keith Jack’s 的书 “Video Demystified” (ISBN 1-878707-09-4) 给出的公式是这样的。
RGB to YUV
𝑌=0.257𝑅+0.504𝐺+0.098𝐵+16
𝐶𝑟=𝑉=0.439𝑅−0.368𝐺−0.071𝐵+128
𝐶𝑏=𝑈=−0.148𝑅−0.291𝐺+0.439𝐵+128
YUV to RGB
𝐵=1.164(𝑌−16)+2.018(𝑈−128)
𝐺=1.164(𝑌−16)−0.813(𝑉−128)−0.391(𝑈−128)
𝑅=1.164(𝑌−16)+1.596(𝑉−128)
注意在上面的式子中,RGB 的范围是 [0,255],Y 的范围是 [16,235] ,UV 的范围是 [16,239]。 如果计算结果超出这个范围就截断处理。
CCIR 601 定义的转换公式是:
𝑌=0.299𝑅+0.587𝐺+0.114𝐵
𝐶𝑟=𝑉=0.713(𝑅−𝑌)=0.500𝑅−0.419𝐺−0.081𝐵
𝐶𝑏=𝑈=0.564(𝐵−𝑌)=−0.169𝑅−0.331𝐺+0.500𝐵
RGB===Y+1.403VY−0.344U−0.714VY+1.770U
𝑅=𝑌+1.403𝑉
𝐺=𝑌−0.344𝑈−0.714𝑉
𝐵=𝑌+1.770𝑈
这里 RGB 的取值范围是 [0,1]。 Y 的范围是 [0,1], Cr 和 Cb 的范围是 [−0.5,0.5]。
大家仔细看,这两个来源给出的公式系数有些细微的差别,如果将公式中的 YUV 和 RGB 的取值范围统一成相同的,计算出的结果也略有不同,但是差异很小,基本上眼睛看不出区别来。所以大家不用计较这两个公式的区别。
如果把 RGB 和YUV 的范围都放缩到 0,255,那么常用的转换公式是这样的。所以我们可以直接使用下面的公式来转换.
𝑅=𝑌+1.403×(𝑉−128)
𝐺=𝑌–0.343×(𝑈–128)–0.714×(𝑉–128)
𝐵=𝑌+1.770×(𝑈–128)
𝑌=0.299𝑅+0.587𝐺+0.114𝐵
𝐶𝑟=𝑉=0.500𝑅−0.419𝐺−0.081𝐵+128
𝐶𝑏=𝑈=−0.169𝑅−0.331𝐺+0.500𝐵+128
C++转换代码如下:
class RGB
{
public:
uint8_t R, G, B;
};
class YUV
{
public:
uint8_t Y, U, V;
};
RGB yuv2rgb(YUV yuv)
{
int R = round(yuv.Y + 1.403 * (yuv.V - 128));
int G = round(yuv.Y - 0.343 * (yuv.U - 128) - 0.714 * (yuv.V - 128));
int B = round(yuv.Y + 1.770 * (yuv.U - 128));
RGB rgb;
rgb.R = max(0, min(R, 255));
rgb.G = max(0, min(G, 255));
rgb.B = max(0, min(B, 255));
return rgb;
}
YUV rgb2yuv(RGB rgb)
{
int Y = round(0.299 * rgb.R + 0.587 * rgb.G + 0.114 * rgb.B);
int V = round(0.500 * rgb.R - 0.419 * rgb.G - 0.081 * rgb.B + 128);
int U = round(-0.169 * rgb.R - 0.331 * rgb.G + 0.500 * rgb.B + 128);
YUV yuv;
yuv.Y = max(0, min(Y, 255));
yuv.U = max(0, min(U, 255));
yuv.V = max(0, min(V, 255));
return yuv;
}
常见颜色RGB与YUV对应值:
黑色 rgb=[00,00,00],yuv=[00,80,80]
白色 rgb=[ff,ff,ff],yuv=[ff,80,80]
红色 rgb=[ff,00,00],yuv=[4c,55,ff]
青色 rgb=[00,ff,ff],yuv=[b3,ab,01]
蓝色 rgb=[00,00,ff],yuv=[1d,ff,6b]
黄色 rgb=[ff,ff,00],yuv=[e2,01,95]