YUV到RGB565的转换

    前一阵买了一个USB的摄像头接在cubieboard2上打算进行图像采集并存储图片,在解决了驱动以及V4L2摄像头编程等问题之后发现采集到的图像数据是YUYV格式的,因为我有一个现成的写BMP文件(RGB565)的函数,所以就将YUYV转换成RGB565格式写入BMP文件来看看cubieboard2的图像采集效果(其实可以利用libjpeg直接将YUYV转JPEG[5],这样写文件传文件还能快点,不过我确实也应该了解下YUYV)。
 
1.YUYV和RGB的基本概念
1.1 什么是YUV和RGB色彩空间
    在不同的应用领域中为了更好更准确的满足各自的需求,出现了各种各样的色彩空间模型来量化的描述颜色。我们比较常接触到的就包括 RGB / CMYK / YIQ / YUV / HIS等等。
    对于数字电子多媒体领域来说,我们经常接触到的色彩空间的概念,主要是RGB , YUV这两种(实际上,这两种体系包含了许多种具体的颜色表达方式和模型,如sRGB, Adobe RGB, YUV422, YUV420 …)。
    RGB是按三基色加光系统的原理来描述颜色,而YUV则是按照亮度、色差的原理来描述颜色,Y表示亮度,UV并非任何单词的缩写,UV信号实际上就是蓝色差信号和红色差信号,一定程度上间接的代表了蓝色和红色的强度(偏向冷色和暖色的程度)。
    YUV主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽。
1.2 YUV、YIQ和YCbCr区别
    对于YUV模型,很多时候我们是把它和YIQ / YCrCb模型混为一谈的。实际上,YUV模型用于PAL制式的电视系统;YIQ模型与YUV模型类似,用于NTSC制式的电视系统。YIQ颜色空间中的I和Q分量相当于将YUV空间中的UV分量做了一个33度的旋转;这两者常应用于模拟领域。YCbCr颜色空间是由YUV颜色空间派生的一种颜色空间,主要用于数字电视系统中(ITU-R BT.601建议)[1]。
    我们在数字电子多媒体领域所谈到的YUV格式(比如我们现在用的USB摄像头),实际上准确的说,是以YcrCb色彩空间模型为基础的具有多种存储格式的一类颜色模型的家族(包括 YUV444 / YUV422 / YUV420 / YUV420P等等,这些YUV模型区别主要在于UV数据的采样方式和存储方式)。并不是传统意义上用于PAL制模拟电视的YUV模型。
1.3 RGB和YUV数学模型转换
    RGB -> YIQ:
                                                    
    RGB ->YCrCb:   
                                                 
    据此可以计算出(我自己没计算,有空的话用MATLAB对矩阵求逆验证下):
R = Y +1.4075 *(V-128)
G = Y –0.3455 *(U –128) – 0.7169 *(V –128)
B = Y +1.779 *(U – 128)
这里的Y,U,V就是USB摄像头采集到的对应YUV数据,而这YUV实际上指的是YCrCb。
 
2. YUV的存储格式
2.1 采样方式
    YUV码流的存储格式其实与其采样的方式密切相关,主流的采样方式有三种,YUV4:4:4,YUV4:2:2,YUV4:2:0,如何根据其采样格式来从码流中还原每个像素点的YUV值,因为只有正确地还原了每个像素点的YUV值,才能通过YUV与RGB的转换公式提取出每个像素点的RGB值,然后显示出来。用三个图来直观地表示采集的方式,以黑点表示采样该像素点的Y分量,以空心圆圈表示采用该像素点的UV分量。[2]
         

所以, YUV 4:4:4采样,每一个Y对应一组UV分量。 YUV 4:2:2采样,每两个Y共用一组UV分量。  YUV 4:2:0采样,每四个Y共用一组UV分量。  2.2 存储格式 YUV的存储格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开存放YUV三个分量,就像是一个三维平面一样。我们常说得YUV420属于planar格式的YUV(这句没去验证)。 Camera Sensor中,最常用的YUV模型是 YUV422格式,因为它采用4个字节描述两个像素,能和RGB565模型比较好的兼容,有利于Camera Sensor和Camera controller的软硬件接口设计。而YUV422还有细分的格式,比如,YUYV,YYUV,UYVY… 我的摄像头是YUYV格式,后面就单讲YUYV。 我的摄像头采用的是打包的YUYV格式,Y0和Y1共用一对U0和U1,即两个像素用4个字节来存储,数据在unsignedchar型的数组中的存储如下: Addr:   0   1   2   3  |  4   5   6   7        YUV:   Y0  U0  Y1  V0 | Y2  U1  Y3  U1    Pixsel: { 1  } {  2  } | { 3  } {  4  }
3 RGB565的存储格式
    RGB565,两个字节存放5bit红色,6bit 绿色,5bit蓝色信息。我原本比较熟悉的RGB24,R、G、B各用了一个字节,这8bit的颜色信息如何压缩成5、6、5bit而显示出整个范围的颜色(稍有色差),存储格式又是怎样。我没有找专门讲RGB565的文章,下面的这个存储格式是我从网上的一个程序中倒推出来的。该程序段经过验证,可以正确显示图片。程序段如下:
