彩色空间转换(RGB与YUV格式文件转换)

一、实验原理

1.本次实验是实现YUV格式转换为RGB格式,这里的YUV其实是指数字高清的YCbCr。

根据亮度和色差计算公式,可以得到:

  • Y=0.2990R+0.5870G+0.1140B 
  • R-Y=0.7010R-0.5870G-0.1140B 
  • B-Y=-0.2990R-0.5870G+0.8860B 

2.为使色差信号的动态范围控制在-0.5~+0.5之间,要对色差信号进行归一化处理,得到UV的计算公式:

  • U=-0.1684R-0.3316G+0.5B 
  • V=0.5R-0.4187G-0.0813B 

由上式得到的UV范围在-128~+127之间,为避免负数,应在U、V之后各加128。

3.YUV在存储时,为了防止信号变得造成过载,在对分量信号进行8比特均匀量化时,Y分量256级上端留20级,下端留16级作为信号超越动态范围的保护带,UV分量256级上端留15级,下端留16级作为信号超越动态范围

的保护带。 
4.这里YUV采用的是420格式,既色度信号是亮度信号取样频率的四分之一。

5.得到YUV转换RUV的公式:

  • B=Y+1.779U
  • G=Y-0.3455U-0.7169V
  • R=Y+1.4075V
注意:这里在计算RBG时应先将UV的值减128。


二、实验流程分析

a.首先读取YUV文件,新建RGB文件

b.开辟RGB内存数组和YUV数组。由于RGB文件是按照BGRBGRBGR……的顺序存储一帧的,所以RBG开辟一个3倍像素数的数组,而YUV文件是YYYY……U……V……存储文件的,可以开辟一个像素数大小的数组存放Y分量和两个四分之一像素数大小的数组存放U和V分量。

c.读取每一帧的YUV值存在YUV三个缓存数组中

d.因为YUV有动态范围,先判断Y和UV是否超出要求的范围。

e.对YUV进行上采样,恢复出444格式的YUV。

f.按照转换公式,将每一个像素分别转换为RGB格式存在RGB缓存数组中。

e.重复c操作完成一帧的计算,再将RGB的值写入RGB文件。


三、关键代码及分析

1.本次实验工程文件包括两个源文件和一个头文件:


2.main.cpp是主文件:

a.通过工作参数设置目标文件和文件像素格式:

yuvFileName = argv[1];
	rgbFileName = argv[2];

	frameWidth = atoi(argv[3]);
	frameHeight = atoi(argv[4]);

b.开辟YUV和RGB的数组空间:
/* get an input buffer for a frame */
	yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
	uBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);
	vBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);


	/* get the output buffers for a frame */
	rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3);

C.读取YUV文件并判断是否超出YUV的动态范围,使用WHILE 函数,可以重复帧操作:

