小议YUV色彩空间
摘要:
在视频图像处理等相关相关领域,YUV是一个经常出现的格式。本文主要以图解的资料形式详细描述YUV和RGB格式的来由,相互关系以及转换方式,并对编程实现的YUV转为RGB程序进行介绍。
1 引言
自然界的颜色千变万化,为了给颜色一个量化的衡量标准,就需要建立色彩空间模型来描述各种各样的颜色,由于人对色彩的感知是一个复杂的生理和心理联合作用的过程,所以在不同的应用领域中为了更好更准确的满足各自的需求,就出现了各种各样的色彩空间模型来量化的描述颜色。我们比较常接触到的就包括 RGB / CMYK / YCbCr/ YUV / HSI等等。
即使只是RGB、 YUV这两大类色彩空间,所涉及到的知识也是十分丰富复杂的,自知具备的相关专业知识有限,所以本文主要针对自己所了解的相关知识以及项目开发中遇到的相关问题对YUV色彩空间相关进行讨论。
2 理论分析
2.1 RGB、YUV色彩空间模型介绍
RGB与YUV有着千丝万缕的联系与区别,其中RGB是按三基色加光系统的原理来描述颜色,而YUV则是按照亮度、色差的原理来描述颜色。
2.1.1 RGB 颜色空间
RGB 颜色空间是我们最常见的颜色空间,是一种简单鲁棒性较好的定义颜色的空间。RGB 颜色空间由红、绿、蓝三个基本颜色通道组成,由这些颜色通道组合代表一种颜色。RGB 颜色模型可以通过一个立方体颜色模型,如图 1 表示,其三个轴分别代表红、绿、蓝 3 个颜色分量。对于一张 24 位真彩色的图片,R、G、B 三个通道各自具有 8 位宽,像素的取值范围为0-255,红色为(255,0,0),绿色为(0,255,0),蓝色为(0,0,255)。
图 1 RGB颜色模型
2.1.2 YUV颜色空间
在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD(点耦合器件)摄像机,它把摄得的彩色图像信号,经分色、分别放大校正得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y、B-Y,最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这就是我们常用的YUV色彩空间。
2.1.2.1 RGB 颜色空间过渡到YUV色彩空间
对于视频捕获和编解码等应用来讲,RGB这样的表示方式数据量太大了。需要想办法在不太影响感觉的情况下,对原始数据的表示方法进行更改,减少数据量。
在RGB色彩空间中,三个颜色的重要程度相同,所以需要使用相同的分辨率进行存储, 3个颜色通道需要按照相同的分辨率进行存储,数据量还是很大的。所以,利用人眼睛对亮度比对颜色更加敏感,将图像的亮度信息和颜色信息分离,并使用不同的分辨率进行存储,这样可以在对主观感觉影响很小的前提下,更加有效的存储图像数据。
YCbCr色彩空间和它的变形(也就是YUV)是最常用的有效的表示彩色图像的方法。Y是图像的亮度(luminance/luma)分量,使用以下公式计算,为R,G,B分量的加权平均值:
Y = kr R + kgG + kbB,其中k是权重因数。
上面的公式计算出了亮度信息,还有颜色信息,使用色差(color difference/chrominance或chroma)来表示,其中每个色差分量为R,G,B值和亮度Y的差值:
Cb = B -Y Cr = R -Y Cg = G- Y
其中,Cb+Cr+Cg是一个常数(其实是一个关于Y的表达式),所以,只需要其中两个数值结合Y值就能够计算出原来的RGB值。所以,我们仅保存亮度和蓝色、红色的色差值,这就是(Y,Cb,Cr)。
相比RGB色彩空间,YCbCr色彩空间有一个显著的优点。Y的存储可以采用和原来画面一样的分辨率,但是Cb,Cr的存储可以使用更低的分辨率。这样可以占用更少的数据量,并且在图像质量上没有明显的下降。所以,将色彩信息以低于量度信息的分辨率来保存是一个简单有效的图像压缩方法。
注释:YCbCr进行不同的取样就是所谓的YUV了。
2.1.2.2 YUV与RGB相互转换
YUV 空间和RGB空间存在如下转换关系:
注释:
1、从公式中,我们关键要理解的一点是,UV / CbCr信号实际上就是蓝色差信号和红色差信号,进而言之,实际上一定程度上间接的代表了蓝色和红色的强度,理解这一点对于我们理解各种颜色变换处理的过程会有很大的帮助。
2、我们在数字电子多媒体领域所谈到的YUV格式,实际上准确的说,是以YcrCb色彩空间模型为基础的具有多种存储格式的一类颜色模型的家族(包括YUV444 / YUV422 / YUV420 / YUV420P等等)。并不是传统意义上用于PAL制模拟电视的YUV模型。这些YUV模型的区别主要在于UV数据的采样方式和存储方式
2.2 RGB、YUV色彩空间模型内存分布
在RGB24格式中,对于宽度为w,高度为h的画面,需要wh3个字节来存储其每个像素的rgb信息,画面的像素数据是连续排列的。按照r(0,0),g(0,0),b(0,0);r(0,1),g(0,1),b(0,1);…;r(w-1,0),g(w-1,0),b(w-1,0);…;r(w-1,h-1),g(w-1,h-1),b(w-1,h-1)这样的顺序存放起来。
在YUV格式中,以YUV420格式为例。宽度为w高度为h的画面,其亮度Y数据需要wh个字节来表示(每个像素点一个亮度)。而Cb和Cr数据则是画面中4个像素共享一个Cb,Cr值。这样Cb用wh/4个字节,Cr用wh/4个字节。
YUV文件中,把多个帧的画面连续存放。就是YUV YUV YUV……这样的不断连续的形式,而其中每个YUV,就是一幅画面。
在这单个YUV中,前wh个字节是Y数据,接着的wh/4个字节是Cb数据,再接着的wh/4个字节为Cr数据。
2.3 RGB、YUV色彩空间模型数据表达方式
以320240的一帧图像为例RGB24的排列方式如下图所示:
每个像素点有三个字节组成分别表示R,G,B分量上的颜色值。在数据中的表示方式为一个像素 一个像素表示。字节流可以表述如下:
BGRBGRBGRBGRBGR……
|---------------3202403-------|
每一个字母表示一个字节,也就是该颜色分量的数值,相邻的三个BGR字节表示一个像素点。在我们做计算时,通常一次取三个字节,也就是一个像素点。
相应的YV12的排列方式如下图所示:
每个像素点都有一个Y分量,每隔一列就有一个U或者V分量,U和V交替出现。YV12的字节流表示方式和RGB24有很大区别,YV12并不是按照像素依次排列的,而是先放置Y空间,然后放置整个V空间,最后放置U空间,那么字节流如下所示:
YYYYYYY……VVVV……UUUU……
|-----320240----|-320240/4-|-320240/4-|
在320240个字节的Y后,紧跟着320240/4个V和320240/4个U。
YV12和RGB24同样都有320240个像素点,但是在数据结构和字节流上有着很大区别。单纯从数据大小来看,RGB24的数据大小为3202403Bytes,而YV12为3202401.5Bytes,可见YV12的数据量为RGB24的一半。
2.4 YCbCr色彩空间模型取样格式
对YCbCr色彩空间,进行不同格式的取样就得到不同的YUV格式了,如下图3所示。
2.5 RGB、YUV色彩空间模型转换示例
核心编程示例
//RGB转YUV
bool RGB2YUV(byte* RgbBuf,int nWidth,int nHeight,byte* yuvBuf,unsigned long len)
{
int i, j;
bytebufY, *bufU, *bufV, *bufRGB,bufYuv;
memset(yuvBuf,0,(unsigned int )len);//len表示yuvBuf长度(WH3/2)
bufY = yuvBuf;//Y首址
bufV = yuvBuf + nWidth * nHeight;//V首址
bufU = bufV + (nWidth * nHeight 1/4);//U首址
*len = 0;
byte y, u, v, r, g, b,testu,testv;
unsigned int ylen = nWidth * nHeight; //Y长度
unsigned int ulen = (nWidth * nHeight)/4;//U长度
unsigned int vlen = (nWidth * nHeight)/4; //V长度
for (j = 0; j < nHeight;j++)
{
bufRGB = RgbBuf + nWidth * (nHeight - 1 - j) * 3 ;
for (i = 0;i < nWidth;i++)
{
int pos = nWidth * i + j;
r = *(bufRGB++);
g = *(bufRGB++);
b = *(bufRGB++);
y = (byte)( ( 66 * r + 129 * g + 25 * b + 128) >> 8) + 16 ;
u = (byte)( ( -38 * r - 74 * g + 112 * b + 128) >> 8) + 128 ;
v = (byte)( ( 112 * r - 94 * g - 18 * b + 128) >> 8) + 128 ;
*(bufY++) = max( 0, min(y, 255 ));
if (j%2==0&&i%2 ==0)
{ //存u分量
if (u>255){u=255;}
if (u<0){u = 0;}
*(bufU++) =u;
}
else
{
//存v分量
if (i%2==0)
{ if (v>255){v = 255;}
if (v<0){v = 0;}
*(bufV++) =v;
}
}
}
}
*len = nWidth * nHeight+(nWidth * nHeight)/2;
return true;
}
//YUV4转RGB
static void YUV420p_to_RGB24(unsigned char *yuv420[3], unsigned char *rgb24, int width, int height)
{
int R,G,B,Y,U,V,x,y;
int nWidth = width>>1; //色度信号宽度
for (y=0;y<height;y++)
{
for (x=0;x<width;x++)
{
Y = (yuv420[0] + ywidth + x);
U = (yuv420[1] + ((y>>1)nWidth) + (x>>1));
V = (yuv420[2] + ((y>>1)nWidth) + (x>>1));
R = Y + 1.402(V-128);
G = Y - 0.34414(U-128) - 0.71414(V-128);
B = Y + 1.772(U-128);
//防止越界
if (R>255)R=255;if (R<0)R=0;
if (G>255)G=255;if (G<0)G=0;
if (B>255)B=255;if (B<0)B=0;
*(rgb24 + ((height-y-1)*width + x)*3) = B;
*(rgb24 + ((height-y-1)*width + x)*3 + 1) = G;
*(rgb24 + ((height-y-1)*width + x)*3 + 2) = R;
}
}
}
2.4 RGB、YUV色彩空间模型转换示例实验结果
为了验证转换的效果,从RGB色彩空间转换到YUV420色彩空间再转换到RGB色彩空间,结果如下图4所示。
图4 RGB与YUV转换结果图
从上图看出,转换的效果还是可以的,部分地方出现色彩失真,算法还需优化。
3 结语
在视频监控领域,YUV是一个经常出现的格式。本文主要以图解的资料形式详细描述YUV和RGB格式的来由,相互关系以及转换方式,并对编程实现的YUV转为RGB程序进行介绍。