YUV转RGB
- 格式:doc
- 大小:38.00 KB
- 文档页数:4
YUV422_to_RGB24转换算法最近做摄像头的测试,读取出来的数据为YUV422(YUYV)格式,若要在LCD上面显示,需要先做格式转换,但在网上搜了一遍,只有YUV420转RGB的算法,无奈自己做了一个函数,实现到RGB24的格式转换,转成RGB24(即RGB888)之后,就可以根据自己的LCD格式再做其他转换,例如我的LCD显示格式为RGB565,可以再做一个RGB24到RGB565的转换即可,类似转换比较简单,相关例程网上也比较多,就不多做描述了,下面给出YUV422到RGB24的转换函数:typedef unsigned char uint8_t;static void yuv422_to_rgb24(unsigned char *yuv422,unsigned char *rgb24, int width, int height){int x,y;uint8_t *yuv444;yuv444 = (uint8_t *) malloc(sizeof(uint8_t) * WIDTH * HEIGHT * 3);for(x = 0,y = 0;x < width*height*2,y < width*height*3;x+=4,y+=6){yuv444[y] = yuv422[x];yuv444[y+1] = yuv422[x+1];yuv444[y+2] = yuv422[x+3];yuv444[y+3] = yuv422[x+2];yuv444[y+4] = yuv422[x+1];yuv444[y+5] = yuv422[x+3];}for(x = 0;x < width*height*3;x+=3){rgb24[x+2] = yuv444[x] + 1.402*(yuv444[x+2] - 128);rgb24[x+1] = yuv444[x]-0.34414*(yuv444[x+1]-128)-0.71414*(yuv444[x+2]-128);rgb24[x] = yuv444[x] + 1.772*(yuv444[x+1] - 128);if (rgb24[x]>255)rgb24[x]=255;if (rgb24[x]<0)rgb24[x]=0;if (rgb24[x+1]>255)rgb24[x+1]=255;if (rgb24[x+1]<0)rgb24[x+1]=0;if (rgb24[x+2]>255)rgb24[x+2]=255;if (rgb24[x+2]<0)rgb24[x+2]=0;}free(yuv444);}该函数的转换思想是先进行YUV422到YUV444的转化,再进行YUV444到RGB24的转化,利用一个YUV422像素点得到两个YUV444像素点,其中YUV444[0]由Y[0]、U[0]、V[0]得到,YUV444[1]由Y[1] 、U[0]、V[0]得到,可见UV分量被重复利用。
关于YUV和RGB之间的转换公式总结了一下网上关于YUV的一些东西先区分一下YUV和YCbCrYUV色彩模型来源于RGB模型,该模型的特点是将亮度和色度分离开,从而适合于图像处理领域。
应用:模拟领域Y'= 0.299*R' + 0.587*G' + 0.114*B'U'= -0.147*R' - 0.289*G' + 0.436*B' = 0.492*(B'- Y')V'= 0.615*R' - 0.515*G' - 0.100*B' = 0.877*(R'- Y')R' = Y' + 1.140*V'G' = Y' - 0.394*U' - 0.581*V'B' = Y' + 2.032*U'YCbCr模型来源于YUV模型。
YCbCr是YUV 颜色空间的偏移版本.应用:数字视频,ITU-R BT.601建议Y’ = 0.257*R' + 0.504*G' + 0.098*B' + 16Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128R' = 1.164*(Y’-16) + 1.596*(Cr'-128)G' = 1.164*(Y’-16) - 0.813*(Cr'-128) - 0.392*(Cb'-128)B' = 1.164*(Y’-16) + 2.017*(Cb'-128)PS: 上面各个符号都带了一撇,表示该符号在原值基础上进行了伽马校正,伽马校正有助于弥补在抗锯齿的过程中,线性分配伽马值所带来的细节损失,使图像细节更加丰富。
opencv yuv 公式在计算机视觉领域,OpenCV是一个广泛使用的开源计算机视觉库,提供了丰富的图像处理和计算机视觉算法。
其中,YUV色彩空间是一种常用的色彩编码方式,它将颜色信息和亮度信息分离,广泛应用于数字视频传输和图像处理领域。
本文将介绍OpenCV中YUV色彩空间的相关公式和用法。
一、YUV色彩空间简介YUV色彩空间由亮度(Y)和色度(UV)两个分量组成,亮度分量表示像素的明暗程度,而色度分量则表示像素的颜色信息。
这种分离的方式在图像和视频压缩中非常有用,可以降低数据量并提高压缩效率。
在YUV色彩空间中,亮度(Y)分量占据整个色彩空间的明度信息。
色度(UV)分量则描述了颜色信息,其中U表示与蓝色的差异,V表示与红色的差异。
由于人眼对亮度更加敏感,而对颜色信息的敏感度较低,因此YUV色彩空间能够满足人眼对图像感知的需求。
二、YUV与RGB的转换公式在OpenCV中,我们可以使用以下公式将YUV和RGB色彩空间相互转换:RGB to YUV:Y = 0.299 * R + 0.587 * G + 0.114 * BU = 0.492 * (B - Y)V = 0.877 * (R - Y)YUV to RGB:R = Y + 1.13983 * VB = Y + 2.032 * UG = Y - 0.39465 * U - 0.5806 * V其中,R、G、B分别表示RGB色彩空间中的红、绿、蓝分量,而Y、U、V则表示YUV色彩空间中的亮度和色度分量。
三、OpenCV中的YUV图像处理在OpenCV中,我们可以通过以下代码来实现YUV图像的处理:```cpp// 加载YUV图像cv::Mat yuvImage = cv::imread("image.yuv",cv::IMREAD_GRAYSCALE);// YUV to RGB转换cv::Mat bgrImage;cv::cvtColor(yuvImage, bgrImage, cv::COLOR_YUV2BGR);// 进行图像处理// ...// RGB to YUV转换cv::Mat processedYUVImage;cv::cvtColor(bgrImage, processedYUVImage, cv::COLOR_BGR2YUV);// 保存处理后的YUV图像cv::imwrite("processed_image.yuv", processedYUVImage);```通过这段代码,我们可以加载YUV图像并将其转换为RGB色彩空间,然后进行图像处理,最后再将结果转换回YUV色彩空间并保存。
【总结】关于YUV-RGB格式转换的⼀些个⼈理解 这段时间⼀直在研究YUV的格式问题例如YUV422、YUV420,在⽹上搜索了很多这⽅⾯的资料,发现很多资料讲的东西是重复的,没有⽐较深⼊的讲解,所以看了之后印象不是很深,过了⼀段时间之后⼜对它们有了困惑。
所以就有了⼀个想法,打算⾃⼰写⼀个c语⾔⼩程序,通过对BMP⽂件的RGB数据读取,然后将得到的RGB数据转换成为YUV格式的⽂件,然后⽤YUV的播放器打开,查看是否解析正确。
(在这⾥,BMP⽂件我选择了24bpp的格式,为了⽅便。
)通过这样的⽅式,正向和逆向学习来加深YUV⽂件的认识。
经过了2天的努⼒,从想法到实践,终于完成了YUV422和YUV420的⽣成,基本上对YUV的⼏种常见格式有了⼀些深⼊的看法,由于本⼈的⽔平有限,如果理解有出⼊,还请各位⽹友能够指出。
⼀、基本思路先附上主要程序的流程图:在正式讲解代码前,我们先来了解YUV的分类:packed: 打包模式,即Y、U、V数据是连续排布的planar: 平⾯模式,即Y、U、V是各⾃分开存放的semi-planar: 半平⾯模式,即Y单独存放, UV⼀起存放上⾯的3种是主要内存排布的分类,⾄于详细的排布如下(主要是YUV422、YUV420):(我们使⽤⼀张分辨率为 height*width的图⽚为例⼦)YUV422 planar:整个YUV⽂件中,Y、U、V是⼀个⼤数组,⽽其中我们可以看成是三个⼩数组,分别是Y数组(长度为Height*Width)、U数组(长度为Height*Width/2)、V数组(长度为Height*Width/2)。
YUV422 Semi planar:YUV420 planar :整个YUV⽂件中,Y、U、V是⼀个⼤数组,⽽其中我们可以看成是三个⼩数组,分别是Y数组(长度为Height*Width)、U数组(长度为Height*Width/4)、V数组(长度为Height*Width/4)。
1 前言自然界的颜色千变万化,为了给颜色一个量化的衡量标准,就需要建立色彩空间模型来描述各种各样的颜色,由于人对色彩的感知是一个复杂的生理和心理联合作用的过程,所以在不同的应用领域中为了更好更准确的满足各自的需求,就出现了各种各样的色彩空间模型来量化的描述颜色。
我们比较常接触到的就包括RGB / CMYK / YIQ / YUV / HSI等等。
对于数字电子多媒体领域来说,我们经常接触到的色彩空间的概念,主要是RGB , YUV 这两种(实际上,这两种体系包含了许多种具体的颜色表达方式和模型,如sRGB, Adobe RGB, YUV422, YUV420 …), RGB是按三基色加光系统的原理来描述颜色,而YUV则是按照亮度,色差的原理来描述颜色。
即使只是RGB YUV这两大类色彩空间,所涉及到的知识也是十分丰富复杂的,自知不具备足够的相关专业知识,所以本文主要针对工程领域的应用及算法进行讨论。
2 YUV相关色彩空间模型对于YUV模型,实际上很多时候,我们是把它和YIQ / YCrCb模型混为一谈的。
实际上,YUV模型用于PAL制式的电视系统,Y表示亮度,UV并非任何单词的缩写。
YIQ模型与YUV模型类似,用于NTSC制式的电视系统。
YIQ颜色空间中的I和Q分量相当于将YUV空间中的UV分量做了一个33度的旋转。
YCbCr颜色空间是由YUV颜色空间派生的一种颜色空间,主要用于数字电视系统中。
从RGB到YCbCr的转换中,输入、输出都是8位二进制格式。
三者与RGB的转换方程如下:RGB -> YUV:实际上也就是:Y=0.30R+0.59G+0.11B ,U=0.493(B-Y) ,V=0.877(R-Y)RGB -> YIQ:RGB -> YCrCb:从公式中,我们关键要理解的一点是,UV / CbCr信号实际上就是蓝色差信号和红色差信号,进而言之,实际上一定程度上间接的代表了蓝色和红色的强度,理解这一点对于我们理解各种颜色变换处理的过程会有很大的帮助。
1.//rgb转yuv4202.//////////////////////////////////////////////////////////////////////////3.bool RGB2YUV(LPBYTE RgbBuf,UINT nWidth,UINT nHeight,LPBYTE yuvBuf,unsigned long*len)4.{5.int i,j;6.unsigned char*bufY,*bufU,*bufV,*bufRGB,*bufYuv;7.memset(yuvBuf,0,(unsigned int)*len);8.bufY=yuvBuf;9.bufV=yuvBuf+nWidth*nHeight;10.bufU=bufV+(nWidth*nHeight*1/4);11.*len=0;12.unsigned char y,u,v,r,g,b,testu,testv;13.unsigned int ylen=nWidth*nHeight;14.unsigned int ulen=(nWidth*nHeight)/4;15.unsigned int vlen=(nWidth*nHeight)/4;16.for(j=0;j<nHeight;j++)17.{18.bufRGB=RgbBuf+nWidth*(nHeight-1-j)*3;19.for(i=0;i<nWidth;i++)20.{21.int pos=nWidth*i+j;22.r=*(bufRGB++);23.g=*(bufRGB++);24.b=*(bufRGB++);25.y=(unsigned char)((66*r+129*g+25*b+128)>>8)+16;26.u=(unsigned char)((-38*r-74*g+112*b+128)>>8)+128;27.v=(unsigned char)((112*r-94*g-18*b+128)>>8)+128;28.*(bufY++)=max(0,min(y,255));29.if(j%2==0&&i%2==0)30.{31.if(u>255)32.{33.u=255;34.}35.if(u<0)36.{37.u=0;38.}39.*(bufU++)=u;40.//存u分量41.}42.else43.{44.//存v分量45.if(i%2==0)46.{47.if(v>255)48.{49.v=255;50.}51.if(v<0)52.{53.v=0;54.}55.*(bufV++)=v;56.}57.}58.}59.}60.*len=nWidth*nHeight+(nWidth*nHeight)/2;61.return true;62.}63.//////////////////////////////////////////////////////////////////////////64.//yuv420转rgb65.//////////////////////////////////////////////////////////////////////////66.bool YUV2RGB(LPBYTE yuvBuf,UINT nWidth,UINT nHeight,LPBYTE pRgbBuf,unsigned long*len)67.{68.#define PIXELSIZE nWidth*nHeight69.const int Table_fv1[256]={-180,-179,-177,-176,-174,-173,-172,-170,-169,-167,-166,-165,-163,-162,-160,-159,-158,-156,-155,-153,-152,-151,-149,-148,-146,-145,-144,-142,-141,-139,-138,-137,-135,-134,-132,-131,-130,-128,-127,-125,-124,-123,-121,-120,-118,-117,-115,-114,-113,-111,-110,-108,-107,-106,-104,-103,-101,-100,-99,-97,-96,-94,-93,-92,-90,-89,-87,-86,-85,-83,-82,-80,-79,-78,-76,-75,-73,-72,-71,-69,-68,-66,-65,-64,-62,-61,-59,-58,-57,-55,-54,-52,-51,-50,-48,-47,-45,-44,-43,-41,-40,-38,-37,-36,-34,-33,-31,-30,-29,-27,-26,-24,-23,-22,-20,-19,-17,-16,-15,-13,-12,-10,-9,-8,-6,-5,-3,-2,0,1,2,4,5,7,8,9,11,12,14,15,16,18,19,21,22,23,25,26,28,29,30,32,33,35, 36,37,39,40,42,43,44,46,47,49,50,51,53,54,56,57,58,60,61,63,64,65,67,68, 70,71,72,74,75,77,78,79,81,82,84,85,86,88,89,91,92,93,95,96,98,99,100,10 2,103,105,106,107,109,110,112,113,114,116,117,119,120,122,123,124,126,12 7,129,130,131,133,134,136,137,138,140,141,143,144,145,147,148,150,151,15 2,154,155,157,158,159,161,162,164,165,166,168,169,171,172,173,175,176,17 8};70.const int Table_fv2[256]={-92,-91,-91,-90,-89,-88,-88,-87,-86,-86,-85,-84,-83,-83,-82,-81,-81,-80,-79,-78,-78,-77,-76,-76,-75,-74,-73,-73,-72,-71,-71,-70,-69,-68,-68,-67,-66,-66,-65,-64,-63,-63,-62,-61,-61,-60,-59,-58,-58,-57,-56,-56,-55,-54,-53,-53,-52,-51,-51,-50,-49,-48,-48,-47,-46,-46,-45,-44,-43,-43,-42,-41,-41,-40,-39,-38,-38,-37,-36,-36,-35,-34,-33,-33,-32,-31,-31,-30,-29,-28,-28,-27,-26,-26,-25,-24,-23,-23,-22,-21,-21,-20,-19,-18,-18,-17,-16,-16,-15,-14,-13,-13,-12,-11,-11,-10,-9,-8,-8,-7,-6,-6,-5,-4,-3,-3,-2,-1,0,0,1,2,2,3,4,5,5,6,7,7,8,9,10,10,11,12,12,13,14,15,15,16,17,17,18,19,2 0,20,21,22,22,23,24,25,25,26,27,27,28,29,30,30,31,32,32,33,34,35,35,36,3 7,37,38,39,40,40,41,42,42,43,44,45,45,46,47,47,48,49,50,50,51,52,52,53,5 4,55,55,56,57,57,58,59,60,60,61,62,62,63,64,65,65,66,67,67,68,69,70,70,7 1,72,72,73,74,75,75,76,77,77,78,79,80,80,81,82,82,83,84,85,85,86,87,87,8 8,89,90,90};71.const int Table_fu1[256]={-44,-44,-44,-43,-43,-43,-42,-42,-42,-41,-41,-41,-40,-40,-40,-39,-39,-39,-38,-38,-38,-37,-37,-37,-36,-36,-36,-35,-35,-35,-34,-34,-33,-33,-33,-32,-32,-32,-31,-31,-31,-30,-30,-30,-29,-29,-29,-28,-28,-28,-27,-27,-27,-26,-26,-26,-25,-25,-25,-24,-24,-24,-23,-23,-22,-22,-22,-21,-21,-21,-20,-20,-20,-19,-19,-19,-18,-18,-18,-17,-17,-17,-16,-16,-16,-15,-15,-15,-14,-14,-14,-13,-13,-13,-12,-12,-11,-11,-11,-10,-10,-10,-9,-9,-9,-8,-8,-8,-7,-7,-7,-6,-6,-6,-5,-5,-5,-4,-4,-4,-3,-3,-3,-2,-2,-2,-1,-1,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9,9,10,10,11,11 ,11,12,12,12,13,13,13,14,14,14,15,15,15,16,16,16,17,17,17,18,18,18,19,19, 19,20,20,20,21,21,22,22,22,23,23,23,24,24,24,25,25,25,26,26,26,27,27,27, 28,28,28,29,29,29,30,30,30,31,31,31,32,32,33,33,33,34,34,34,35,35,35,36, 36,36,37,37,37,38,38,38,39,39,39,40,40,40,41,41,41,42,42,42,43,43};72.const int Table_fu2[256]={-227,-226,-224,-222,-220,-219,-217,-215,-213,-212,-210,-208,-206,-204,-203,-201,-199,-197,-196,-194,-192,-190,-188,-187,-185,-183,-181,-180,-178,-176,-174,-173,-171,-169,-167,-165,-164,-162,-160,-158,-157,-155,-153,-151,-149,-148,-146,-144,-142,-141,-139,-137,-135,-134,-132,-130,-128,-126,-125,-123,-121,-119,-118,-116,-114,-112,-110,-109,-107,-105,-103,-102,-100,-98,-96,-94,-93,-91,-89,-87,-86,-84,-82,-80,-79,-77,-75,-73,-71,-70,-68,-66,-64,-63,-61,-59,-57,-55,-54,-52,-50,-48,-47,-45,-43,-41,-40,-38,-36,-34,-32,-31,-29,-27,-25,-24,-22,-20,-18,-16,-15,-13,-11,-9,-8,-6,-4,-2,0,1,3,5,7,8,10,12,14,15,17,19,21,23,24,26,28,30,31,33,35,37,39,40,42,4 4,46,47,49,51,53,54,56,58,60,62,63,65,67,69,70,72,74,76,78,79,81,83,85,8 6,88,90,92,93,95,97,99,101,102,104,106,108,109,111,113,115,117,118,120,1 22,124,125,127,129,131,133,134,136,138,140,141,143,145,147,148,150,152,1 54,156,157,159,161,163,164,166,168,170,172,173,175,177,179,180,182,184,1 86,187,189,191,193,195,196,198,200,202,203,205,207,209,211,212,214,216,2 18,219,221,223,225};73.*len=3*nWidth*nHeight;74.if(!yuvBuf||!pRgbBuf)75.return false;76.const long nYLen=long(PIXELSIZE);77.const int nHfWidth=(nWidth>>1);78.if(nYLen<1||nHfWidth<1)79.return false;80.//Y data81.unsigned char*yData=yuvBuf;82.//v data83.unsigned char*vData=&yData[nYLen];84.//u data85.unsigned char*uData=&vData[nYLen>>2];86.if(!uData||!vData)87.return false;88.int rgb[3];89.int i,j,m,n,x,y,pu,pv,py,rdif,invgdif,bdif;90.m=-nWidth;91.n=-nHfWidth;92.bool addhalf=true;93.for(y=0;y<nHeight;y++){94.m+=nWidth;95.if(addhalf){96.n+=nHfWidth;97.addhalf=false;98.}else{99.addhalf=true;100.}101.for(x=0;x<nWidth;x++){102.i=m+x;103.j=n+(x>>1);104.py=yData[i];105.//search tables to get rdif invgdif and bidif106.rdif=Table_fv1[vData[j]];//fv1107.invgdif=Table_fu1[uData[j]]+Table_fv2[vData[j]];//fu1+fv2 108.bdif=Table_fu2[uData[j]];//fu2109.rgb[0]=py+rdif;//R110.rgb[1]=py-invgdif;//G111.rgb[2]=py+bdif;//B112.j=nYLen-nWidth-m+x;113.i=(j<<1)+j;114.//copy this pixel to rgb data115.for(j=0;j<3;j++)116.{117.if(rgb[j]>=0&&rgb[j]<=255){118.pRgbBuf[i+j]=rgb[j];119.}120.else{121.pRgbBuf[i+j]=(rgb[j]<0)?0:255;122.}123.}124.} 125.}126.return true; 127.}。
android中YUV转RGB的方法在一个外国网站上看到一段YUV转RGB的程序很不错,根据维基上的知识,方法应该是没问题的,自己也用过了,效果没问题。
首先说一下android上preview中每一帧的信息都是YUV420的,或者叫NV21,又或者叫YCbCr_420_SP (NV21),反正这么个东西呢,Y,U,V三个分量的数量比是4:1:1.也就是说每四个像素共用一对UV。
举个例子,如果是一个30*40的帧,那么有1200个Y分量,分别有300个U和300个V分量。
总共有1200*1.5这么多个值。
如果调用android中的onPreviewFrame(byte[] data, Camera camera)这个方法,data就是这一帧的数据。
数据是这么排列的:首先是Y分量(亮度) Y.... Y....接着是v,u分量成对出现 (v,u),(v,u)...... (v,u),(v,u)......然后讲一下共用的v,u问题比如图像是4*4的: Y11,Y12,Y13,Y14 Y21,Y22,Y23,Y24 Y31,Y32,Y33,Y34 Y41,Y42,Y43,Y44 V,U分量是这样的: (V1,U1),(V2,U2) (V3,U3),(V4,U4) 其中, Y11,Y12, Y21,Y22, 共用 (V1,U1) Y13,Y14 Y23,Y24 共用 (V2,U2) 其他的同理。
根据以上的介绍,我们就可以写程序了,程序如下:int yy,v,u; //三个分量 int frame_size=width*height;int p_y=x*width+y; //当前像素点y分量的位置int p_v=frame_size+(x >> 1) * width + (y& ~1) + 0; //当前像素点v分量的位置 int p_u=frame_size+(x >> 1) * width + (y& ~1) + 1; //当前像素点u分量的位置 yy=pSrc[p_y]; v=pSrc[p_v]; u=pSrc[p_u];yy = yy-16>0 ? yy-16 : 0; v= v-128>0?v-128:0;u=u-128>0?u-128:0; //开始转化成rgbunsigned char r = (unsigned char) ((116 *(int)yy + 160 *(int)v)/100);unsigned char g = (unsigned char) ((116 * (int)yy - 81 * (int)v - 39 * (int)u)/100); unsigned cha r b = (unsigned char) ((116 * (int)yy + 202 * (int)u)/100);。
(转)RGB、YUY2、YUYV、YVYU、UYVY、AYUV格式详解YUY2经常⽤于电视制式以及许多摄像头的输出格式.⽽我们在处理时经常需要将其转化为RGB进⾏处理,这⾥简单介绍下YUY2(YUV)与RGB 之间相互转化的关系:YUY2(YUV) To RGB:C = Y - 16D = U - 128E = V - 128R = clip(( 298 * C + 409 * E + 128) >> 8) G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8) B = clip(( 298 * C + 516 * D + 128) >> 8)其中 clip()为限制函数,将其取值限制在0-255之间.RGB To YUY2(YUV):Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128上述两个公式在代码中的int YUV2RGB(void* pYUV, void* pRGB, int width, int height, bool alphaYUV, bool alphaRGB);int RGB2YUV(void* pRGB, void* pYUVX, int width, int height, bool alphaYUV, bool alphaRGB);函数中转换。
在诸如摄像头的数据获取中,我们往往需要直接在YUY2(YUV)空间上进⾏⼀些图象处理,我们希望能够在YUY2 (YUV)进⾏⼀些RGB上可以做到的处理。
这⾥已blending为例,将两张带有透明度的YUY2(YUV)图⽚进⾏叠加,以达到在RGB空间进⾏图像合成的效果。
颜色空间是一个三维坐标系统,每一种颜色由一个点表示。
在RGB 颜色空间中,红,绿,蓝是基本元素。
RGB 格式是显示器通常使用的格式。
在YUV 空间中,每一个颜色有一个亮度信号Y,和两个色度信号U 和V。
亮度信号是强度的感觉,它和色度信号断开,这样的话强度就可以在不影响颜色的情况下改变。
YUV 格式通常用于PAL制,即欧洲的电视传输标准,而且缺省情况下是图像和视频压缩的标准。
YUV 使用RGB的信息,但它从全彩色图像中产生一个黑白图像,然后提取出三个主要的颜色变成两个额外的信号来描述颜色。
把这三个信号组合回来就可以产生一个全彩色图像。
YUV 使用红,绿,蓝的点阵组合来减少信号中的信息量。
Y 通道描述Luma 信号,它与亮度信号有一点点不同,值的范围介于亮和暗之间。
Luma 是黑白电视可以看到的信号。
U (Cb) 和V (Cr) 通道从红(U) 和蓝(V) 中提取亮度值来减少颜色信息量。
这些值可以从新组合来决定红,绿和蓝的混合信号。
YUV和RGB的转换: ★这里是不是不是yuv而是Y Cb Cr???★Y = 0.299 R + 0.587 G + 0.114 BU = -0.1687 R - 0.3313 G + 0.5 B + 128V = 0.5 R - 0.4187 G - 0.0813 B + 128R = Y + 1.402 (V-128)G = Y - 0.34414 (U-128) - 0.71414 (V-128)B = Y + 1.772 (U-128)以前,一直没明白yuv和YcbCr之间的差异,想必有些朋友也会有同样的疑惑。
所以,我看完之后就记载下来了。
一、和rgb之间换算公式的差异yuv<-->rgbY'= 0.299*R' + 0.587*G' + 0.114*B'U'= -0.147*R' - 0.289*G' + 0.436*B' = 0.492*(B'- Y')V'= 0.615*R' - 0.515*G' - 0.100*B' = 0.877*(R'- Y')R' = Y' + 1.140*V'G' = Y' - 0.394*U' - 0.581*V'B' = Y' + 2.032*U'yCbCr<-->rgbY’ = 0.257*R' + 0.504*G' + 0.098*B' + 16Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128R' = 1.164*(Y’-16) + 1.596*(Cr'-128)G' = 1.164*(Y’-16) - 0.813*(Cr'-128) - 0.392*(Cb'-128)B' = 1.164*(Y’-16) + 2.017*(Cb'-128)Note: 上面各个符号都带了一撇,表示该符号在原值基础上进行了gamma correction二、来源上的差异yuv色彩模型来源于rgb模型,该模型的特点是将亮度和色度分离开,从而适合于图像处理领域。
csc bt.601公式
CSC (Color Space Converter) BT.601是一种用于视频信号的颜色空间转换标准,主要用于标清视频。
BT.601定义了YUV颜色空间和RGB颜色空间之间的转换公式。
具体的转换公式如下:
对于RGB转换到YUV:
Y = 0.299R + 0.587G + 0.114B.
U = -0.147R 0.289G + 0.436B.
V = 0.615R 0.515G 0.100B.
对于YUV转换到RGB:
R = Y + 1.140V.
G = Y 0.394U 0.581V.
B = Y + 2.032U.
这些公式描述了如何将RGB颜色空间的颜色值转换为YUV颜色空间的颜色值,以及如何将YUV颜色空间的颜色值转换为RGB颜色空间的颜色值。
这些公式是BT.601标准中定义的,用于视频信号的颜色空间转换,以便在不同设备和系统之间进行兼容和互操作。
这些转换公式在视频处理和编解码中发挥着重要作用,确保视频信号在不同设备上能够正确显示和处理。
我们从CMOS摄像头采集到的数据一般是YUV2格式的,YUV2是YUYV,YVYU,VYUY,UYVY,四种格式的统称,在源代码中,采用YUYV格式的数据转换为RGB24格式的数据,当然,通过修改某些参数,YUV2所有格式的数据都可以转换成RGB24即RGB888格式的数据。
首先,我们采集到的数据是以Y0,V0,Y1,U0, Y2,V2,Y3,U2 …的格式存放在内存中,这里,我是通过串口将该块内存中的数据打印到文件中,并将数据稍作编辑,即可作为带转换的YUV2数据。
YUV与RGB的转换关系可以看到,Y0,V0…都是8位数据,占1个字节,但每个16进制数以字符存放在内存中,那么Y,U,V就是占2个字节,Y0,V0,Y1,U0,共32位,包含两个像素,转换为RGB24时,关系如下:RGB0=(Y0,V0,U0),RGB1=(Y1,V0,U0),依次类推,可以看到每个YUV2占32位,转换为2个RGB时,占48位,所有,字符长度增加了0.5倍。
从文件中读取数据,并分配内存大小,YUV的数据大小为WIDTH*HEIGHT*2,而RGB数据大小为WIDTH*HEIGHT*3;具体转换算法:图片中,是网上常用的两种转换算法,(注释部分是一种,在*号之间的部分是目前在使用的一种)存在问题:核心部分就是从文件中读取数据,分配内存,并将数据进行转换,然后放回文件中。
但我们从文件中读取到的数据均为字符型,而在转换关系中,用到的数据均为数值型,所以需要对数据进行转换处理,算法如下:以上部分是将字符型数据转换成数值型,另一方面,存入文件中,还应当将数值型数据转换成字符型,即上图转换算法的逆算法如下:到此,整个转换算法分析完毕。
BYTE *YUV422_to_RGB24(VIDEO_FRAME_S * pVBuf,LONG *pwidth, LONG *pheight,FILE *pfd,BYTE *rgb24){LONG width=*pwidth;LONG height=*pheight;HI_S32 s32Ret = HI_SUCCESS;BYTE *pVBufVirt_Y;BYTE *pVBufVirt_C;BYTE *pMemContent;HI_U32 phy_addr[2],size;HI_CHAR *pUserPageAddr[2];PIXEL_FORMAT_E enPixelFormat = pVBuf->enPixelFormat;HI_U32 u32UvHeight;if (PIXEL_FORMAT_YUV_SEMIPLANAR_420 == enPixelFormat){size = (pVBuf->u32Stride[0])*(pVBuf->u32Height)*3/2;u32UvHeight = pVBuf->u32Height/2;}else{size = (pVBuf->u32Stride[0])*(pVBuf->u32Height);u32UvHeight = pVBuf->u32Height;}phy_addr[0] = pVBuf->u32PhyAddr[0];phy_addr[1] = pVBuf->u32PhyAddr[1];//printf("phy_addr:%x, size:%d\n", phy_addr, size);pUserPageAddr[0] = (BYTE *) HI_MPI_SYS_Mmap(phy_addr[0], size);if (NULL == pUserPageAddr[0])return HI_FAILURE;}pUserPageAddr[1] = (BYTE *) HI_MPI_SYS_Mmap(phy_addr[1], size);if (NULL == pUserPageAddr[0]){return HI_FAILURE;}// printf("stride: %d,%d\n",pVBuf->u32Stride[0],pVBuf->u32Stride[1] );pVBufVirt_Y = pUserPageAddr[0];pVBufVirt_C = pUserPageAddr[1];BYTE *yuv422[3];yuv422[0]=pVBufVirt_Y;yuv422[1]=pVBufVirt_C;yuv422[2]=pVBufVirt_C;/*****************************************************************************/ BITMAPFILEHEADER bmfh;BITMAPINFOHEADER bmih;DWORD Linebytes=width*3;DWORD SizeImage = Linebytes*height;bmfh.bfType=0x4D42;bmfh.bfSize=SizeImage+54;bmfh.bfReserved1 = 0;bmfh.bfReserved2 = 0;bmfh.bfOffBits =54;bmih.biSize =40;bmih.biWidth = width;bmih.biHeight = height;bmih.biPlanes = 1;bmih.biBitCount = 24;bmih.biCompression = 0;bmih.biSizeImage =width*height*3;bmih.biXPelsPerMeter = 0;bmih.biYPelsPerMeter = 0;bmih.biClrUsed = 0;bmih.biClrImportant = 0;saveBmpFileHeader(pfd,&bmfh);saveBmpInfoHeader(pfd,&bmih);rgb24=(BYTE *)malloc(Linebytes*height);int R,G,B;BYTE Y,U,V;int x,x1,y;x1=0;for (y=0;y<height;y++)for (x=0;x<width;x++){x1=x;Y = *(yuv422[0] + y*width + x);if(x==0){U = *(yuv422[1] + y*width + 0);V = *(yuv422[2] + y*width + 1);}else if((x>0)&&(x%2==0)){U = *(yuv422[1] + y*width + x);V = *(yuv422[2] + y*width + x+1);}else{U = *(yuv422[1] + y*width + x-1);V = *(yuv422[2] + y*width + x);}R = Y + 1.402*(V-128);//method 1:G = Y - 0.34414*(U-128) - 0.71414*(V-128);B = Y + 1.772*(U-128);// R=1.164*(Y-16)+1.596*(V-128);//method 2:// G=1.164*(Y-16)+0.813*(V-128)-0.391*(U-128); // B=1.164*(Y-16)+2.018*(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] = (BYTE)R;rgb24[((height-y-1)*width + x)*3 + 1] = (BYTE)G;rgb24[((height-y-1)*width + x)*3 + 2] = (BYTE)B;}}fwrite(rgb24,Linebytes*height,1,pfd);fclose(pfd);printf("YUV2BMP %d success ok\n",gs_s32SnapCntbmp);HI_MPI_SYS_Munmap(pUserPageAddr[0],size);HI_MPI_SYS_Munmap(pUserPageAddr[1],size);return rgb24;}。
YUV转为RGB24(Java版本实现)YUV简介⼀般来说,直接采集到的视频数据是RGB24的格式,RGB24⼀帧的⼤⼩size=width×heigth×3 Byte,RGB32的size=width×heigth×4 Byte。
如果是I420(即YUV标准格式4:2:0)的数据量是size=width×heigth×1.5 Byte。
在采集到RGB24数据后,需要对这个格式的数据进⾏第⼀次压缩。
即将图像的颜⾊空间由RGB24转化为IYUV。
因为X264在进⾏编码的时候需要标准的YUV(4:2:0)。
但是这⾥需要注意的是,虽然YV12也是(4:2:0),但是YV12和I420的却是不同的,在存储空间上⾯有些区别。
区别如下:YV12 :亮度(⾏×列) + V(⾏×列/4) + U(⾏×列/4)I420 :亮度(⾏×列) + U(⾏×列/4) + V(⾏×列/4)可以看出,YV12和I420基本上是⼀样的,就是UV的顺序不同。
YUV420p 和 YUV420的区别在于存储格式上有区别:YUV420p:yyyyyyyy uuuu vvvvvYUV420: yuv yuv yuv另外需要注意的是海康威视设备回调数据类型为YV12格式;⽽⼤华设备回调数据类型为YUV420格式。
// YV12格式⼀个像素占1.5个字节private byte[] YV12_To_RGB24(byte[] yv12, int width, int height) {if(yv12 == null) {return null;}int nYLen = (int)width * height;int halfWidth = width >> 1;if(nYLen<1 || halfWidth<1) {return null;}// yv12's data structure// |WIDTH |// y......y--------// y......y HEIGHT// y......y// y......y--------// v..v// v..v// u..u// u..u// Convert YV12 to RGB24byte[] rgb24 = new byte[width * height * 3];int[] rgb = new int[3];int i, j, m, n, x, y;m = -width;n = -halfWidth;for(y=0; y<height; y++) {m += width;if(y%2 != 0) {n += halfWidth;}for(x=0; x<width; x++) {i = m+x;j = n + (x>>1);rgb[2] = (int)((int)(yv12[i]&0xFF) + 1.370705 * ((int)(yv12[nYLen+j]&0xFF) - 128)); // rrgb[1] = (int)((int)(yv12[i]&0xFF) - 0.698001 * ((int)(yv12[nYLen+(nYLen>>2)+j]&0xFF) - 128) - 0.703125 * ((int)(yv12[nYLen+j]&0xFF) - 128)); // grgb[0] = (int)((int)(yv12[i]&0xFF) + 1.732446 * ((int)(yv12[nYLen+(nYLen>>2)+j]&0xFF) - 128)); // b//j = nYLen - iWidth - m + x;//i = (j<<1) + j; //图像是上下颠倒的j = m + x;i = (j<<1) + j;for(j=0; j<3; j++) {if(rgb[j]>=0 && rgb[j]<=255) {rgb24[i+j] = (byte)rgb[j];} else {rgb24[i+j] = (byte) ((rgb[j] < 0)? 0 : 255);}}}}return rgb24; }。
Android 视频渲染:YUV 转RGBAndroid SDK 为Camera 预览提供了一个Demo ,这个Demo 的大致流程是初始化一个Camera 和一个SurfaceView ,SurfaceView 被 创建之后可以获取到一个SurfaceHolder 的实例,将这个SurfaceHolder 传递给Camera ,这样Camera 就会自动的将捕获到的 视频数据渲染到SurfaceView 上面,这也就是Camera 预览的效果。
当然更多的时候我们需要获取到Camera 的实时视频数据来自己进行预处理 并渲染,Camera 也提供了这个接口,用法如下:1 2 34 5mCamera.setPreviewCallback (new PreviewCallback (){ @Overridepublic void onPreviewFrame (byte [] data, Camera camera ) { }); 在这个回调里我们就能够获取到当前帧的数据,我们可以对其进行预处理,比如压缩、加密、特效处理等,不过byte[]这个buffer 里面的数据是 YUV 格式的,一般是YUV420SP ,而Android 提供的SurfaceView 、GLSurfaceView 、TextureView 等控件只支 持RGB 格式的渲染,因此我们需要一个算法来解码。
先介绍一个YUV 转RGB 的算法,转换的公式一般如下,也是线性的关系:R=Y+1.4075*(V-128)G=Y-0.3455*(U-128) – 0.7169*(V-128)B=Y+1.779*(U-128)下面是一段将YUV 转成ARGB_8888的jni 代码,类似的代码网上很多,将这个代码简单修改一下也能直接用在C 中。
1 2 3 4 5 6 7 jintArrayJava_com_spore_jni_ImageUtilEngine_decodeYUV420SP (JNIE nv * env ,jobject thiz , jbyteArray buf , jint width , jint height ) { jbyte * yuv420sp = (*env )->GetByteArrayElements (env , buf , 0);8 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0int frameSize = width * height;jint rgb[frameSize];// 新图像像素值int i =0, j =0,yp =0;int uvp =0, u =0, v =0;for(j =0, yp =0; j < height; j++){uvp = frameSize +(j >>1)* width;u =0;v =0;for(i =0; i < width; i++, yp++){int y =(0xff&((int) yuv420sp[yp])) -16;if(y <0)y =0;if((i &1)==0){v =(0xff& yuv420sp[uvp++])-128;u =(0xff& yuv420sp[uvp++])-128;}int y1192 =1192* y;int r =(y1192 +1634* v);int g =(y1192 -833* v -400* u);int b =(y1192 +2066* u);if(r <0) r =0;else if(r >262143) r =262143;if(g <0) g =0;else if(g >262143) g =262143;if(b <0) b =0;else if(b >262143) b =262143;rgb[yp]=0xff000000|((r <<6)& 0xff0000)|((g >>2)&0xff00)|((b >>10)&0xff);}}jintArray result =(*env)->NewIntArray(env, frameSize);(*env)->SetIntArrayRegion(env,result,0, frameSize, rgb);(*env)->ReleaseByteArrayElements(env,buf, yuv420sp,0);return result;}313233343536373839441424344JNI代码对应的Java接口如下:1 public native int[]decodeYUV420SP(byte[] buf, int width, int height);从这个接口就很容易理解了,参数buf就是从Camera的onPreviewFrame回调用获取到的YUV格式的视频帧数据,width和height分别是对应的Bitmap的宽高。
yuv下alpha计算在计算机图像处理中,YUV是一种常用的色彩编码格式,用于将彩色图像的亮度和色度分离。
而Alpha通道是RGBA颜色模型中的一个通道,用于表示图像的透明度。
本文将介绍在YUV色彩空间下如何进行Alpha通道的计算。
一、YUV色彩空间简介YUV色彩空间是一种将亮度(Y)和色度(U、V)分离的编码方式。
在YUV色彩空间中,亮度(Y)代表图像的明暗程度,而色度(U、V)则代表图像的颜色信息。
二、YUV转RGB公式在进行Alpha通道计算之前,需要先将YUV图像转换为RGB图像。
YUV转RGB的公式如下:R = Y + 1.13983VG = Y - 0.39465U - 0.58060VB = Y + 2.03211U三、Alpha通道计算Alpha通道表示图像的透明度,取值范围为0到255,其中0表示完全透明,255表示完全不透明。
在YUV色彩空间下,可以利用亮度(Y)的数值来计算Alpha通道的值。
Alpha = 255 - Y根据上述公式,可以通过Y的数值来计算Alpha通道的值。
较高的亮度值对应较低的Alpha值,反之亦然。
这样,通过调整Y的数值,可以控制图像的透明度。
四、示例程序下面是一个示例程序,演示了如何在YUV色彩空间下计算Alpha 通道:```import cv2# 读取YUV图像yuv_image = cv2.imread("input.yuv", cv2.IMREAD_UNCHANGED) # 分离Y、U、V通道Y = yuv_image[:, :, 0]U = yuv_image[:, :, 1]V = yuv_image[:, :, 2]# 计算RGB图像R = Y + 1.13983 * VG = Y - 0.39465 * U - 0.58060 * VB = Y + 2.03211 * U# 计算Alpha通道Alpha = 255 - Y# 合并RGB和Alpha通道rgba_image = cv2.merge([R, G, B, Alpha])# 保存结果图像cv2.imwrite("output.png", rgba_image)```通过上述示例程序,我们可以根据YUV图像中的亮度值计算出对应的Alpha通道值,并将结果保存为带有Alpha通道的RGBA图像。
一种yuv格式remap在图像处理中,remap操作是一种常见的操作,用于将图像从一个坐标系映射到另一个坐标系。
而本文将讨论一种常见的yuv格式的remap操作。
首先,yuv格式是一种通用于数字视频的颜色空间表示方式,其中y表示亮度,而u和v则分别表示蓝色和红色色度。
在图像处理中,通常使用yuv格式以提高效率和减小数据存储需求。
在进行yuv格式的remap操作时,需要先将输入的yuv图像转换为rgb格式的图像,然后进行remap操作,最后再将rgb格式的图像转换回yuv格式的图像输出。
以下是yuv格式的remap操作的步骤:第一步:将输入的yuv图像转换为rgb格式的图像。
这一步需要使用yuv到rgb色彩空间的转换公式,通常使用以下公式:R = Y + 1.13983VG = Y - 0.39465U - 0.58060VB = Y + 2.03211U其中Y、U、V分别表示yuv格式的三个通道的像素值。
转换完成后,得到一个rgb格式的图像。
第二步:进行remap操作。
remap操作实际上是一种像素坐标的重新映射,通常涉及到一个映射矩阵或者函数。
在具体的操作中,可以使用OpenCV库提供的remap函数实现。
这个函数需要输入两个变换矩阵(x和y方向上的),以及一个interpolation类型来说明像素值的插值方式。
其中,变换矩阵可以通过计算坐标映射关系得到。
第三步:将rgb格式的图像转换回yuv格式的图像。
这一步需要使用rgb到yuv色彩空间的转换公式,通常使用以下公式:Y = 0.299R + 0.587G + 0.114BU = -0.14713R - 0.28886G + 0.436BV = 0.615R - 0.51498G - 0.10001B其中R、G、B分别表示rgb格式的三个通道的像素值。
转换完成后,得到一个yuv格式的图像。
以上就是yuv格式的remap操作的步骤。
这个操作可以应用于许多领域,例如视觉跟踪、图像纠正等等。
yuv 和颜色对应关系YUV是一种用于视频编码和图像处理的颜色空间模型,它将亮度(Y)和色度(UV)分离开来,使得图像的处理更加高效和灵活。
在YUV 颜色对应关系中,Y表示亮度,U和V表示色度。
本文将详细介绍YUV和颜色之间的对应关系。
YUV颜色空间模型是由亮度(Y)和色度(UV)组成的。
亮度表示图像的明亮程度,色度表示图像的颜色信息。
亮度和色度的分离可以有效地压缩图像数据,从而减小存储空间和传输带宽的占用。
在YUV颜色空间中,亮度(Y)的取值范围是0到255,表示黑到白的变化程度。
较小的Y值代表较暗的像素,较大的Y值代表较亮的像素。
色度(UV)的取值范围是-128到127,表示颜色的偏移程度。
较小的U和V值代表较蓝或绿的偏移,较大的U和V值代表较红或黄的偏移。
在YUV颜色空间中,亮度和色度的转换公式如下:R = Y + 1.402 * (V-128)G = Y - 0.344136 * (U-128) - 0.714136 * (V-128)B = Y + 1.772 * (U-128)这些公式描述了YUV到RGB的转换过程。
通过这些公式,我们可以将YUV颜色空间中的像素值转换为RGB颜色空间中的像素值,从而实现图像的显示和处理。
在实际应用中,YUV颜色空间经常被用于视频编码和压缩。
由于人眼对亮度的敏感性高于对色度的敏感性,因此在视频编码中,通常对亮度进行更高的压缩,而对色度进行较低的压缩。
这种压缩方式可以减小视频文件的大小,同时保持较好的视觉效果。
YUV颜色空间还被广泛应用于图像处理中的色彩空间转换、图像增强和视频特效等方面。
通过对YUV颜色空间中的亮度和色度进行分析和处理,我们可以实现图像的去噪、锐化、对比度增强等效果,从而提升图像的质量和观感。
YUV是一种用于视频编码和图像处理的颜色空间模型,它将亮度和色度分离开来,使得图像的处理更加高效和灵活。
在YUV颜色对应关系中,亮度(Y)表示图像的明亮程度,色度(UV)表示图像的颜色信息。
采⽤Python实现快速YUV转RGB⽬标采⽤Python脚本实现快速的YUV图像⼆进制(BIN)⽂件到sRGB-24bit图像的转换,并保存为PNG⽂件。
解决⽅法⼀般来说,YUV转RGB的主要⼿段有三种:libYUV, from Google Chromium Project, Open Source.FFmpeg, the most popular tool to decode images and videos across all web/pc platforms.(BiliBili也是⽤的这个库做的视频解码)OpenCV, open source project mainly providing all popular and stable algorithms in computer vision.各⾃特点:采⽤libYUV会更快(⼀般4倍),采⽤FFmpeg效果可能更贴近⼈眼视觉(?),但采⽤OpenCV最⽅便,因为libYUV需要从源码根据平台修改编译,并没有库的形式直接调⽤,FFmpeg虽然有库,但是对python不友好(可能是我个⼈对基于FFmpeg的库不了解?),opencv就很简单,⼆进制的Yuv数据读进来就能直接转sRGB,⽽且和Numpy⽆缝结合,极为便利。
Show me the code right now!import numpy as npimport cv2import sysimport osimport platformimport globdef Windows():return platform.system() == "Windows"YUV_NV21 = 0YUV_NV12 = 1# param:# @f: file pointer# @w: image width# @h: image height# @p: pitch size# @c: image color channel# @t YUV type, NV21 or NV12def DecodeYUV(f, w, h, p, c, t):if c == 3:size_ = p*h*3//2else:size_ = p*hdata = f.read(size_)if c == 3:im_yuv = np.frombuffer(data, dtype='<'+str(size_)+'B').reshape([h*3//2, p])else:im_yuv = np.frombuffer(data, dtype='<'+str(size_)+'B').reshape([h, p])if c==1:return im_yuvim_rgb = Noneif t == YUV_NV21:im_rgb = cv2.cvtColor(im_yuv, cv2.COLOR_YUV2RGB_NV21)elif t == YUV_NV12:im_rgb = cv2.cvtColor(im_yuv, cv2.COLOR_YUV2RGB_NV12)else:print('not implemented yet!')assert Falsereturn im_rgb[:, :w]if __name__ == '__main__':assert len(sys.argv) == 2print('================ CONVERT YUV 2 RGB FOR PRAGUE ONLY =============') # create dirs for output imagesdir_main = 'picMain'dir_aux = 'picAux'dir_bokeh = 'Bokeh'cmd_mkdir = ''if Windows():cmd_mkdir = 'md 'else:cmd_mkdir = 'mkdir -p 'os.system(cmd_mkdir + dir_main)os.system(cmd_mkdir + dir_aux)os.system(cmd_mkdir + dir_bokeh)yuv_dir = sys.argv[1]print('YUV DIR : ' + yuv_dir)print('****** PROCESSING MAIN ******')# find main imagesmain_w = 4608main_h = 3456pitch = main_wfiles = glob.glob(yuv_dir + '/*_BokehInput0.nv21')for i in range(len(files)):print(files[i])f_ = open(files[i], 'rb')im_ = DecodeYUV(f_, main_w, main_h, pitch, 3, YUV_NV12)f_.close()# save RGB imagesfn_start = ''if Windows():fn_start = files[i].rfind('\\')else:fn_start = files[i].rfind('/')fn_ = dir_main + files[i][fn_start:]fn_ = fn_.replace('.nv21', '.png')cv2.imwrite(fn_ , im_)print('****** PROCESSING AUX ******')# find aux imagesaux_w = 2592aux_h = 1944pitch = 3072files = glob.glob(yuv_dir + '/*_BokehInput1.nv21')for i in range(len(files)):print(files[i])f_ = open(files[i], 'rb')im_ = DecodeYUV(f_, aux_w, aux_h, pitch, 3, YUV_NV12)f_.close()# save RGB imagesfn_start = ''if Windows():fn_start = files[i].rfind('\\')else:fn_start = files[i].rfind('/')fn_ = dir_aux + files[i][fn_start:]fn_ = fn_.replace('.nv21', '.png')cv2.imwrite(fn_ , im_)print('****** PROCESSING BOKEH ******')# find aux imagesbokeh_w = main_wbokeh_h = main_hpitch = bokeh_wfiles = glob.glob(yuv_dir + '/*_BokehOutput.nv21')for i in range(len(files)):print(files[i])f_ = open(files[i], 'rb')im_ = DecodeYUV(f_, bokeh_w, bokeh_h, pitch, 3, YUV_NV12)f_.close()# save RGB imagesfn_start = ''if Windows():fn_start = files[i].rfind('\\')else:fn_start = files[i].rfind('/')fn_ = dir_bokeh + files[i][fn_start:]fn_ = fn_.replace('.nv21', '.png')cv2.imwrite(fn_ , im_)print('================================================================')整个代码中其实核⼼的只有两⾏(或2个函数调⽤):1. np.frombuffer():从⼆进制字节流中结构化为numpy数组,如果字节流来⾃⽹络则选择⼤端的>{size}B,如果不是uint8,⽽是float类型,则选择<{size}f,这个规则是numpy适应struct库得到的。
YUV转RGB(转)
1 前言
自然界的颜色千变万化,为了给颜色一个量化的衡量标准,就需要建立色彩空间模型来描述各种各样的颜色,由于人对色彩的感知是一个复杂的生理和心理联合作用的过程,所以在不同的应用领域中为了更好更准确的满足各自的需求,就出现了各种各样的色彩空间模型来量化的描述颜色。
我们比较常接触到的就包括RGB / CMYK / YIQ / YUV / HSI等等。
对于数字电子多媒体领域来说,我们经常接触到的色彩空间的概念,主要是RGB , YUV这两种(实际上,这两种体系包含了许多种具体的颜色表达方式和模型,如sRGB, Adobe RGB, YUV422, YUV420 …), RGB是按三基色加光系统的原理来描述颜色,而YUV则是按照亮度,色差的原理来描述颜色。
即使只是RGB YUV这两大类色彩空间,所涉及到的知识也是十分丰富复杂的,自知不具备足够的相关专业知识,所以本文主要针对工程领域的应用及算法进行讨论。
2 YUV相关色彩空间模型
2.1 YUV 与YIQ YcrCb
对于YUV模型,实际上很多时候,我们是把它和YIQ / YCrCb模型混为一谈的。
实际上,YUV模型用于PAL制式的电视系统,Y表示亮度,UV并非任何单词的缩写。
YIQ模型与YUV模型类似,用于NTSC制式的电视系统。
YIQ颜色空间中的I和Q分量相当于将YUV空间中的UV分量做了一个33度的旋转。
YCbCr颜色空间是由YUV颜色空间派生的一种颜色空间,主要用于数字电视系统中。
从RGB到YCbCr的转换中,输入、输出都是8位二进制格式。
三者与RGB的转换方程如下:
RGB -> YUV:
实际上也就是:
Y=0.30R+0.59G+0.11B ,U=0.493(B-Y) ,V=0.877(R-Y)
RGB -> YIQ:
RGB -> YCrCb:
从公式中,我们关键要理解的一点是,UV / CbCr信号实际上就是蓝色差信号和红色差信号,进而言之,实际上一定程度上间接的代表了蓝色和红色的强度,理解这一点对于我们理解各种颜色变换处理的过程会有很大的帮助。
我们在数字电子多媒体领域所谈到的YUV格式,实际上准确的说,是以YcrCb
色彩空间模型为基础的具有多种存储格式的一类颜色模型的家族(包括YUV444 / YUV422 / YUV420 / YUV420P等等)。
并不是传统意义上用于PAL制模拟电视的YUV 模型。
这些YUV模型的区别主要在于UV数据的采样方式和存储方式,这里就不详述。
而在Camera Sensor中,最常用的YUV模型是YUV422格式,因为它采用4个字节描述两个像素,能和RGB565模型比较好的兼容。
有利于Camera Sensor和Camera controller的软硬件接口设计。
3 YUV2RGB快速算法分析
这里指的YUV实际是YcrCb了8 ) YUV2RGB的转换公式本身是很简单的,但是牵涉到浮点运算,所以,如果要实现快速算法,算法结构本身没什么好研究的了,主要是采用整型运算或者查表来加快计算速度。
首先可以推导得到转换公式为:
R = Y + 1.4075 *(V-128)
G = Y – 0.3455 *(U –128)– 0.7169 *(V –128)
B = Y + 1.779 *(U – 128)
3.1 整型算法
要用整型运算代替浮点运算,当然是要用移位的办法了,我们可以很容易得到下列算法:
u = YUVdata[UPOS] - 128;
v = YUVdata[VPOS] - 128;
rdif = v + ((v * 103) >> 8);
invgdif = ((u * 88) >> 8) +((v * 183) >> 8);
bdif = u +( (u*198) >> 8);
r = YUVdata[YPOS] + rdif;
g = YUVdata[YPOS] - invgdif;
b = YUVdata[YPOS] + bdif;
为了防止出现溢出,还需要判错计算的结果是否在0-255范围内,做类似下面的判断。
if (r>255)
r=255;
if (r<0)
r=0;
要从RGB24转换成RGB565数据还要做移位和或运算:
RGBdata[1] =( (r & 0xF8) | ( g >> 5) );
RGBdata[0] =( ((g & 0x1C) << 3) | ( b >> 3) );
3.2 部分查表法
查表法首先可以想到的就是用查表替代上述整型算法中的乘法运算。
rdif = fac_1_4075[u];
invgdif = fac_m_0_3455[u] + fac_m_0_7169[v];
bdif = fac_1_779[u];
这里一共需要4个1维数组,下标从0开始到255,表格共占用约1K的内存空间。
uv可以不需要做减128的操作了。
在事先计算对应的数组元素的值的时候计算在内就好了。
对于每个像素,部分查表法用查表替代了2次减法运算和4次乘法运算,4次移位运算。
但是,依然需要多次加法运算和6次比较运算和可能存在的赋值操作,相对第一种方法运算速度提高并不明显。
3.3 完全查表法
那么是否可以由YUV直接查表得到对应的RGB值呢?乍一看似乎不太可能,以最复杂的G的运算为例,因为G与YUV三者都相关,所以类似G=YUV2G[Y][U][V]这样的算法,一个三维下标尺寸都为256的数组就需要占用2的24次方约16兆空间,绝对是没法接受的。
所以目前多数都是采用部分查表法。
但是,如果我们仔细分析就可以发现,对于G我们实际上完全没有必要采用三维数组,因为Y只与UV运算的结果相关,与UV的个体无关,所以我们可以采用二次查表的方法将G的运算简化为对两个二维数组的查表操作,如下:
G = yig2g_table[ y ][ uv2ig_table[ u ][ v ] ];
而RB本身就只和YU或YV相关,所以这样我们一共需要4个8*8的二维表格,需要占用4乘2的16次方共256K内存。
基本可以接受。
但是对于手机这样的嵌入式运用来说,还是略有些大了。
进一步分析,我们可以看到,因为在手机等嵌入式运用上我们最终是要把数据转换成RGB565格式送到LCD屏上显示的,所以,对于RGB三分量来说,我们根本不需要8bit这么高的精度,为了简单和运算的统一起见,对每个分量我们其实只需要高6bit的数据就足够了,所以我们可以进一步把表格改为4个6*6的二维表格,这样一共只需要占用16K内存!在计算表格元素值的时候还可以把最终的溢出判断也事先做完。
最后的算法如下:
y = (YUVdata[Y1POS] >> 2);
u = (YUVdata[UPOS] >> 2);
v = (YUVdata[VPOS] >> 2);
r = yv2r_table[ y ][ v ];
g = yig2g_table[ y ][ uv2ig_table[ u ][ v ] ];
b = yu2b_table[ y ][ u ];
RGBdata[1] =( (r & 0xF8) | ( g >> 5) );
RGBdata[0] =( ((g & 0x1C) << 3) | ( b >> 3) );
这样相对部分查表法,我们增加了3次移位运算,而进一步减少了4次加法运算和6次比较赋值操作。
在计算表格元素数值的时候,要考虑舍入和偏移等因数使得计算的中间结果满足数组下标非负的要求,需要一定的技巧。
采用完全查表法,相对于第一种算法,最终运算速度可以有比较明显的提高,具体性能能提高多少,要看所在平台的CPU运算速度和内存存取速度的相对比例。
内存存取速度越快,用查表法带来的性能改善越明显。
在我的PC上测试的结果性能大约能
提高35%。
而在某ARM平台上测试只提高了约15%。
3.4 进一步的思考
实际上,上述算法:
RGBdata[1] =( (r & 0xF8) | ( g >> 5) );
RGBdata[0] =( ((g & 0x1C) << 3) | ( b >> 3) );
中的(r & 0xF8) 和( b >> 3) 等运算也完全可以在表格中事先计算出来。
另外,YU / YV的取值实际上不可能覆盖满6*6的范围,中间有些点是永远取不到的无输入,RB的运算也可以考虑用5*5的表格。
这些都可能进一步提高运算的速度,减小表格的尺寸。
另外,在嵌入式运用中,如果可能尽量将表格放在高速内存如SRAM中应该比放在SDRAM中更加能发挥查表法的优势。
4 RGB2YUV
目前觉得这个是没法将3维表格的查表运算化简为2维表格的查表运算了。
只能用部分查表法替代其中的乘法运算。
另外,多数情况下,我们需要的还是YUV2RGB的转换,因为从Sensor得到的数据通常我们会用YUV数据,此外JPG和MPEG实际上也是基于YUV格式编码的,所以要显示解码后的数据需要的也是YUV2RGB的运算8 )运气运气。