声明:下面的图部分是摘自博主的,感谢博主 https://www.cnblogs.com/tid-think/p/10616789.html,如果涉及侵权,感谢告知,
学习了博主的图,彻底搞懂了yuv格式的知识,yuv格式很多种类,乱七八糟的感觉,学了他的图,加上自己的知识,彻底搞明白了,

一、yuv planar和packed的区别。

YUV格式有两大类:planar和packed。

PIXEL_FORMAT_YVU_SEMIPLANAR_422,
PIXEL_FORMAT_YVU_SEMIPLANAR_420,
PIXEL_FORMAT_YVU_SEMIPLANAR_444,
PIXEL_FORMAT_YUV_SEMIPLANAR_422,
PIXEL_FORMAT_YUV_SEMIPLANAR_420,
PIXEL_FORMAT_YUV_SEMIPLANAR_444,
PIXEL_FORMAT_YUYV_PACKAGE_422,
PIXEL_FORMAT_YVYU_PACKAGE_422,
PIXEL_FORMAT_UYVY_PACKAGE_422,

对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。 对于packed的YUV格式,每个像素点的Y,U,V是连续交*存储的。

二、yuv422,yuv420,yuv444的区别。

YUV 4:4:4采样,每一个Y对应一组UV分量。
YUV 4:2:2采样,每两个Y共用一组UV分量。
YUV 4:2:0采样,每四个Y共用一组UV分量。

什么意思额,看下面的图,第二张图,实心黑圈代表u和v的值,每两个y共用一个uv,第三张图,空心白圈代表u和v的值,第一第二行,列共用一个u和v,
在这里插入图片描述
假如图像视720※576的
(1)、yuv444,图片的大小是720x576x3个字节,是总像素大小的3倍
y的字节是720x576
u的字节是720x576
v的字节是720x576
在这里插入图片描述
下面的图是摘自博主的,感谢博主 https://www.cnblogs.com/tid-think/p/10616789.html,如果涉及侵权,感谢告知,
博主原话
首先要介绍的是YUV444,这种格式占用空间最大,每个像素点有一个Y分量+一个U分量+一个V分量所以和rgb一样每个像素点占用3个字节!但是根据UV存储顺序不一样,又有两种不同的格式。
在这里插入图片描述

(2)、yuv422,图片的大小是720x576x2个字节,是总像素大小的2倍
y的字节是720x576
u的字节是720x576 /2
v的字节是720x576 /2在这里插入图片描述
在这里插入图片描述
下面的图是摘自博主的,感谢博主 https://www.cnblogs.com/tid-think/p/10616789.html,如果涉及侵权,感谢告知,
博主原话
接下来是YUV422 每两个Y分量公用一个UV分量,所以一个像素占用两个字节,根据存储顺序不同又分为四种不同的格式。
还有一种变态的V210格式,好像是苹果搞出来的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(3)、yuv420,图片的大小是720x576x3/2个字节,是总像素大小的1.5倍
y的字节是720x576 w*h
u的字节是720x576 /4 (w/2) * (h/2)
v的字节是720x576 /4 (w/2) * (h/2)
在这里插入图片描述
在这里插入图片描述
下面的图是摘自博主的,感谢博主 https://www.cnblogs.com/tid-think/p/10616789.html,如果涉及侵权,感谢告知,
博主原话
接下来是YUV420 每四个y分量共用一个UV分量,所以每个像素点占用1.5个字节空间,根据存储顺序不一样又分为四个不同的类型。
在这里插入图片描述
在这里插入图片描述

如果要将4 :2: 2 和4:2:0 转换:上图很清晰,只需把uv的值在垂直方向隔行取,就额可以了。

三、采集到的yuv420转rgb
下面的程序能帮助更能理解,yuv420的储存格式

yuv2rgb的转换公式:参数可以调,颜色将不一样。
r= y + 402 *(v - 128);
g = y - 0.34413 *(u - 128) - 0.71414 *(v - 128);
b = y + 1.772 *(u -128);

datas[0]对应装的是y,这里是指针,指向了一段存y的内存,
datas[1]对应装的是u,这里是指针,指向了一段存u的内存,
datas[2]对应装的是v,这里是指针,指向了一段存v的内存,
看下图,我的数据是这样存储的,别搞错了,下面的代码清楚的知道y是如何和u,v组合提取的。
在这里插入图片描述

如果要参考公式是可以的,如果你的yuv和我不一样,别傻傻的直接用,修改看你自己。
转换后,存在了数组里,调用的是opcv里的imwrite函数,保存为bmp格式的图片,自动填充bmp数据头,如果有需要自己
保存为bmp的,问度娘,如何填充54字节的数据头。

int w = 800;
int h = 600;
char rgbBuf[800*600*3] = { 0 };
{
	  	int i = 0,j = 0;
	 	double  y = 0, u = 0, v = 0;
	  	double  r = 0, g = 0, b = 0;
  		for (j = 0; j < h; j++) 
	  	{
	  		for (i = 0; i < w; i++) 
	   		{	   			
	    		rgbBuf[(w *j + i) * 3] =  0;
	    		rgbBuf[(w*j + i) * 3 + 1] =  0;
	    		rgbBuf[(w*j + i) * 3 + 2] =  0;
				
	    		y = *(datas[0] + w*j + i);
	     		v =	*(datas[1] +(w/2)* (j /2) + (i /2));//这里w/2,j/2,i/2,是u,v只有y的一半宽和高
	     		u = *(datas[2] +(w/2)* (j /2) + (i /2));
				
				r= y + 402 *(v - 128);
				g = y - 0.34413 *(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;
					
	    		rgbBuf[(w*j + i) * 3] 		=  (char)(r);
	    		rgbBuf[(w*j + i) * 3 + 1] 	=  (char)(g);
	    		rgbBuf[(w *j + i) * 3 + 2] 	=  (char)(b);
	  		}
	  	}

		cv::Mat resultMat(cv::Size(width, height), CV_8UC3, &rgbBuf);
		ret = imwrite(url, resultMat);
	}
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