实验报告:彩色空间转换实验
1.实验内容
①编写RGB转化为YUV程序,重点掌握函数定义,部分查找表的初始化和调用,缓冲区
分配。将得到的RGB文件转换为YUV文件,用YUV Viewer播放器观看,验证是否正确。
②编写将YUV转换为RGB的程序。将给定的实验数据用该程序转换为RGB文件。并与原
RGB文件进行比较,如果有误差,分析误差来自何处。
2.实验步骤
YUV2RGB文件转换流程分析
① 程序初始化(打开两个文件、定义变量和缓冲区 等)
② 读取YUV文件,抽取YUV数据写入缓冲区
③ 调用YUV2RGB的函数实现YUV到RGB数据的转换
④ 写RGB文件
⑤ 程序收尾工作(关闭文件,释放缓冲区)
3.实验代码
/RGB转YUV/
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
int w=256;
int h=256;
//程序初始化(打开两个文件、定义变量和缓冲区等)
FILE* rgbFile=NULL;
FILE* yuvFile = NULL;
unsigned char*R,*G,*B,*pf,*Y,*U,*V,*u,*v;
//打开rgb文件
//rgbFile = fopen("D:\\大三下\\数据压缩\\down.rgb", "rb");
rgbFile = fopen(argv[1], "rb");
//开辟缓存区
pf = (unsigned char *)malloc(sizeof(char)*(w*h*3));
R = (unsigned char *)malloc(sizeof(char)*(w*h));
G = (unsigned char *)malloc(sizeof(char)*(w*h));
B = (unsigned char *)malloc(sizeof(char)*(w*h));
Y = (unsigned char *)malloc(sizeof(char)*(w*h));
U = (unsigned char *)malloc(sizeof(char)*(w*h));
V = (unsigned char *)malloc(sizeof(char)*(w*h));
u=(unsigned char *)malloc(sizeof(char)*(w*h/4));
v=(unsigned char *)malloc(sizeof(char)*(w*h/4));
fread(pf,1,w*h*3,rgbFile);
int i,j,k=0;
//提取RGB分量
for(i=0,j=0;i<w*h*3;i=i+3,j++)
{
R[j]=pf[i+2];
G[j]=pf[i+1];
B[j]=pf[i];
}
//计算YUV分量
for(i=0,j=0;i<w*h;i++,j++)
{
Y[j]=0.2990*R[i]+0.5870*G[i]+0.1140*B[i];
U[j]=-0.1684*R[i]-0.3316*G[i]+0.5*B[i]+128;
V[j]=0.5*R[i]-0.4187*G[i]-0.0813*B[i]+128;
}
//对UV下采样
for(i=0;i<h;i=i+2)
{
for(j=0;j<w;j=j+2)
{
u[k]=(U[w*i+j]+U[w*i+j+1]+U[(i+1)*w+j]+U[(i+1)*w+j+1])/4;
v[k]=(V[w*i+j]+V[w*i+j+1]+V[(i+1)*w+j]+V[(i+1)*w+j+1])/4;
k++;
}
}
//YUV量化后码电平分配
for(k=0;k<w*h;k++)
{
if(Y[k]>235)
Y[k]=235;
if(Y[k]<16)
Y[k]=16;
}
for(k=0;k<w*h/4;k++)
{
if(u[k]>240)
u[k]=240;
if(u[k]<16)
u[k]=16;
if(v[k]>240)
v[k]=240;
if(v[k]<16)
v[k]=16;
}
//yuvFile = fopen("D:\\大三下\\数据压缩\\down.yuv", "wb");
yuvFile = fopen(argv[2], "wb");
fwrite(Y,1,w*h,yuvFile);
fwrite(u,1,w*h/4,yuvFile);
fwrite(v,1,w*h/4,yuvFile);
free(pf);
free(R);
free(G);
free(B);
free(Y);
free(U);
free(V);
free(u);
free(v);
fclose(rgbFile);
fclose(yuvFile);
return 0;
}
转换后的down.yuv文件用YUV播放器播放
/YUV转RGB/此处我用了与RGB转YUV相反的方法,输出rgb文件再转换为yuv文件用YUV播放器打开
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char* argv[])
{
int w=256;
int h=256;
//程序初始化(打开两个文件、定义变量和缓冲区等)
FILE* rgbFile=NULL;
FILE* yuvFile = NULL;
unsigned char*R,*G,*B,*pf,*Y,*U,*V,*u,*v;
//打开yuv文件
yuvFile = fopen(argv[1], "rb");
//开辟缓存区
pf = (unsigned char *)malloc(sizeof(char)*(w*h*3));
R = (unsigned char *)malloc(sizeof(char)*(w*h));
G = (unsigned char *)malloc(sizeof(char)*(w*h));
B = (unsigned char *)malloc(sizeof(char)*(w*h));
Y = (unsigned char *)malloc(sizeof(char)*(w*h));
U = (unsigned char *)malloc(sizeof(char)*(w*h));
V = (unsigned char *)malloc(sizeof(char)*(w*h));
u=(unsigned char *)malloc(sizeof(char)*(w*h/4));
v=(unsigned char *)malloc(sizeof(char)*(w*h/4));
fread(Y,1,w*h,yuvFile);
fread(u,1,w*h/4,yuvFile);
fread(v,1,w*h/4,yuvFile);
int i,j,k=0;
//上采样
for(i=0;i<h;i=i+2)
{
for(j=0;j<w;j=j+2)
{
U[w*i+j]=U[w*i+j+1]=U[(i+1)*w+j]=U[(i+1)*w+j+1]=u[k];
V[w*i+j]=V[w*i+j+1]=V[(i+1)*w+j]=V[(i+1)*w+j+1]=v[k];
k++;
}
}
//计算RGB
for(i=0,j=0;i<w*h;i++,j++)
{
R[j]=Y[i]+1.14075*(V[i]-128);
G[j]=Y[i]-0.7169*(V[i]-128)-0.3455*(U[i]-128);
B[j]=Y[i]+1.779*(U[i]-128);
}
rgbFile = fopen(argv[2], "wb");
for(i=0,j=0;i<w*h*3;i=i+3,j++)
{
pf[i+2]=R[j];
pf[i+1]=G[j];
pf[i]=B[j];
}
fwrite(pf,1,w*h*3,rgbFile);
free(pf);
free(R);
free(G);
free(B);
free(Y);
free(U);
free(V);
free(u);
free(v);
fclose(rgbFile);
fclose(yuvFile);
return 0;
}
再次转为YUV文件打开
误差来源:RGB转YUV时有下采样和量化后码电平分配造成部分YUV数据丢失,故YUV转RGB会产生误差。
4.实验心得:
通过这次实验我对RGB和YUV文件格式其内部是如何储存的,如何读取,如何写入有了更好的理解,同时也学会如何开辟缓存区,如何使用main函数的形参。但仍有很多不足,我还是不习惯建多个文件,所有的代码都写在了main函数里,对于目标文件也只考虑当前的文件,代码不能广泛性使用,这些问题在以后的实验中都要注意。