YUV与RGB彩色空间转换公式
Y = 0.299R + 0.587G + 0.114B;
U = -0.169R - 0.331G + 0.5B ;
V = 0.5R - 0.419G - 0.081B;
R = Y + 1.4075V;
G = Y - 0.3455U - 0.7169V;
B = Y + 1.779U;
基本算法
该程序算法分为下面几个模块:
1、预备阶段:rgb文件导入项目、打开rgb文件,创建要进行输出的yuv文件和新的rgb文件、开辟空间。
2、提取rgb文件中的r、g、b分量
3、计算yuv分量并实现uv下采样,按照yuv文件格式输出进文件
4、利用yuv分量计算rgb分量,按照rgb文件格式输出文件
5、空间释放
预备阶段算法实例
关键在于计算各个分量所需要的空间,记得给指针赋值时做强制类型转换。
rgb和y字节数分别与图像像素数相同,uv字节数为四分之一。因此yuv文件应为rgb文件大小的一半。打开文件用main函数参数argv[]。
FILE *fpi = NULL,*fpo=NULL,*fpo2 = NULL;
unsigned char *R = (unsigned char*)malloc(width*height);
unsigned char *G = (unsigned char*)malloc(width*height);
unsigned char *B = (unsigned char*)malloc(width*height);
unsigned char *RGB = (unsigned char*)malloc(width*height*3);
unsigned char *YUV = (unsigned char*)malloc(width*height * 3 / 2);
unsigned char *Y = (unsigned char*)malloc(width*height);
unsigned char *U = (unsigned char*)malloc(width*height/4);
unsigned char *V = (unsigned char*)malloc(width*height/4);
if ((fpi = fopen(argv[1], "rb")) == NULL)
{
return 0;
}
if ((fpo = fopen(argv[2], "wb")) == NULL)
{
return 0;
}
if ((fpo2 = fopen(argv[3], "wb")) == NULL)
{
return 0;
}
计算RGB分量
fread(RGB, sizeof(unsigned char), height*width*3, fpi);
for (int i = 0; i < height*width*3; i++)
{
if (i % 3 == 0) { B[i / 3] = RGB[i]; }
if (i % 3 == 1) { G[i / 3] = RGB[i]; }
if (i % 3 == 2) { R[i / 3] = RGB[i]; }
}
fclose(fpi);
计算YUV并下采样
由于420取样格式,只有偶数行的偶数列的像素点才记录一个uv分量,同时yuv一次存入yuv文件。因此我的算法是:每两个像素取一个uv同时每记录一行后向后跳一行。注意uv分量后要+128对进行标准化。下面给出U分量计算的程序:
int a = 0;
for (int i=0; i < height*width / 4; i++)
{
if (a % 512 > 255)
{
a = a + 256;
}
YUV[height*width + i] = (unsigned char)(-0.1684*R[a] - 0.3316*G[a] + 0.5*B[a])+128;
U [i] = YUV[height*width + i]-128;
a = a + 2;
}
利用YUV重新转回rgb文件
for (int i = 0; i < height*width; i++)
{
R[i] = (unsigned char)(Y[i]+1.4075*V[i/4]);
G[i] = (unsigned char)(Y[i] - 0.3455 * U[i / 4] - 0.7169*V[i / 4]);
B[i] = (unsigned char)(Y[i] + 1.779*U[i / 4]);
}
for (int i = 0; i < height*width * 3; i++)
{
if (i % 3 == 0) { RGB[i] = B[i / 3]; }
if (i % 3 == 1) { RGB[i] = G[i / 3]; }
if (i % 3 == 2) { RGB[i] = R[i / 3]; }
}
fwrite(RGB, sizeof(unsigned char), height*width * 3, fpo2);
fclose(fpo2);
两个rgb文件数据差别的解释
试验后观测两个rgb文件,会发现文件数据中存在误差,原因如下:
1、rgb和yuv分量均为unsigned char型,但是在彩色空间转换使有进行浮点型乘法后强转,存在省略小数点。
2、yuv分量对色度信号下采样,省略了高频的色度数据。
3、yuv转rgb时同样存在强转,又省略了一次小数点。