数据压缩作业-彩色空间转换

实验目的:
1学会从计算和程序的角度分析问题
2进一步理解彩色空间的概念并掌握不同彩色空间转换的基本方程
3通过逐步设计程序,掌握编程细节
实验内容:
(1)RGB转YUV
首先根据公式有
Y=0.299R+0.587G+0.114B
U=-0.1687
R-0.3313G+0.5B
V=0.5R-0.4187G-0.0813B
其中色差信号经过归一化处理范围在-0.5~0.5之间,可能是负数。因此在U、V公式上加128使得色差信号零电平对应码电平128。
则公式变换为
Y=0.299
R+0.587G+0.114B
U=-0.1687R-0.3313G+0.5B+128
V=0.5
R-0.4187G-0.0813B+128
YUV信号进行8bit均匀量化,分为256个等间隔量化级。为了防止信号变动产生过载,在256级上端留20级,下端留16级作为超越动态范围保护带。即若码电平小于16就置码电平为16,大于235就置于235。
将RGB图像转为4:2:0格式YUV图像
在这里插入图片描述
如上图所示,将四个样点的R、G、B值取平均计算公式。(上图公式找了许久。。。)j值为i值每128加一。
代码如下:

#include <iostream>
#include<fstream>
using namespace  std;

#pragma warning(disable:4996);//这个声明可以使用fopen不报错
#define h 256
#define w 256

int main()
{
	ifstream fp;
	FILE* fp_changed;//生成的yuv文件
	fp.open("down.rgb", ios::in | ios::binary);//打开down.rgb文件
	if (!fp)
	{
		cout << "down.rgb open failed" << endl;
		return 0;
	}
	fp_changed = fopen("down.yuv", "wb+");//先打开yuv文件

	unsigned char* Y_buffer;
	unsigned char* U_buffer;
	unsigned char* V_buffer;

	Y_buffer = (unsigned char*)malloc(w * h);
	U_buffer = (unsigned char*)malloc(w * h / 4);
	V_buffer = (unsigned char*)malloc(w * h / 4);

	unsigned char r[w * h];
	unsigned char g[w * h];
	unsigned char b[w * h];
	for (int i = 0; i < w * h; i++)
	{
		fp.read((char*)(b + i), sizeof(unsigned char));//直接从rgb图像中读取r、g、b
		fp.read((char*)(g + i), sizeof(unsigned char));
		fp.read((char*)(r + i), sizeof(unsigned char));
	}

	int j = -1;

	for(int i=0;i<w * h;i++)
	{
		Y_buffer[i] = 0.299 * r[i] + 0.587 * g[i] + 0.114 * b[i];
		if (Y_buffer[i] < 16)
			Y_buffer[i] = 16;
		if (Y_buffer[i] > 235)
			Y_buffer[i] = 235;
	}
	for (int i = 0; i < w * h / 4; i++)
	{
		if (i % 128 == 0)
			j++;
		U_buffer[i] = -0.1687 * ((r[2 * i + j * w] + r[2 * i + 1 + j * w] + r[2 * i + (j + 1) * w] + r[2 * 1 + 1 + (j + 1) * w]) / 4)
			- 0.3313 * ((g[2 * i + j * w] + g[2 * i + 1 + j * w] + g[2 * i + (j + 1) * w] + g[2 * 1 + 1 + (j + 1) * w]) / 4)
			+ 0.5 * ((b[2 * i + j * w] + b[2 * i + 1 + j * w] + b[2 * i + (j + 1) * w] + b[2 * 1 + 1 + (j + 1) * w]) / 4) + 128;
		if (U_buffer[i] < 16)
			U_buffer[i] = 16;
		if (U_buffer[i] > 235)
			U_buffer[i] = 235;
	}
	j = -1;
	for (int i = 0; i < w * h / 4; i++)
	{
		if (i % 128 == 0)
			j++;
		V_buffer[i] = 0.5 * ((r[2 * i + j * w] + r[2 * i + 1 + j * w] + r[2 * i + (j + 1) * w] + r[2 * 1 + 1 + (j + 1) * w]) / 4)
			- 0.4187 * ((g[2 * i + j * w] + g[2 * i + 1 + j * w] + g[2 * i + (j + 1) * w] + g[2 * 1 + 1 + (j + 1) * w]) / 4)
			-0.0813 * ((b[2 * i + j * w] + b[2 * i + 1 + j * w] + b[2 * i + (j + 1) * w] + b[2 * 1 + 1 + (j + 1) * w]) / 4) + 128;
		if (V_buffer[i] < 16)
			V_buffer[i] = 16;
		if (V_buffer[i] > 235)
			V_buffer[i] = 235;
	}

	fwrite(Y_buffer, 1, w * h , fp_changed);//将YUV数值写入yuv图像
	fwrite(U_buffer, 1, w * h / 4, fp_changed);
	fwrite(V_buffer, 1, w * h / 4, fp_changed);

	fp.close();//释放缓冲区
	fclose(fp_changed);
	free(Y_buffer);
	free(U_buffer);
	free(V_buffer);
	return 0;
}


