实验报告 RGB2YUV&YUV2RGB

实验报告 RGB2YUV&YUV2RGB

1.编写RGB转化为YUV程序,重点掌握函数定义,部分查找表的初始化和调用,缓冲区
分配。将得到的RGB文件转换为YUV文件,用YUV Viewer播放器观看,验证是否正确。
2.编写将YUV转换为RGB的程序。将给定的实验数据用该程序转换为RGB文件。并与原
RGB文件进行比较,如果有误差,分析误差来自何处。

一、两种色彩空间的转换公式

两种色彩空间RGB和YUV的转换公式可有亮度方程直接推导,亮度方程如下:
Y = 0.2990 R + 0.5870 G + 0.1140 B Y = 0.2990R + 0.5870G + 0.1140B Y=0.2990R+0.5870G+0.1140B
色差信号可直接用相应的基色与亮度作差得到
B − Y = − 0.2990 R − 0.5870 G + 0.8860 B B - Y = - 0.2990R - 0.5870G + 0.8860B BY=0.2990R0.5870G+0.8860B
R − Y = 0.7010 R − 0.5870 G + 0.1140 B R - Y = 0.7010R - 0.5870G + 0.1140B RY=0.7010R0.5870G+0.1140B
在实际应用中,我们要将色差信号的动态范围设置为-0.5~0.5之间,因此我们要将上述色差信号系数的最大值映射到0.5,得到的色差信号记为U V
U = − 0.1684 R − 0.3316 G + 0.5 B {U = - 0.1684R - 0.3316G + 0.5B} U=0.1684R0.3316G+0.5B
V = 0.5 R − 0.4187 G − 0.0813 B {V = 0.5R - 0.4187G - 0.0813B} V=0.5R0.4187G0.0813B
在存储时,我们要将色差信号的零电平对应到128。

