[20200326]第一次实验

第一次实验:彩色空间转换

实验目的

1.学会从计算和程序的角度分析问题
通过完成本实验,理解计算思维,即从问题出发,通过逐步分析和分解,把原问题转化
为可用程序方式解决的问题。在此过程中设计出一个解决方案。
2.进一步理解彩色空间的概念并掌握不同彩色空间转换的基本方程。
3.通过逐步设计程序,掌握编程细节:如查找表的设计,内存分配,对 U 和 V 信号进
行下采样,文件读写过程等。掌握程序调试的基本方法。

实验内容

掌握彩色空间转换的基本思想及转换公式
(1)RGB到YUV空间的转换
由电视原理可知,亮度和色差信号的构成如下:
Y=0.2990R+0.5870G+0.1140B
R-Y=0.7010R-0.5870G-0.1140B
B-Y=-0.2990R-0.5870G+0.8860B
为了使色差信号的动态范围控制在0.5之间,需要进行归一化,对色差信号引入压缩
系数。归一化后的色差信号为:
U=-0.1684 * R-0.3316*G+0.5 * B
V=0.5 * R-0.4187 * G-0.0813 * B

YUV到RGB空间的转换

R = Y + 1.4075 *(V-128)
G = Y – 0.3455 * (U –128) – 0.7169 * (V –128)
B = Y + 1.779 * (U – 128)

(2) 码电平分配及数字表达式

  • 亮电平信号量化后码电平分配

在对分量信号进行8比特均匀量化时,共分为256个等间隔的量化级。为了防止信号变动造成过载,在256级上端留20级,下端留16级作为信号超越动态范围的保护带。

  • 色差信号量化后码电平分配

色差信号经过归一化处理后,动态范围为-0.5-0.5,让色差零电平对应码电平128,色差信号总共占225个量化级。在256级上端留15级,下端留16级作为信号超越动态范围
的保护带。

(3)色度格式
4:2:0格式是指色差信号U,V的取样频率为亮度信号取样频率的四分之一,在水平方向和垂直方向上的取样点数均为Y的一半。

∴总结
实验第一部分
我们需要将给定RGB文件转换为YUV文件。
1.已知转换公式和电平分配,总结后得到具体计算方法如下:
Y=0.2990R+0.5870G+0.1140B
且Y>235时取235,<20时取20.
U=-0.1684 * R-0.3316*G+0.5 * B +128
V=0.5 * R-0.4187 * G-0.0813 * B+128
且U,V>240时取240,<20时取20.
2.计算U和V数值时需要注意,由于色差信号在水平和垂直方向的取样点数均为Y的一半,所以需要用上下左右的相邻四个像素点RGB值取平均值共同计算。
3.YUV值是按顺序存储。
YYYYYYYY
YYYYYYYY
UUUUVVVV
RGB是每个像素的RGB一起存储。
BGRBGRBGR……
因此在读写文件操作时要注意数组不要越界,读取数值要正确。
实验第二部分
我们需要将第一部分计算的YUV文件再转换回RGB文件。
1.已知转换公式和电平分配,总结后得到具体计算方法如下:
R = Y + 1.4075 *(V-128)
G = Y – 0.3455 * (U –128) – 0.7169 * (V –128)
B = Y + 1.779 * (U – 128)
2.计算时需要注意,由于色差信号在水平和垂直方向的取样点数均为Y的一半,所以一组U和V值对应的是上下左右相邻四个像素的RGB值,一起计算会简便一些。

代码如下。
第一部分:

#include<iostream>
#include<fstream>
#include<string>

using namespace std;

static double RGB2YUV02990[256],
RGB2YUV05870[256],
RGB2YUV01140[256],
RGB2YUV01684[256],
RGB2YUV03316[256],
RGB2YUV04187[256],
RGB2YUV00813[256],
RGB2YUV05000[256];