*(RGBdata++) =( ((g & 0x1C) << 3) | ( r >> 3) );
*(RGBdata++) =( (b & 0xF8) | ( g >> 5) );
    RGBdata是存储RGB565的数组,r、g、b分别是存储三种颜色的unsigned char 型的变量,值的取值范围在0-255之间。r和b都经过了右移运算,舍弃了低三位的信息,g也是舍弃了低二位的信息,所以显示出的颜色能大致符合,稍有色差(实际上是对应了调色板的索引值)。最后的存储格式如下:
{``````blue`````}  {```````green`````````}  {```````red```````}
b7  b6  b5 b4  b3  g7  g6  g5  | g4  g3 g2  r7   r6  r5 r4   r3 
A17 A16 A15 A14 A13 A12 A11 A10|A07 A06 A05 A04 A03 A02 A01 A00
[------Addr1------------------][------------Addr0-------------]
 
4. YUV转RGB加快运算速度
    R = Y +1.4075 *(V-128)
    G = Y –0.3455 *(U –128) – 0.7169 *(V –128)
    B = Y +1.779 *(U – 128)
转换公式中有浮点运算,将浮点运算转换成右移运算。
    v=V-128;
    u=U-128;
    y=Y;
    r=y+ v+ (v*103>>8);
    g=y- (u*88>>8) - (v*183>>8);
    b=y+ u + (u*198>>8);
 
5. 补充说明
5.1 YUYV与RGB的其他转换矩阵
    YUYU转RGB除了1.3节中提到的转换矩阵,另外还有以下转换矩阵[6]:
        
        

经过计算可以得到转换关系a: v=V-128; u=U-128; y=Y-16; r = 1.164*y + 1.596*v; g = 1.164*y - 0.380*u- 0.813*v; b = 1.164*y + 2.018*u;   还有另外一个转换关系b,但是我没有去找原始的转换矩阵, v=V-128; u=U-128; y=Y; r = y+1.14*v; g = y-0.394*u-0.581*v; b = y+2.203*u; 以上两种转换关系我都测试过,图片可以正常显示。 5.2 YUYV的planar格式     我最开始参考的程序[3],YUYV是planar格式的,测试的时候发现存储下来的图片如下左图,看起来好像每一小块区域保留了一定的图像,但是每一小块区域都有一部分信息错误,通篇都是如此。想像了一下,这样的现象正好符合packet格式错当成planar格式来处理的结果。据此修改程序后图像显示正常了。             YUV到RGB565的转换_第1张图片          5.3 RGB565的存储格式 我最开始参考的程序[3],rgb565的格式处理是这样: *(RGBdata++) =( ((g & 0x1C) << 3) | ( b >> 3) ); *(RGBdata++) =( (r & 0xF8) | ( g >> 5) ); 也就是从地位到高位排列是b、g、r。但是按照这种方式处理之后,我发现我采集到的图像中,红色和蓝色正好相反了,如下左图,所以怀疑r和b的位置颠倒了。调换位置之后图像显示就正确了。 本来以为是不是作者不小心写错了,不过后来看到很多篇博文rgb的顺序都是如此,差点怀疑是我摄像头的特殊性造成的,可是再一想,不可能的,摄像头有关的只有YUYV格式,而此后的处理(如YUV转RGB,提取出来rgb的颜色分量)已经和摄像头本身的格式无关了,就是说r、g、b或者b、g、r的顺序只和内存中的图片格式有关,我用的是16bit的BMP,理论上顺序是唯一的。于是又查了一下RGB565,发现从低位到高位的确应该是r、g、b[4]。   6. YUYU转RGB565的源程序 我的摄像头是packed(打包)YUYV格式,GRB565的存储中由低到高是RGB。 int convert_yuyv_to_rgb(unsignedchar *inBuf, unsigned char *outBuf,int imgWidth, int imgHeight, int cvtMethod) {        introws,cols;        inty,u,v,r,g,b;        unsignedchar *YUVdata,*RGBdata;        intYpos,Upos,Vpos;//in the inBuf's postion          YUVdata= inBuf;      RGBdata = outBuf;        Ypos=0;        Upos=Ypos+1;        Vpos=Upos+2;          for(rows=0;rows>8);                      g=y- (u*88>>8) - (v*183>>8);                      b=y+ u + (u*198>>8);                                                                r=r>255?255:(r<0?0:r);                      g=g>255?255:(g<0?0:g);                      b=b>255?255:(b<0?0:b);                                              *(RGBdata++)=( ((g & 0x1C) << 3) | ( r >> 3) );                      *(RGBdata++)=( (b & 0xF8) | ( g >> 5) );                                           Ypos+=2;                      if(!(cols& 0x01))//if cols%2!=0                      {                             Upos=Ypos+1;                             Vpos=Upos+2;                      }               }        }        return0; }

 

[0] YUV / RGB 格式及快速转换算法  http://www.cnblogs.com/huaping-audio/archive/2009/12/27/1633624.html
[1] 关于YUV和RGB之间的转换公式  http://blog.sina.com.cn/s/blog_5713096b0100059i.html

[2] 谈谈RGBYUV2YUYVYVYUUYVYAYUV   http://blog.csdn.net/cuiy0001/article/details/8591037
[3] YUV420P和YUV422转RGB565  http://blog.sina.com.cn/s/blog_475e9bf20100siir.html
[4] RGB565格式互转,及彩条程序  http://blog.csdn.net/zhandoushi1982/article/details/5178645
[5]YUYV转JPEG  http://blog.csdn.net/zd394071264/article/details/8288111
[6]http://wenku.baidu.com/link?url=OBu9Ukl682IHSB1efGPNE6TdrEIM3YE3TGT266VJk69s5f8gMzYbE06fkKYDeRum8SDOilKkOergGyslpkh5iSkBicnbTb9oOf7YRTQxcJy

你可能感兴趣的:(YUV到RGB565的转换)