1.YUV和RGB格式
在显示器发明之后,从黑白显示器发展到彩色显示器,人们开始使用发出不同颜色的光的荧光粉(CRT,等离子体显示器),或者不同颜色的滤色片(LCD),或者不同颜色的半导体发光器件(OLED和LED大型全彩显示牌)来形成色彩,无一例外的选择了Red,Green,Blue这3种颜色的发光体作为基本的发光单元。通过控制他们发光强度,组合出了人眼睛能够感受到的大多数的自然色彩。 不过这里面的YUV TO RGB的算法,效率实在是低,因为里面有了浮点运算,解一帧176*144的图像大概需要400ms左右,这是无法忍受的,如果消除浮点运算,只需要10ms左右,效率的提升真是无法想象.所以大家还是避免在手机上面进行浮点运算.
计算机显示彩色图像的时候也不例外,最终显示的时候,要控制一个像素中Red,Green,Blue的值,来确定这个像素的颜色。计算机中无法模拟连续的存储从最暗到最亮的量值,而只能以数字的方式表示。
于是,结合人眼睛的敏感程度,使用3个字节(3*8位)来分别表示一个像素里面的Red,Green和Blue的发光强度数值,这就是常见的RGB格式。我们可以打开画图板,在自定义颜色工具框中,输入r,g,b值,得到不同的颜色。
RGB简介:
是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色。
RGB组成:
在RGB色彩模型中,图像每一个像素点RGB分量(R分量,G分量,B分量)有0~255种强度值。
RGB24
RGB24使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。注意在内存中RGB各分量的排列顺序为:BGR BGR BGR…。通常可以使用RGBTRIPLE数据结构来操作一个像素,它的定义为:
typedef struct tagRGBTRIPLE {
BYTE rgbtBlue; // 蓝色分量
BYTE rgbtGreen; // 绿色分量
BYTE rgbtRed; // 红色分量
} RGBTRIPLE;
但是对于视频捕获和编解码等应用来讲,这样的表示方式数据量太大了。需要想办法在不太影响感觉的情况下,对原始数据的表示方法进行更改,减少数据量。
无论中间处理过程怎样,最终都是为了展示给人观看,这样的更改,也是从人眼睛的特性出发,和发明RGB三原色表示方法的出发点是一样的。
于是我们使用Y,Cb,Cr模型来表示颜色。Iain的书中写道:The human visual system (HVS) is less sensitive to colour than to luminance (brightness).人类视觉系统(其实就是人的眼睛)对亮度的感觉比对颜色更加敏感。
在RGB色彩空间中,三个颜色的重要程度相同,所以需要使用相同的分辨率进行存储,最多使用RGB565这样的形式减少量化的精度,但是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的存储可以使用更低的分辨率。这样可以占用更少的数据量,并且在图像质量上没有明显的下降。所以,将色彩信息以低于量度信息的分辨率来保存是一个简单有效的图像压缩方法。
在COLOUR SPACES .17 ITU-R recommendation BT.601 中,建议在计算Y时,权重选择为kr=0.299,kg=0.587,kb=0.114。
于是常用的转换公式如下:
YUV与RGB相互转换的公式如下(RGB取值范围均为0-255): Y = 0.299R 0.587G 0.114B U = -0.147R - 0.289G 0.436B V = 0.615R - 0.515G - 0.100B R = Y 1.14V G = Y - 0.39U - 0.58V B = Y 2.03U
有了这个公式,我们就能够将一幅RGB画面转换成为YUV画面了,反过来也可以。下面将j介绍画面数据究竟是以什么形式存储起来的。
在RGB24格式中,对于宽度为w,高度为h的画面,需要w*h*3个字节来存储其每个像素的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数据需要w*h个字节来表示(每个像素点一个亮度)。而Cb和Cr数据则是画面中4个像素共享一个Cb,Cr值。这样Cb用w*h/4个字节,Cr用w*h/4个字节。
YUV文件中,把多个帧的画面连续存放。就是YUV YUV YUV…..这样的不断连续的形式,而其中每个YUV,就是一幅画面。在这单个YUV中,前w*h个字节是Y数据,接着的w*h/4个字节是Cb数据,再接着的w*h/4个字节为Cr数据。
在由这样降低了分辨率的数据还原出RGB数据的时候,就要依据像素的位置找到它对应的Y,Cb,Cr值,其中Y值最好找到,像素位置为x,y的话,Y数据中第y*width x个数值就是它的Y值。Cb和Cr由于是每2x2像素的画面块拥有一个,这样Cb和Cr数据相当于两个分辨率为w/2 * h/2的画面,那么原来画面中的位置为x,y的像素,在这样的低分辨率画面中的位置是x/2,y/2,属于它的Cb,Cr值就在这个地方:(y/2)*(width/2) (x/2)。
以320*240分辨率图像为例 RGB24的排列方式: BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR…… ¦---------------320*240*3------- ¦
YUV420的排列方式 YYYYYYYYYYYYY………UUUUU ………VVVVVVV…… ¦----320*240--- ¦-320*240/4- ¦-320*240/4- ¦
YUV420平面存储形式
我们常说得YUV420属于planar格式的YUV,使用三个数组分开存放YUV三个分量,就像是一个三维平面一样。
在常见H264测试的YUV序列中,例如CIF图像大小的YUV序列(352*288),在文件开始并没有文件头,直接就是YUV数据,先存第一帧的Y信息,长度为352*288个byte, 然后是第一帧U信息长度是352*288/4个byte, 最后是第一帧的V信息,长度是352*288/4个byte,
因此可以算出第一帧数据总长度是352*288*1.5,即152064个byte, 如果这个序列是300帧的话, 那么序列总长度即为152064*300=44550KB, 这也就是为什么常见的300帧CIF序列总是44M的原因.