yuv图像生成:在这里插入图片描述
原图:在这里插入图片描述
两张图片看不出什么区别。
(2)YUV转RGB
公式:R=Y+1.402*(V-128)
G=Y-0.3441*(U-128)-0.7139*(V-128)
B=Y+1.7718*(U-128)-0.0013*(V-128)
注意bmp格式图片是bgr次序写入。
结果是倒过来的,通过旋转镜像得到第一次结果:在这里插入图片描述
可以看到有红点。分析是因为unsigned char型RGB数据超出了0~255的范围,于是加了几行代码:

for (int i = 0; i < w * h; i++)
	{
		if (R_buffer[i] < 0)
			R_buffer[i] = 0;
		if (R_buffer[i] > 255)
			R_buffer[i] = 255;
		if (G_buffer[i] < 0)
			G_buffer[i] = 0;
		if (G_buffer[i] > 255)
			G_buffer[i] = 255;
		if (B_buffer[i] < 0)
			B_buffer[i] = 0;
		if (B_buffer[i] > 255)
			B_buffer[i] = 255;
	}

但是,结果依旧有红点。
在这里插入图片描述

下面是YUV转RGB代码:

#include<iostream>
#include<fstream>
using namespace std;

#pragma warning(disable:4996);
#define h 256
#define w 256
int main()
{
	FILE* yuv;
	FILE* rgb;
	yuv = fopen("down.yuv", "rb+");
	if (!yuv)
		cout << "open failed" << endl;
	else
		cout << "open successed" << endl;
		
	rgb = fopen("down.rgb", "wb+");

	unsigned char* R_buffer;
	unsigned char* G_buffer;
	unsigned char* B_buffer;
	unsigned char* YUV_buffer;

	YUV_buffer = (unsigned char*)malloc(w * h * 3 / 2);
	R_buffer = (unsigned char*)malloc(w * h);
	G_buffer = (unsigned char*)malloc(w * h);
	B_buffer = (unsigned char*)malloc(w * h);

	unsigned char Y[w * h];
	unsigned char U[w * h / 4];
	unsigned char V[w * h / 4];

	fread(YUV_buffer, sizeof(unsigned char), w * h * 3 / 2, yuv);
	for (int i = 0; i < w * h; i++)
		Y[i] = YUV_buffer[i];
	for (int i = 0; i < w * h / 4; i++)
	{
		U[i] = YUV_buffer[i + w * h];
		V[i] = YUV_buffer[i + w * h * 5 / 4];
	}
	int j = -1;
	for (int i = 0; i < w * h - w; i++)
	{
		if (i % 2 == 0)
			j++;
		if (i != 0 && i % 256 == 0)
			i = i + w;
		R_buffer[i] = Y[i] + 1.4020 * (V[j] - 128);
		R_buffer[i + w] = Y[i + w] + 1.4020 * (V[j] - 128);
		G_buffer[i] = Y[i] - 0.3441 * (U[j] - 128) - 0.7139 * (V[j] - 128);
		G_buffer[i + w] = Y[i + w] - 0.3441 * (U[j] - 128) - 0.7139 * (V[j] - 128);
		B_buffer[i] = Y[i] + 1.7718 * (U[j] - 128) - 0.0013 * (V[i] - 128);
		B_buffer[i + w] = Y[i + w] + 1.779 * (U[j] - 128) - 0.0013 * (V[i] - 128);
	}
	for (int i = 0; i < w * h; i++)
	{
		if (R_buffer[i] < 0)
			R_buffer[i] = 0;
		if (R_buffer[i] > 255)
			R_buffer[i] = 255;
		if (G_buffer[i] < 0)
			G_buffer[i] = 0;
		if (G_buffer[i] > 255)
			G_buffer[i] = 255;
		if (B_buffer[i] < 0)
			B_buffer[i] = 0;
		if (B_buffer[i] > 255)
			B_buffer[i] = 255;
	}
	for (int i = 0; i < w * h; i++)
	{
		fwrite((B_buffer+i), 1, 1, rgb);
		fwrite((G_buffer+i), 1, 1, rgb);
		fwrite((R_buffer+i), 1, 1, rgb);
	}	

	fclose(yuv);
	fclose(rgb);
	free(R_buffer);
	free(G_buffer);
	free(B_buffer);
	free(YUV_buffer);
	return 0;
}


判断误差不是来源于数据溢出。
因此猜测误差还可能来源于:
1.RGB转YUV以及YUV转RGB公式本身就有误差
2.rgb格式转化为4:2:0yuv格式时,舍去了色差信号,后yuv格式转rgb格式又是四个点公用一个色差信号,产生误差
3.代码有些直接从double转为unsigned char可能会使数据丢失产生误差

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值