【实验一】彩色空间转换


1.rgb空间与yuv空间对应关系:

根据电视原理相关知识可知RGB与的YUV对应关系为:
Y=0.299R +0.587G+0.114B
U=-0.1684R-0.3316G+0.5B
V=0.5R-0.4187G-0.0813B
为了使色差信号的动态范围控制在[-0.5, 0.5],需要进行量化前的归一化处理,需要引入数字色差信号的压缩系数(分别为0.564与0.713)。

2.量化电平的分配

参考《现代电视原理》“视频信号量化电平的分配”部分:

在进行8 bit量化时,需要在上下两端留出一定的余量,作为信号超越动态范围的保护带。具体地:

对于亮度信号,在256级的上端留出20级,下端留出16级作为余量,即Y的动态范围为16—235;
对于两个色差信号,在256级的上端留出15级,下端留出16级作为余量,即U、V的动态范围为16—240。

3.利用RGB转YUV的转换公式,整理得到:

R’=1.1686Y+1.16118V-224.8784
G’=1.1686Y-0.3961U-0.8274V+136.2314
B’=1.1686Y+2.0353U-278.8902

4.main函数的参数

main函数具有两个形参,int argc和char* argv[]。在涉及文件的操作中,使用命令行参数可以为编程提供一定的便利。如下图:在这里插入图片描述

5.查找表的使用

使用查找表法,使用存储空间换运算时间。

(1)RGB转YUV

void InitLookupTable()
{
	int i;

	for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
	for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
	for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
	for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
	for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
	for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
	for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
}

(1)YUV转RGB

void yuvLookupTable()
{
	for (int i = 0; i < 256; i++)
	{
		yuv11686[i] = 1.1686 * i;
		yuv16118[i] = 1.6118 * i;
		yuv03961[i] = 0.3961 * i;
		yuv08274[i] = 0.8274 * i;
		yuv20353[i] = 2.0353 * i;

	}
}

6.代码部分

(1)main.cpp

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "rgb2yuv.h"
#include "yuv2rgb.h"
#include <iostream>

using namespace std;

#define u_int8_t	unsigned __int8
#define u_int		unsigned __int32
#define u_int32_t	unsigned __int32
#define FALSE		false
#define TRUE		true
int main(int argc, char** argv)
{
	/* variables controlable from command line */
	u_int frameWidth = 352;			/* --width=<uint> */
	u_int frameHeight = 240;		/* --height=<uint> */
	bool flip = TRUE;				/* --flip */
	unsigned int i;

	/* internal variables */
	char* rgbFileName = NULL;
	char* yuvFileName = NULL;
	
	char* rgbFileName1 = NULL;
	char* yuvFileName1 = NULL;


	FILE* rgbFile = NULL;
	FILE* yuvFile = NULL;

	FILE* rgbFile1 = NULL;
	FILE* yuvFile1 = NULL;
	u_int8_t* rgbBuf = NULL;
	u_int8_t* rgbBuf1 = NULL;
	u_int8_t* yuvBuf = NULL;
	u_int8_t* yBuf = NULL;
	u_int8_t* uBuf = NULL;
	u_int8_t* vBuf = NULL;

	u_int32_t videoFramesWritten = 0;

	/* begin process command line */
	/* point to the specified file names */
	rgbFileName = argv[1];
	yuvFileName = argv[2];

	rgbFileName1 = argv[6];
	yuvFileName1 = argv[5];
	cout << rgbFileName1 << endl;
	cout << yuvFileName1 << endl;
	frameWidth = atoi(argv[3]);
	frameHeight = atoi(argv[4]);
	
	/* open the RGB file */
	if (fopen_s(&rgbFile, rgbFileName, "rb")==0)
	{
		printf("The input rgb file is %s\n", rgbFileName);
	}
	else
	{
		cout << rgbFileName<<endl;
		printf("cannot find rgb file\n");
		exit(0);
	}

	/* open the RAW file */
	if (fopen_s(&yuvFile, yuvFileName, "wb") == 0)
	{
		
		printf("The output yuv file is %s\n", yuvFileName);
	
	}
	else
	{
		printf("cannot find yuv file\n");
		exit(0);
	}

	if (fopen_s(&rgbFile1, rgbFileName1, "wb") == 0)
	{
		//printf("The input rgb file is %s\n", rgbFileName1);
	}
	else
	{
		cout << rgbFileName1 << endl;
		printf("cannot find rgb file\n");
		exit(0);
	}

	/* open the RAW file */
	if (fopen_s(&yuvFile1, yuvFileName1, "rb") == 0)
	{

		//printf("The output yuv file is %s\n", yuvFileName1);

	}
	else
	{
		printf("cannot find yuv file\n");
		exit(0);
	}

	/* get an input buffer for a frame */
	rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3);
	yuvBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3 / 2);
	rgbBuf1 = (u_int8_t*)malloc(frameWidth * frameHeight * 3);

	/* get the output buffers 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);
	unsigned char* yBuffer = NULL;		// Y分量缓冲区
	unsigned char* uBuffer = NULL;		// U分量缓冲区
	unsigned char* vBuffer = NULL;		// V分量缓冲区
	unsigned char* rgbRecBuffer = NULL;	// 复原RGB图像缓冲区

	if (rgbBuf == NULL || yBuf == NULL || uBuf == NULL || vBuf == NULL)
	{
		printf("no enought memory\n");
		exit(1);
	}

	while (fread(rgbBuf, 1, frameWidth * frameHeight * 3, rgbFile)) 
	{
		if(RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, flip))
		{
			printf("error");
			return 0;
		}

		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;
		}

		fwrite(yBuf, 1, frameWidth * frameHeight, yuvFile);
		fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
		fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);

		printf("\r...%d", ++videoFramesWritten);
	}

	yBuffer = new unsigned char[frameWidth* frameHeight];
	uBuffer = new unsigned char[frameWidth * frameHeight / 4];		// 4:2:0格式
	vBuffer = new unsigned char[frameWidth * frameHeight / 4];
	rgbRecBuffer = new unsigned char[frameWidth * frameHeight * 3];

	fread(yBuffer,sizeof(unsigned char), frameWidth* frameHeight , yuvFile1);
	fread(uBuffer, sizeof(unsigned char), frameWidth * frameHeight / 4, yuvFile1);
	fread(vBuffer, sizeof(unsigned char), frameWidth * frameHeight / 4, yuvFile1);
	
	
	yuv2rgb(rgbFile1, 256*256*3/2, frameWidth, frameHeight, yBuffer, uBuffer, vBuffer, rgbRecBuffer);
	cout << "win" << endl;
	delete[]yBuffer;
	delete[]uBuffer;
	delete[]vBuffer;
	delete[]rgbRecBuffer;
	

	printf("\n%u %ux%u video frames written\n", 
		videoFramesWritten, frameWidth, frameHeight);

	/* cleanup */

	fclose(rgbFile);
	fclose(yuvFile);
	fclose(rgbFile1);
	fclose(yuvFile1);
	return(0);
}

