数据压缩实验报告1 彩色空间转换

本文详细介绍了如何使用C++编程实现RGB到YUV及YUV到RGB的色彩空间转换,包括函数定义、查找表初始化、缓冲区分配等关键步骤,并通过实际编程验证了转换的正确性。

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

YUV与RGB空间的相互转换
由电视原理可知,亮度和色差信号的构成如下:
Y=0.2990R+0.5870G+0.1140B
U=-0.1684R-0.3316G+0.5B
V=0.5R-0.4187G-0.0813B

R=1.000Y+1.4020(V−128)
G=1.000Y−0.3441(U−128)−0.7139(V−128)
B=1.000Y+1.7718(U−128)−0.0013(V−128)

在这里插入图片描述需要在项目属性中设置命令参数和工作目录

rgb2yuv.cpp

#include<stdio.h>
#include<stdlib.h>
const int width = 256;
const int height = 256;
int main(int argc,char *argv[])
{
    FILE* rgb=NULL;
    FILE* yuv=NULL;
    //判断是否成功打开文件
    if (fopen_s(&rgb, argv[1], "rb") != 0)
        printf("file not opened\n");
    else
        printf("file opened\n");
    if (fopen_s(&yuv, argv[2], "wb") != 0)
        printf("file not opened\n");
    else
        printf("file opened\n");
    //建立缓冲区
    unsigned char* buffer_rgb = (unsigned char*)malloc(sizeof(unsigned char) * 3 * width * height);
    unsigned char* buffer_y = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
    unsigned char* buffer_u = (unsigned char*)malloc(sizeof(unsigned char) * width * height / 4);
    unsigned char* buffer_v = (unsigned char*)malloc(sizeof(unsigned char) * width * height / 4);
    //读文件
    fread(buffer_rgb, sizeof(unsigned char), 3 * width * height,rgb);
    //计算y分量
    for (int i = 0; i < width * height; i++)
    {
        buffer_y[i] = 0.299 * buffer_rgb[3 * i + 2] + 0.587 * buffer_rgb[3 * i + 1] + 0.114 * buffer_rgb[3 * i];
        if (buffer_y[i] > 235)
            buffer_y[i] = 235;
        else if (buffer_y[i] < 16)
            buffer_y[i] = 16;
    }
    //计算u分量
    int k = 0;
    for (int i = 0; i < height ; i++)
        for (int j = 0; j < width; j++)
        {
            if (i % 2 == 0 && j % 2 == 0)
            {
                buffer_u[k] = -0.1684 * buffer_rgb[3 * (i * width + j) + 2] - 0.3316 * buffer_rgb[3 * (i * width + j) + 1] + 0.5 * buffer_rgb[3 * (i * width + j)]+128;
                if (buffer_u[k] > 240)
                    buffer_u[k] = 240;
                else if (buffer_u[k] < 16)
                    buffer_u[k] = 16;
                k++;
            }
        }
    //计算v分量
    k = 0;
    for (int i = 0; i < height; i++)
        for (int j = 0; j < width; j++)
        {
            if (i % 2 == 0 && j % 2 == 0)
            {
                buffer_v[k] = 0.5 * buffer_rgb[3 * (i * width + j) + 2] - 0.4187 * buffer_rgb[3 * (i * width + j) + 1] - 0.0813 * buffer_rgb[3 * (i * width + j)]+128;
                if (buffer_v[k] > 240)
                    buffer_v[k] = 240;
                else if (buffer_v[k] < 16)
                    buffer_v[k] = 16;
                k++;
            }
        }
    //写入文件
    fwrite(buffer_y, sizeof(unsigned char), width * height, yuv);
    fwrite(buffer_u, sizeof(unsigned char), width * height / 4, yuv);
    fwrite(buffer_v, sizeof(unsigned char), width * height / 4, yuv);
    //释放缓冲区,关闭文件
    if (buffer_rgb != NULL)
        free(buffer_rgb);
    if (buffer_y != NULL)
        free(buffer_y);
    if (buffer_u != NULL)
        free(buffer_u);
    if (buffer_v != NULL)
        free(buffer_v);
    if (rgb != NULL)
        fclose(rgb);
    if (yuv != NULL)
        fclose(yuv);
    return 0;
}