综上,可得到由RGB色彩空间转换到YUV色彩空间的表达式,
{ Y = 0.299 R + 0.5870 G + 0.1140 B U = − 0.1684 R − 0.3316 G + 0.5 B + 128 V = 0.5 R − 0.4187 G − 0.0813 B + 128 \left\{ {\begin{array}{l} {Y = 0.299R + 0.5870G + 0.1140B}\\ {U = - 0.1684R - 0.3316G + 0.5B + 128}\\ {V = 0.5R - 0.4187G - 0.0813B + 128} \end{array}} \right. Y=0.299R+0.5870G+0.1140BU=0.1684R0.3316G+0.5B+128V=0.5R0.4187G0.0813B+128
为了得到由YUV色彩空间转换到RGB色彩空间的表达式,我们只需将上式的系数提取出来,组成3*3的系数矩阵,求其逆矩阵,即可得到YUV2RGB的转换式系数
{ R = 1.000 Y + 1.4020 ( V − 128 ) G = 1.000 Y − 0.3441 ( U − 128 ) − 0.7139 ( V − 128 ) B = 1.000 Y + 1.7718 ( U − 128 ) − 0.0013 ( V − 128 ) \left\{ {\begin{array}{l} {R = 1.000Y + 1.4020\left( {V - 128} \right)}\\ {G = 1.000Y - 0.3441\left( {U - 128} \right) - 0.7139\left( {V - 128} \right)}\\ {B = 1.000Y + 1.7718\left( {U - 128} \right) - 0.0013\left( {V - 128} \right)} \end{array}} \right. R=1.000Y+1.4020(V128)G=1.000Y0.3441(U128)0.7139(V128)B=1.000Y+1.7718(U128)0.0013(V128)

二、具体代码和实现成果

1.rgb2yuv

#include<stdio.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
	constexpr auto wid = 256;
	constexpr auto hei = 256;
//point
	FILE *p_rgb;
	FILE *p_yuv;
//fopen
	if (fopen_s(&p_rgb, argv[1], "rb") != 0)
	{
		printf("打开down.rgb失败!\n");
	}
	if (fopen_s(&p_yuv, argv[2], "wb") != 0)
	{
		printf("打开down.yuv失败!\n");
	}
//buffer
	unsigned char* b_rgb = (unsigned char*)malloc(sizeof(unsigned char) * 3 * wid * hei);
	unsigned char* b_y = (unsigned char*)malloc(sizeof(unsigned char) * wid * hei);
	unsigned char* b_u = (unsigned char*)malloc(sizeof(unsigned char) * wid * hei / 4);
	unsigned char* b_v = (unsigned char*)malloc(sizeof(unsigned char) * wid * hei / 4);
//fread
	fread(b_rgb, sizeof(unsigned char), 3 * wid * hei, p_rgb);
//measure
//计算y
    for (int i = 0; i < wid * hei; i++)
    {
        b_y[i] = 0.299 * b_rgb[3 * i + 2] + 0.587 * b_rgb[3 * i + 1] + 0.114 * b_rgb[3 * i];
		if (b_y[i] > 235)
			b_y[i] = 235;
		if(b_y[i]<16)
			b_y[i] = 16;
    }
//计算u
	int k = 0;
	for(int i=0;i<hei;i++)
		for (int j = 0; j < wid; j++)
		{
			if (i % 2 == 0 && j % 2 == 0)
			{
				b_u[k]= -0.1684 * b_rgb[3 * (i*wid+j) + 2] - 0.3316 * b_rgb[3 * (i*wid+j) + 1] 
					+ 0.5 * b_rgb[3 * (i*wid+j)]+128;
				if (b_u[k] < 16)
					b_u[k] = 16;
				if (b_u[k] > 240)
					b_u[k] = 240;
				k++;
			}
		}
//计算v
	k = 0;
	for (int i = 0; i < hei; i++)
		for (int j = 0; j < wid; j++)
		{
			if (i % 2 == 0 && j % 2 == 0)
			{
				b_v[k] = 0.5 * b_rgb[3 * (i * wid + j) + 2] - 0.4187 * b_rgb[3 * (i * wid + j) + 1]
					- 0.0183 * b_rgb[3 * (i * wid + j)]+128;
				if (b_v[k] < 16)
					b_v[k] = 16;
				if (b_v[k] > 240)
					b_v[k] = 240;
				k++;
			}
		}
//fwrite
	fwrite(b_y, sizeof(unsigned char), wid*hei, p_yuv);
	fwrite(b_u, sizeof(unsigned char), wid * hei / 4, p_yuv);
	fwrite(b_v, sizeof(unsigned char), wid * hei / 4, p_yuv);
//free
	free(b_rgb);
	free(b_y);
	free(b_u);
	free(b_v);
//fclose
	fclose(p_rgb);
	fclose(p_yuv);
	return 0;
}

得到的yuv文件用YUV播放器观看
在这里插入图片描述
可以看到得到的yuv文件与原rgb文件图片几乎一致。

2.rgb2yuv

#include<stdio.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{
	constexpr auto wid = 256;
	constexpr auto hei = 256;
	//point
	FILE* p_rgb;
	FILE* p_yuv;
	//fopen
	if (fopen_s(&p_rgb, argv[1], "wb") != 0)
	{
		printf("打开down.rgb失败!\n");
	}
	if (fopen_s(&p_yuv, argv[2], "rb") != 0)
	{
		printf("打开down.yuv失败!\n");
	}
	//buffer
	unsigned char* b_rgb = (unsigned char*)malloc(sizeof(unsigned char) * 3 * wid * hei);
	unsigned char* b_y = (unsigned char*)malloc(sizeof(unsigned char) * wid * hei);
	unsigned char* b_u = (unsigned char*)malloc(sizeof(unsigned char) * wid * hei / 4);
	unsigned char* b_v = (unsigned char*)malloc(sizeof(unsigned char) * wid * hei / 4);
	//fread
	fread(b_y, sizeof(unsigned char), wid * hei, p_yuv);
	fread(b_u, sizeof(unsigned char), wid * hei / 4, p_yuv);
	fread(b_v, sizeof(unsigned char), wid * hei / 4, p_yuv);
	//measure
	//处理y
	unsigned char y[wid][hei] = { 0 };
	for (int i = 0; i < hei; i++)
		for (int j = 0; j < wid; j++)
		{
			y[i][j] = b_y[(i * wid + j)];
		}
	//处理uv
	unsigned char u[wid][hei] = { 0 };
	unsigned char v[wid][hei] = { 0 };
	int k = 0;
	for (int i = 0; i < hei; i++)
		for (int j = 0; j < wid; j++)
		{
			if (i % 2 == 0 && j % 2 == 0)
			{
				u[i][j] = b_u[k];
				v[i][j] = b_v[k];
				k++;
			}
			else if (i % 2 == 0 && j % 2 == 1)
			{
				u[i][j] = u[i][j - 1];
				v[i][j] = v[i][j - 1];
			}
			else if (i % 2 == 1 && j % 2 == 0)
			{
				u[i][j] = u[i - 1][j];
				v[i][j] = v[i - 1][j];
			}
			else if (i % 2 == 1 && j % 2 == 1)
			{
				u[i][j] = u[i - 1][j - 1];
				v[i][j] = v[i - 1][j - 1];
			}
		}
	//计算bgr
	for (int i = 0; i < hei; i++)
		for (int j = 0; j < wid; j++)
		{
			b_rgb[3*(i*wid+j)] = y[i][j] + 1.7718 * (u[i][j] - 128) - 0.0013 * (v[i][j] - 128); //b
			b_rgb[3*(i*wid+j) + 1] = y[i][j] - 0.3441 * (u[i][j] - 128) - 0.7139 * (v[i][j] - 128); //g
			b_rgb[3*(i*wid+j) + 2] = y[i][j] + 1.4020 * (v[i][j] - 128); ; //r
		}
	//fwrite
	fwrite(b_rgb, sizeof(unsigned char), 3*wid * hei, p_rgb);
	//free
	free(b_rgb);
	free(b_y);
	free(b_u);
	free(b_v);
	//fclose
	fclose(p_rgb);
	fclose(p_yuv);
	return 0;
}

得到的rgb文件用matlab预览

在这里插入图片描述
可以发现rgb文件和初始图片大致相同,但是会存在一些红色和蓝色的坏点,对此,我们用matlab定点考察,会发现造成坏点的原因是数据溢出,一些原本为0的数值变为255了
在这里插入图片描述
误差原因有下:
i.运算中涉及unchar和double之间的转换,容易发生最终结果为0的数值计算为255,254.
ii.由于UV值使用4:2:0的方式采样,一部分像素UV值并不是尤其原本的RGB值计算而来,这样使用自身的Y值和非自身的UV值还原RGB,可能带来微小的误差,使数据溢出。
改进方法:
在这幅自然景物图片中,没有纯色调颜色的像素,可以使RB值大于240的像素将为10,达到无技巧修正的目的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值