(2)rgb2yuv.h

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

void InitLookupTable();

(3)yuv2rgb.h

void yuv2rgb(FILE* rgbFile, int yuvSize, int w, int h, unsigned char* yBuf, unsigned char* uBuf, unsigned char* vBuf, unsigned char* rgbBuf);

(4)yuv2rgb.cpp

#include <iostream>
using namespace std;

double yuv11686[256], yuv16118[256];
double yuv03961[256], yuv08274[256];
double yuv20353[256];


void yuvLookupTable()
{
	for (int i = 0; i < 256; i++)
	{
		yuv11686[i] = 1.1686 * i;
		yuv16118[i] = 1.6118 * i;
		yuv03961[i] = 0.3961 * i;
		yuv08274[i] = 0.8274 * i;
		yuv20353[i] = 2.0353 * i;

	}
}

void yuv2rgb(FILE* rgbFile, int yuvSize, int w, int h, unsigned char* yBuf, unsigned char* uBuf, unsigned char* vBuf, unsigned char* rgbBuf)
{
	unsigned char* uBuf444 = new unsigned char[yuvSize * 2 / 3];	// 还原成4:4:4的U分量缓冲区
	unsigned char* vBuf444 = new unsigned char[yuvSize * 2 / 3];	// 还原成4:4:4的V分量缓冲区

	// 4:2:0 to 4:4:4
	for (int i = 0; i < h / 2; i++)
	{
		for (int j = 0; j < w / 2; j++)	
		{
			uBuf444[2 * i * w + 2 * j] = uBuf[i * w / 2 + j];
			uBuf444[2 * i * w + 2 * j + 1] = uBuf[i * w / 2 + j];
			uBuf444[2 * i * w + 2 * j + w] = uBuf[i * w / 2 + j];
			uBuf444[2 * i * w + 2 * j + w + 1] = uBuf[i * w / 2 + j];

			vBuf444[2 * i * w + 2 * j] = vBuf[i * w / 2 + j];
			vBuf444[2 * i * w + 2 * j + 1] = vBuf[i * w / 2 + j];
			vBuf444[2 * i * w + 2 * j + w] = vBuf[i * w / 2 + j];
			vBuf444[2 * i * w + 2 * j + w + 1] = vBuf[i * w / 2 + j];
		}
	}

	// YUV (4:4:4) to RGB
	for (int i = 0; i < w * h; i++)
	{
		int y = yBuf[i];	
		int u = uBuf444[i];	
		int v = vBuf444[i];	
		double r;
		double g;
		double b;

		yuvLookupTable();
		r = yuv11686[y] + yuv16118[v] - 224.9784;
		if (r < 0)
			r = 0;	
		if (r > 255)
			r = 255;
		g = yuv11686[y]-yuv03961[u]-yuv08274[v]+136.2314;	// 还原的RGB图像的G分量
		if (g < 0)
			g = 0;
		if (g > 255)
			g = 255;
		b = yuv11686[y]+yuv20353[u]-278.8902;	// 还原的RGB图像的B分量
		if (b < 0)
			b = 0;
		if (b > 255)
			b = 255;

		rgbBuf[3 * i + 2] = (unsigned char)r;	// 还原的RGB图像的R分量
		rgbBuf[3 * i + 1] = (unsigned char)g;	// 还原的RGB图像的G分量
		rgbBuf[3 * i] = (unsigned char)b;	// 还原的RGB图像的B分量

	}
	delete[]uBuf444;
	delete[]vBuf444;
	cout << *(rgbBuf +1) << endl;
	unsigned char* temp = new unsigned char[yuvSize * 2];
	unsigned char* temp1 = new unsigned char[yuvSize * 2];
	int i = 0, j = 256 * 256 * 3;
	for(i = 0; j >= 0; i += 3, j -= 3)
	{
		*(temp+i) = *(rgbBuf+j-3);

		*(temp+i+1) = *(rgbBuf+j - 2);

		*(temp+i+2) = *(rgbBuf+j - 1);

	}
	for (i = 0; i < 256; i++)
	{
		for (j = 0; j < 256; j++) 
		{
			*(temp1 + 3 * j+i*256*3) = *(temp + (255 - j) * 3 + i * 256 * 3);
			*(temp1 + 3 * j+1 + i * 256 * 3) = *(temp + (255 - j) * 3+1 + i * 256 * 3);
			*(temp1 + 3 * j+2 + i * 256 * 3) = *(temp + (255 - j) * 3+2 + i * 256 * 3);
		}
	}
	fwrite(temp1, sizeof(unsigned char), yuvSize * 2, rgbFile);
}