在这里插入图片描述
原rgb图像

在这里插入图片描述
转换后的yuv图像

可见转换后的yuv图像与原rgb图像没有什么区别

yuv2rgb.cpp

#include<stdio.h>
#include<stdlib.h>
const int width = 256;
const int height = 256;
int main(int argc,char *argv[])
{
	FILE* rgb = NULL;
	FILE* yuv = NULL;
	//判断是否成功打开文件
	if (fopen_s(&yuv, argv[1], "rb") != 0)
		printf("file not opened\n");
	else
		printf("file opened\n");
	if (fopen_s(&rgb, argv[2], "wb") != 0)
		printf("file not opened\n");
	else
		printf("file opened\n");
	//建立缓冲区
	unsigned char* buffer_rgb = (unsigned char*)malloc(sizeof(unsigned char) * 3 * width * height);
	unsigned char* buffer_y = (unsigned char*)malloc(sizeof(unsigned char) * width * height);
	unsigned char* buffer_u = (unsigned char*)malloc(sizeof(unsigned char) * width * height / 4);
	unsigned char* buffer_v = (unsigned char*)malloc(sizeof(unsigned char) * width * height / 4);
	//读文件
	fread(buffer_y, sizeof(unsigned char), width * height, yuv);
	fread(buffer_u, sizeof(unsigned char), width * height / 4, yuv);
	fread(buffer_v, sizeof(unsigned char), width * height / 4, yuv);
	//处理y分量数据
	unsigned char y[width][height] = { 0 };
	for (int i = 0; i < height; i++)
		for (int j = 0; j < width; j++)
			y[i][j] = buffer_y[i * width + j];
	//处理u和v分量数据
	unsigned char u[width][height] = { 0 };
	unsigned char v[width][height] = { 0 };
	int k = 0;
	for(int i=0;i<height;i++)
		for (int j = 0; j < width; j++)
		{
			if (i % 2 == 0 && j % 2 == 0)
			{
				u[i][j] = buffer_u[k];
				v[i][j] = buffer_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];
			}
		}
	//计算rgb分量,注意这里是bgr
	for(int i=0;i<height;i++)
		for (int j = 0; j < width; j++)
		{
			buffer_rgb[3 * (i * width + j)] = y[i][j] + 1.7718 * (u[i][j] - 128) - 0.0013 * (v[i][j] - 128);
			buffer_rgb[3 * (i * width + j) + 1] = y[i][j] - 0.3441 * (u[i][j] - 128) - 0.7139 * (v[i][j] - 128);
			buffer_rgb[3 * (i * width + j) + 2] = y[i][j] + 1.4020 * (v[i][j] - 128);
		}
	//写入文件
	fwrite(buffer_rgb, sizeof(unsigned char), 3 * width * height, rgb);
	//释放缓冲区,关闭文件
	if (buffer_rgb != NULL)
		free(buffer_rgb);
	if (buffer_y != NULL)
		free(buffer_y);
	if (buffer_u != NULL)
		free(buffer_u);
	if (buffer_v != NULL)
		free(buffer_v);
	if (rgb != NULL)
		fclose(rgb);
	if (yuv != NULL)
		fclose(yuv);
	return 0;
}

在这里插入图片描述
原rgb图像

在这里插入图片描述
由yuv图像转换的rgb图像

可见转换来的rgb图像与原来的相比出现了一些红色和蓝色的点。产生误差的原因:由于采用4:2:0的色度格式采样,yuv图像的一些uv数据并不是由原图像的rgb数据得到,所以再转换时会产生误差。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值