使用C++实现YUV格式图像与RGB格式图像之间相互转换

一、RGB与YUV转换公式

1、RGB转YUV

1)RGB转换亮度与色差信号公试:

Y=0.299R+0.587G+0.114B
R-Y=0.701R-0.587G-0.114B
B-Y=-0.299R-0.587G+0.866B

2)归一化为YUV的转化公试为:

Y=0.299R+0.587G+0.114B
U=-0.168R-0.332G+0.5B
V=0.5R-0.419G-0.081B

2、YUV转RGB

根据RGB转YUV转换公式,我们可以计算出YUV转化为RGB的公试:
R=Y+1.40 (V-28)
G=Y-0.344 (U-128)-0.714(V-128)
B=Y+1.772*(U-128)

二、利用命令参数实现读取文件的简单化安全化

通过选择“项目”-“yuv2rgb属性”进入yuv2rgb属性页
在这里插入图片描述
在这里插入图片描述
在属性页中选择“配置属性”-“调试”进入调试器界面
在这里插入图片描述
在命令参数中按顺序依次输入值(文件名称、参数等)并以“ ”(空格)隔开,这些值会依次排放在argv[1]-argv[n]之中,需要调用的时候直接赋值即可:

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

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

并在工作目录选择文件所在位置即可并通过已下代码即可使文件读取更加安全,文件路径不会再在代码中展现:

	yuvFile = fopen(yuvFileName, "rb");
	rgbFile = fopen(rgbFileName, "wb");

三、使用C++实现YUV格式图像转换为RGB格式图像

实现这一共功能一共分为三个部分,主体实现(main1.cpp),yuv到rgb的转换(yuv2rgb.cpp),yuv到rgb的头文件(yuv2rgb.h);
其中最为重要的是yuv到rgb转换功能的实现,即yuv2rgb.cpp,因此下面我先简述yuv2rgb.cpp的具体实验过程

(一)、YUV格式到RGB格式的转换(yuv2rgb.cpp)

1、实现YUV转RGB公式

因为图像大小为256*256,若在转换时对每个像素以此进行转换公式的计算,则计算量过大,所以可以先建立一个转换公式,计算0-255像数值的转换,并将其存在数组中,这样在后续的使用中可以直接调用其对应的值不用再一一计算,大大提高了程序运行效率。根据转换公试,具体实现如下:

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++) RGBYUV07169[i] = (float)0.7169 * (i - 128);
	for (i = 0; i < 256; i++) RGBYUV17790[i] = (float)1.7790 * (i - 128);

}

2、图像数据的读入

因为YUV格式图像分辨率为256* 256,所以Y分配空间为256* 256,U、V分配空间为256*256/4:

	y_buffer = (unsigned char*)malloc(size* sizeof(unsigned char));
	u_buffer = (unsigned char*)malloc(size* sizeof(unsigned char) / 4);
	v_buffer = (unsigned char*)malloc(size* sizeof(unsigned char) / 4);
	sub_u_buf = (unsigned char*)malloc(size* sizeof(unsigned char));
	sub_v_buf = (unsigned char*)malloc(size* sizeof(unsigned char));
	yuv_buffer = (unsigned char*)bmp;
	y = y_buffer;
	u = u_buffer;
	v = v_buffer;

其中y_buffer、u_buffer、v_buffer为存放Y、U、V数据的指针,y,u,v为读入数据的中间过渡传递指针;
因为RGB格式图像的R、G、B分量都为256256大小,所以需要将,原本为256256/4的U、V分量扩大以此才方便计算,所以设置sub_u_buf、sub_v_buf两个为256*256大小的指针以此来进行扩充存放。
因为YUV格式图像为按照全部像素Y数据块、U数据块、V数据块依次存放,且为4:2:0采样,所以读取方式为YYYY…,U…,V…:

for (i = 0; i < size; i ++) 
	{
   
		*y = *(yuv_buffer + i);
		y++;
	}

	for (i = size; i < size * 5 / 4; i++) 
	{
   
		*u = *(yuv_buffer + i);
		u++;
	}
	for (i = size * 5 / 4; i < size * 3 / 2; i ++) 
	{
   
		*v = *(yuv_buffer + i);
		v++;
	}

3、将U、V分量扩充到256*256

因为RGB格式图像的R、G、B分量都为256256大小,所以需要将原本为256256/4的U、V分量扩大以此才方便计算,这里设置sub_u_buf、sub_v_buf两个为256*256大小的指针以此来进行扩充存放。
我选用将U、V的值直接分配给他最近邻的4个值的方法(如图所示,将原本左上角位置的a直接赋值给其正下方,右方,与右下方三个值

a a
a a

)以此来实现对U、V分量的扩充。具体实现如下:

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

		}
	}

4、将YUV转化为RGB

因为所用的读图工具(gbmp)为倒着读图中的数据,所以需要设计两种方式的转化,来实现正数据存放与倒数据存放;
并且因为在上面公式数组中计算存放的数值为“float”型,而传入图像所需的数据是“unsigned char”型,所以将“float”型数据强制转换为“unsigned char”是可能会出现数据溢出(通过转换公式得到的R、G、B分量值可能得到负值或大于255的值)所以需要将溢出的值规定为不溢出的值,我将负值=0,大于255的值=255。这样既可解决数值溢出问题,所以需要另设“float”类型参数sub_r、sub_g、sub_b来作为中间参数;
具体实现方法如下:

if (flip)
	{
   

		for (i = 0; i < size; i++)
		{
   
			sub_r = *(y_buffer+i) + RGBYUV14075[*(sub_v_buf+i)];
			sub_g = *(y_buffer+i) - RGBYUV03455[*(sub_u_buf+i)] - RGBYUV07169[*(sub_v_buf+i)];
			sub_b = *(y_buffer+i) + RGBYUV17790[*(sub_u_buf+i)];
		
			if (sub_r < 0) sub_r = 0;
			if (sub_r > 255) sub_r = 255;

			if (sub_g < 0) sub_g = 0;
			if (sub_g > 255) sub_g = 255;

			if (sub_b < 0) sub_b = 0;
			if (sub_b > 255) sub_b = 255;
		
			*r = (unsigned char)sub_r;
			*g = (unsigned char)sub_g;
			*b = (unsigned char)sub_b;
			r++;
			g++;
			b++;
		}
	}
	else {
   
		for (j = 0; j < y_dim; j++) 
		{
   
			psy = y_buffer + (y_dim - 1 - j) * x_dim;
			psu = sub_u_buf + (y_dim - 1 - j) * x_dim;
			psv = sub_v_buf+ (y_dim - 1 - j) * x_dim;
			
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值