while (fread(yBuf, 1, frameWidth * frameHeight, yuvFile) && fread(uBuf, 1, frameWidth * frameHeight /4, yuvFile)
		&& fread(vBuf, 1, frameWidth * frameHeight /4, yuvFile))
	{
		for (i = 0; i < frameWidth*frameHeight; i++)
		{
			if (yBuf[i] < 16) yBuf[i] = 16;
			if (yBuf[i] > 235) yBuf[i] = 235;
		}

		for (i = 0; i < frameWidth*frameHeight / 4; i++)
		{
			if (uBuf[i] < 16) uBuf[i] = 16;
			if (uBuf[i] > 240) uBuf[i] = 240;

			if (vBuf[i] < 16) vBuf[i] = 16;
			if (vBuf[i] > 240) vBuf[i] = 240;
		}

d.调用yuv2rgb函数,使YUV转换为RGB:

YUV2RGB(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf)

e.将RGB数据存储进RGB文件:

	fwrite(rgbBuf, 1, frameWidth * frameHeight*3, rgbFile);


3.yuv2rgb.cpp是调用的YUV转换为RGB的函数:

a.对YUV进行上采用,恢复444格式:

	//上采样
	for (j = 0; j < y_dim / 2; j++)
	{
		
		psu = sub_u_buf + j*x_dim / 2;
		psv = sub_v_buf + j*x_dim / 2;
		pu1 = u_buffer + 2 * j*x_dim;
		pv1 = v_buffer + 2 * j*x_dim;
		pu2 = u_buffer + (2 * j + 1)*x_dim;
		pv2 = v_buffer + (2 * j + 1)*x_dim;
		for (i = 0; i < x_dim / 2; i++)
		{
			*pu1 = *psu;
			*(pu1 + 1) = *psu;
			*pu2 = *psu;
			*(pu2 + 1) = *psu;
			*pv1 = *psv;
			*(pv1 + 1) = *psv;
			*pv2 = *psv;
			*(pv2 + 1) = *psv;
			psu++;
			psv++;
			pu1 += 2;
			pu2 += 2;
			pv1 += 2;
			pv2 += 2;			
		}
	}

b.将YUV转换为RGB,因为RGB采用的unsiged char型,只有一字节,只能保存0~255之间的值,如果之间将转换过来的RGB值存入,可能会存在溢出的现象发生错误,所以要先用int型判断是否溢出,再重新赋给RGB指针:

for (i = 0; i < size ; i++)
	{
		aa = (int)((*y) + RGBYUV1779[*u]+0.5 );//b
		bb = (int)((*y) - RGBYUV03455[*u] - RGBYUV07169[*v]+0.5);//g
		cc = (int)((*y) + RGBYUV14075[*v]+0.5 );//r
		//char a = *(b + 1); char c = *(b + 2);

		if (aa>255)
			aa = 255;
		if (aa<0)
			aa = 0;
		if (bb>255)
			bb = 255;
		if (bb<0)
			bb = 0;
		if (cc>255)
			cc = 255;
		if (cc<0)
			cc = 0;
		

		*(b + 0) = (unsigned char) aa;
		*(b + 1) = (unsigned char) bb;
		*(b + 2) = (unsigned char) cc;
		

		b += 3;
		y++;
		u++;
		v++;
		
	}

c.对UV进行系数计算时,采用查表法可以提高运行速度,因为数组序号不能为负数,UV之前转换时为保证取值为正数,加上了128,所以要在计算时先减去128:

void InitLookupTable()
{
	int i;

	for (i = 0; i < 256; i++) RGBYUV14075[i] = (float)1.4075 * (i-128);
	for (i = 0; i < 256; i++) RGBYUV03455[i] = (float)0.3455 * (i-128);
	for (i = 0; i < 256; i++) RGBYUV1779[i] = (float)1.779 *( i-128);
	for (i = 0; i < 256; i++) RGBYUV07169[i] = (float)0.7169 * (i-128);

}

d.开辟的数组要在不需要时及时释放:

if (u_buffer)
		free(u_buffer);
	if (v_buffer)
		free(v_buffer);

4.yuv2rgb.h声明了要是有的函数:

int YUV2RGB(int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out);

void InitLookupTable();

四、实验结果及分析

第一组例子

左图是RGB文件转换为YUV文件查看后,右图是将YUV文件转为RGB,再转为YUV查看:

彩色空间转换(RGB与YUV格式文件转换)_第1张图片


以下三组例子

左图是YUV420素材,右图是将YUV文件转换为RGB,再转换为YUV的文件:


彩色空间转换(RGB与YUV格式文件转换)_第2张图片

彩色空间转换(RGB与YUV格式文件转换)_第3张图片

彩色空间转换(RGB与YUV格式文件转换)_第4张图片


转换之后的视频与原文件相同,说明实验正确。

五、结论

通过本次实验,熟悉了RGB、YUV420、YUV444的存储格式,熟悉了指针、数组以及文件的操作方式。在实验中应注意正确设置工作路径和实验参数。

你可能感兴趣的:(格式转换)