void initLookUpTable()
{	
	for (int i = 0;i < 256;i++)
	{
		RGB2YUV02990[i] = (double)i * 0.2990;
		RGB2YUV05870[i] = (double)i * 0.5870;
		RGB2YUV01140[i] = (double)i * 0.1140;
		RGB2YUV01684[i] = (double)i * 0.1684;
		RGB2YUV03316[i] = (double)i * 0.3316;
		RGB2YUV04187[i] = (double)i * 0.4187;
		RGB2YUV00813[i] = (double)i * 0.0813;
		RGB2YUV05000[i] = (double)i * 0.5;
	}
}

int main(int argc, char* argv[])
{
	FILE* rgbFile=NULL;
	FILE* yuvFile=NULL;

	//输入输出文件
	if(fopen_s(&rgbFile,"E:\\数据压缩\\20200322\\down.rgb", "rb")!=0)
	{
		cout << "Failed to open the RGB file!" << endl;
	}
	else
	{
		cout << "Successfully opened down.rgb!" << endl;
	}
	
	if ((fopen_s(&yuvFile, "E:\\数据压缩\\20200322\\down.yuv", "wb")) != 0)
	{
		cout << "Failed to write in the YUV file!" << endl;
	}
	else
	{
		cout << "Successfully written YUV!" << endl;
	}
	
	int width = 256;
	int height = 256;
	int size = 256 * 256;

	unsigned char* rgb_b = NULL;
	unsigned char* r_b = NULL;
	unsigned char* g_b = NULL;
	unsigned char* b_b = NULL;
	unsigned char* y_b = NULL;
	unsigned char* u_b = NULL;
	unsigned char* v_b = NULL;

	
	//创建动态数组
	rgb_b = (unsigned char*)malloc(sizeof(char) * size * 3);
	r_b = (unsigned char*)malloc(sizeof(char) * size);
	g_b = (unsigned char*)malloc(sizeof(char) * size);
	b_b = (unsigned char*)malloc(sizeof(char) * size);
	y_b = (unsigned char*)malloc(sizeof(char) * size);
	u_b = (unsigned char*)malloc(sizeof(char) * size / 4);
	v_b = (unsigned char*)malloc(sizeof(char) * size / 4);

	//读入数据
	fread(rgb_b, sizeof(unsigned char), size * 3, rgbFile);
	
	//把rgb文件的数据分别读到r g b三个数组中
	for (int i = 0; i < size; i++)
	{
		b_b[i] = rgb_b[3 * i];
		g_b[i] = rgb_b[3 * i + 1];
		r_b[i] = rgb_b[3 * i + 2];
	}

	//提前计算数据方便算yuv三个分量
	initLookUpTable();
	
	//计算y分量
	for (int i = 0; i < size; i++)
	{
		y_b[i] = RGB2YUV02990[r_b[i]] + RGB2YUV05870[g_b[i]] + RGB2YUV01140[b_b[i]];
		if (y_b[i] < 16)
		{
			y_b[i] = 16;
		}
		else if (y_b[i] > 235)
		{
			y_b[i] = 235;
		}
	}

	//计算uv分量
	int u = 0;
	int i = 0;
	while(i < size)
	{
		u_b[u] = 128 -(RGB2YUV01684[r_b[i]] + RGB2YUV01684[r_b[i + 1]] + RGB2YUV03316[r_b[i + width]] + RGB2YUV03316[r_b[i + width + 1]]) / 4 +
			-(RGB2YUV03316[g_b[i]] + RGB2YUV03316[g_b[i + 1]] + RGB2YUV03316[g_b[i + width]] + RGB2YUV03316[g_b[i + width + 1]]) / 4 +
			(RGB2YUV05000[b_b[i]] + RGB2YUV05000[b_b[i + 1]] + RGB2YUV05000[b_b[i + width]] + RGB2YUV05000[b_b[i + width + 1]]) / 4;

		v_b[u] = 128 -(RGB2YUV00813[b_b[i]] + RGB2YUV00813[b_b[i + 1]] + RGB2YUV00813[b_b[i + width]] + RGB2YUV00813[b_b[i + width + 1]]) / 4 +
			-(RGB2YUV04187[g_b[i]] + RGB2YUV04187[g_b[i + 1]] + RGB2YUV04187[g_b[i + width]] + RGB2YUV04187[g_b[i + width + 1]]) / 4 +
			(RGB2YUV05000[r_b[i]] + RGB2YUV05000[r_b[i + 1]] + RGB2YUV05000[r_b[i + width]] + RGB2YUV05000[r_b[i + width + 1]]) / 4;
		if (u_b[u] < 16)
		{
			u_b[u] = 16;
		}
		else if (u_b[u] > 240)
		{
			u_b[u] = 240;
		}

		if (v_b[u] < 16)
		{
			v_b[u] = 16;
		}
		else if (v_b[u] > 239)
		{
			v_b[u] = 239;
		}

		if (i % width == 254)
		{
			i = i + 258;
		}
		else
		{
			i = i + 2;
		}
		u++;
	}

	//写入yuv文件
	fwrite(y_b, sizeof(unsigned char), size, yuvFile);
	fwrite(u_b, sizeof(unsigned char), size/4, yuvFile);
	fwrite(v_b, sizeof(unsigned char), size/4, yuvFile);

	//释放buffer
	free(rgb_b);
	free(r_b);
	free(g_b);
	free(b_b);
	free(y_b);
	free(u_b);
	free(v_b);
	fclose(rgbFile);
	fclose(yuvFile);

	return 0;
}

