本文档描述了RGB与YUV两个颜色空间的相互转换问题。
很多书在讲YUV颜色空间或YUV模型时,一般直接给出RGB与YUV的相互转换公式,比如这样:
(1)RGB转换成YUV
Y = 0.299R + 0.587G + 0.114B
U = 0.567(B - Y)
V = 0.713(R - Y)
值得注意的是,Y值范围为[0, 1.0]、UV值范围都是[-0.5, 0.5],在Accelerate框架的vImage_CVUtilities.h有描述。
(2)YUV转换成RGB
R = Y + 1.402V
G = Y - 0.344U - 0.714V
B = Y + 1.772U
对于JPEG图片,这两组公式的计算结果往往是正确的。然而,对于视频,这只处理了一种情况,即,这只是BT.601 Full Range转换矩阵。实际上,据我所知,还存在多个转换矩阵,部分转换矩阵可在GPUImage源码中找到应用。值得注意的是,GPUImage使用列矩阵存储。其中,ITU BT.601对应于标准分辨率电视(SDTV)、ITU BT.709对应于高分辨率电视(HDTV),几个常见的颜色转换矩阵分别是:
-
ITU BT.601 Full Range转换矩阵
GLfloat kColorConversion601FullRangeDefault[] = {
1.0, 1.0, 1.0,
0.0, -0.343, 1.765,
1.4, -0.711, 0.0,
};
- ITU BT.601默认转换矩阵
![ITU BT.601默认转换矩阵](http://upload-images.jianshu.io/upload_images/1613657-c90e9ab3f9d8d8d9.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
GLfloat kColorConversion601Default[] = {
1.164, 1.164, 1.164,
0.0, -0.392, 2.017,
1.596, -0.813, 0.0,
};
- ITU BT.709默认转换矩阵
![ITU BT.709默认转换矩阵](http://upload-images.jianshu.io/upload_images/1613657-dad726961c0f76d3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
GLfloat kColorConversion709Default[] = {
1.164, 1.164, 1.164,
0.0, -0.213, 2.112,
1.793, -0.533, 0.0,
};
- ITU BT.709 Full Range转换矩阵
留空
由于OpenGL ES着色器中mat系列数据结构以列优先存储,意味着,**数据上传到着色器端将按列优先规则构造矩阵**,故GPUImage在保存转换矩阵时也以列矩阵表示。因此,在片段着色器中的计算为:
yuv.x = texture2D(luminanceTexture, textureCoordinate).r;
yuv.yz = texture2D(chrominanceTexture, textureCoordinate).rg - vec2(0.5, 0.5);
rgb = colorConversionMatrix * yuv;
以ITU BT.601 Full Range为例,kColorConversion601FullRangeDefault * yuv可得到:
R = Y + 1.4V
G = Y - 0.343U - 0.711V
B = Y + 1.765U
基本等于文档开始提及的转换公式,个别小数部分内容不太一样,怀疑是舍入或大家相互抄袭导致书写错误。
其中,阐明了BT.601与BT.709的区别,这在很多书上是不作说明的,为刚接触视频开发的开发人员提供了参考。
full range我之前了解是[0, 255],video range把人眼察觉不到的范围给去掉了
**参考:**
- 数字图像处理与机器视觉——Visual C++与Matlab实现(第二版)
**推荐阅读:**
- [YCbCr](https://en.wikipedia.org/wiki/YCbCr)
- [R-REC-BT.709](https://www.itu.int/rec/R-REC-BT.709)