(5)rgb2yuv.cpp

#include "stdlib.h"
#include "rgb2yuv.h"

static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];
int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip)
{
	static int init_done = 0;

	long i, j, size;
	unsigned char *r, *g, *b;
	unsigned char *y, *u, *v;
	unsigned char *pu1, *pu2, *pv1, *pv2, *psu, *psv;
	unsigned char *y_buffer, *u_buffer, *v_buffer;
	unsigned char *sub_u_buf, *sub_v_buf;

	if (init_done == 0)
	{
		InitLookupTable();
		init_done = 1;
	}

	// check to see if x_dim and y_dim are divisible by 2
	if ((x_dim % 2) || (y_dim % 2)) return 1;
	size = x_dim * y_dim;

	// allocate memory
	y_buffer = (unsigned char *)y_out;
	sub_u_buf = (unsigned char *)u_out;
	sub_v_buf = (unsigned char *)v_out;
	u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
	v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));
	if (!(u_buffer && v_buffer))
	{
		if (u_buffer) free(u_buffer);
		if (v_buffer) free(v_buffer);
		return 2;
	}

	b = (unsigned char *)bmp;
	y = y_buffer;
	u = u_buffer;
	v = v_buffer;

	// convert RGB to YUV
	if (!flip) {
		for (j = 0; j < y_dim; j ++)
		{
			y = y_buffer + (y_dim - j - 1) * x_dim;
			u = u_buffer + (y_dim - j - 1) * x_dim;
			v = v_buffer + (y_dim - j - 1) * x_dim;

			for (i = 0; i < x_dim; i ++) {
				g = b + 1;
				r = b + 2;
				*y = (unsigned char)(  RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
				*u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2          + 128);
				*v = (unsigned char)(  (*r)/2          - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
				b += 3;
				y ++;
				u ++;
				v ++;
			}
		}
	} else {
		for (i = 0; i < size; i++)
		{
			g = b + 1;
			r = b + 2;
			*y = (unsigned char)(  RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
			*u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2          + 128);
			*v = (unsigned char)(  (*r)/2          - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
			b += 3;
			y ++;
			u ++;
			v ++;
		}
	}

	// subsample UV
	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;
		pu2 = u_buffer + (2 * j + 1) * x_dim;
		pv1 = v_buffer + 2 * j * x_dim;
		pv2 = v_buffer + (2 * j + 1) * x_dim;
		for (i = 0; i < x_dim/2; i ++)
		{
			*psu = (*pu1 + *(pu1+1) + *pu2 + *(pu2+1)) / 4;
			*psv = (*pv1 + *(pv1+1) + *pv2 + *(pv2+1)) / 4;
			psu ++;
			psv ++;
			pu1 += 2;
			pu2 += 2;
			pv1 += 2;
			pv2 += 2;
		}
	}

	free(u_buffer);
	free(v_buffer);

	return 0;
}


void InitLookupTable()
{
	int i;

	for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
	for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
	for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
	for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
	for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
	for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
	for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
}

7.实验结果分析

(1)rgb转yuv

原图:
在这里插入图片描述

转换后:
在这里插入图片描述

(2)yuv转rgb

原图:

在这里插入图片描述
转换后:
在这里插入图片描述

8.误差分析

由yuv420图像转化来的rgb图像与原rgb图像之间是存在误差的,因为yuv420的uv分量只有原来的1/4,如果在一个色度变化慢的区域uv分量只取1/4对整体不太有影响,但是如果区域内色度变化剧烈,那么区域内的色度信息就会有很大误差。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值