第二部分

#include<iostream>
#include<fstream>
#include<math.h>
#include<string>
using namespace std;

static double YUV2RGB14075V[256],
	          YUV2RGB03455U[256],
			  YUV2RGB07169V[256],
			  YUV2RGB01779U[256];

/*void initLookUpTable()
{
	for (int i = 0;i < 256;i++)
	{
		YUV2RGB14075V[i] = (double)(i-128) * 1.4075;
		YUV2RGB03455U[i] = (double)(i - 128) * (-0.3455);
		YUV2RGB07169V[i] = (double)(i-128) * (-0.7169);
		YUV2RGB01779U[i] = (double)i * 1.1779;
	}
}*/

int main(void)
{
	FILE* yuvFile = NULL;
	FILE* rgbFile = NULL;

	//输入输出文件
	if (fopen_s(&yuvFile, "E:\\数据压缩\\20200322\\down.yuv", "rb") != 0)
	{
		cout << "Failed to open the YUV file!" << endl;
	}
	else
	{
		cout << "Successfully opened down.yuv!" << endl;
	}

	if ((fopen_s(&rgbFile, "E:\\数据压缩\\20200322\\downed.rgb", "wb")) != 0)
	{
		cout << "Failed to write in the RGB file!" << endl;
	}
	else
	{
		cout << "Successfully written downed.rgb!" << endl;
	}

	int width = 256;
	int height = 256;
	int size = 256 * 256;

	unsigned char* yuv_b = NULL;
	unsigned char* rgb_b = NULL;
	unsigned char* r_b = NULL;
	unsigned char* g_b = NULL;
	unsigned char* b_b = NULL;
	unsigned char* y_b = NULL;
	unsigned char* u_b = NULL;
	unsigned char* v_b = NULL;

	yuv_b = (unsigned char*)malloc(sizeof(char) * size * 1.5);
	rgb_b = (unsigned char*)malloc(sizeof(char) * size * 3);
	y_b = (unsigned char*)malloc(sizeof(char) * size);
	u_b = (unsigned char*)malloc(sizeof(char) * size / 4);
	v_b = (unsigned char*)malloc(sizeof(char) * size / 4);
	r_b = (unsigned char*)malloc(sizeof(char) * size);
	g_b = (unsigned char*)malloc(sizeof(char) * size);
	b_b = (unsigned char*)malloc(sizeof(char) * size);

	fread(yuv_b, sizeof(unsigned char), size * 1.5, yuvFile);

	/*for (int i = 0; i < size*1.5;i++)
	{
		cout << yuv_b[i] << ' ';
		if (i % 256 == 0) cout << endl;
	}*/

	int count = 0;
	for(int i = 0; i < size; i++)
	{
		y_b[i] = yuv_b[i];
		count++;
	}
	for (int i = 0; i < size / 4; i++)
	{
		u_b[i] = yuv_b[ count + i];
		count++;
	}
	for (int i = 0; i < size / 4; i++)
	{
		v_b[i] = yuv_b[ count + i];
		count++;
	}

	//initLookUpTable();

	//R = Y + 1.4075 *(V-128)
	//G = Y – 0.3455 * (U –128) – 0.7169 * (V –128)
	//B = Y + 1.779 * (U – 128)

	int rcount = 0;
	int i = 0;
	while(i<size)
	{
		r_b[i] = y_b[i] + 1.4075 * (v_b[rcount] - 128);               //YUV2RGB14075V[v_b[rcount]];
		r_b[i + 1] = y_b[i + 1] + 1.4075 * (v_b[rcount] - 128);           //YUV2RGB14075V[v_b[rcount]];
		r_b[i + width] = y_b[i + width] + 1.4075 * (v_b[rcount] - 128);    //YUV2RGB14075V[v_b[rcount]];
		r_b[i + width + 1] = y_b[i + width + 1] + 1.4075 * (v_b[rcount] - 128);      //YUV2RGB14075V[v_b[rcount]];
		if (i % width == 254)
		{
			i += 256;
		}
		else
		{
			i += 2;
		}
		rcount++;
	}

	int gcount = 0;
	i = 0;
	while(i<size/4)
	{
		g_b[i] = y_b[i] -0.3455 * (u_b[gcount] - 128) - 0.7169 * (v_b[gcount] - 128);//YUV2RGB03455U[u_b[gcount]] + YUV2RGB07169V[v_b[gcount]];
		g_b[i + 1] = y_b[i + 1] - 0.3455 * (u_b[gcount] - 128) - 0.7169 * (v_b[gcount] - 128);//YUV2RGB03455U[u_b[gcount]] + YUV2RGB07169V[v_b[gcount]];
		g_b[i + width] = y_b[i + width] + -0.3455 * (u_b[gcount] - 128) - 0.7169 * (v_b[gcount] - 128);//YUV2RGB03455U[u_b[gcount]] + YUV2RGB07169V[v_b[gcount]];
		g_b[i + width + 1] = y_b[i + width + 1] + -0.3455 * (u_b[gcount] - 128) - 0.7169 * (v_b[gcount] - 128);//YUV2RGB03455U[u_b[gcount]] + YUV2RGB07169V[v_b[gcount]];
		if (i % width == 254)
		{
			i += 256;
		}
		else
		{
			i += 2;
		}
		gcount++;
	}

	int bcount = 0;
	i = 0;
	while(i<size/4)
	{
		b_b[i] = y_b[i] + 1.779 * (u_b[bcount]-128);//YUV2RGB01779U[u_b[bcount]];
		b_b[i + 1] = y_b[i + 1] + 1.779 * (u_b[bcount]-128);//+ YUV2RGB01779U[u_b[bcount]];
		b_b[i + width] = y_b[i + width] + 1.779 * (u_b[bcount]-128);//+ YUV2RGB01779U[u_b[bcount]];
		b_b[i + width + 1] = y_b[i + width + 1] + 1.779 * (u_b[bcount]-128);//+ YUV2RGB01779U[u_b[bcount]];
		if (i % width == 254)
		{
			i += 256;
		}
		else
		{
			i += 2;
		}
		bcount++;
	}

	for (int i = 0; i < size; i++)
	{
		rgb_b[i * 3] = b_b[i];
		rgb_b[i * 3 + 1] = g_b[i];
		rgb_b[i * 3 + 2] = r_b[i];
	}
	
    fwrite(rgb_b, sizeof(unsigned char), size * 3, rgbFile);
	free(yuv_b);
	free(rgb_b);
	free(y_b);
	free(u_b);
	free(v_b);
	free(r_b);
	free(g_b);
	free(b_b);
	fclose(yuvFile);
	fclose(rgbFile);
	return 0;
}
错误反思

在调试程序时出现了多次堆栈溢出的报错,在程序多个地方加入输出语句以后及时改正了。以后再处理动态数组的问题时要多加注意

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值