1、实验基本原理
(1)YUV 与 RGB 空间的相互转换
Y=0.2990R+0.5870G+0.1140B
R-Y=0.7010R -0.5870G -0.1140B
B-Y=-0.2990R -0.5870G+0.8860B
归一 化后的色差信号为:
U=-0.1684R -0.3316G+0.5B
V=0.5R -0.4187G -0.0813B
为将两个色差信号电平控制在-0.5~0.5,零电平对应128的码电平 :
U=-0.1684R -0.3316G+0.5B +128
V=0.5R -0.4187G -0.0813B +128
结合以上得
R = Y + 1.4075 *(V-128)
G = Y – 0.3455 (U –128) – 0.7169 (V –128)
B = Y + 1.779 *(U – 128)
2、实验流程
1.程序初始化(打开两个文件、定义变量和缓冲区等)
2.读取YUV文件,抽取YUV数据写入缓冲区
3.调用YUV2RGB的函数实现YUV到RGB数据的转换
4.写RGB文件
5.程序收尾工作(关闭文件,释放缓冲区)
3、关键代码及其分析
yuv2rgb.cpp部分代码
int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_in, void *u_in, void *v_in, 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;
float b1,r1,g1;//设置中间变量,防止溢出
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_in;
sub_u_buf = (unsigned char *)u_in;
sub_v_buf = (unsigned char *)v_in;
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;
//上采样
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 ++)
{
*pu1 = *psu;
*(pu1 + 1) = *psu;
*pu2 = *psu;
*(pu2 + 1) = *psu;
*pv1 = *psv;
*(pv1 + 1) = *psv;
*pv2 = *psv;
*(pv2 + 1) = *psv;
psu ++;
psv ++;
pu1 += 2;
pu2 += 2;
pv1 += 2;
pv2 += 2;
}
}
// convert YUV to RGB
if (!flip) {
//暂时不用
} else {
for (i = 0; i < size; i++)
{
g = b + 1;//RGB格式文件储存按照BGR的顺序
r = b + 2;
b1 = (*y) + YUVRGB1779[*u];
g1 = (*y) - YUVRGB03455[*u] - YUVRGB07169[*v];
r1 = (*y) + YUVRGB14075[*v];
if(b1>0&&b1<255) //类型为unsigned char的数据范围为0~255,直接进行计算可能会出现溢出现象,所以要引入中间变量进行判断
{
*b = (unsigned char)b1;
}
else if (b1>255)
{
*b = 255;
}
else
{
*b = 0;
}
if (g1>0 && g1<255)
{
*g = (unsigned char)g1;
}
else if (g1>255)
{
*g = 255;
}
else
{
*g = 0;
}
if (r1>0 && r1<255)
{
*r = (unsigned char)r1;
}
else if (r1>255)
{
*r = 255;
}else
{
*r = 0;
}
b += 3;
y ++;
u ++;
v ++;
}
}
free(u_buffer);
free(v_buffer);
return 0;
}
void InitLookupTable()
{
int i;
for (i = 0; i < 256; i++) YUVRGB14075[i] = (float)1.4075 * (i-128);
for (i = 0; i < 256; i++) YUVRGB03455[i] = (float)0.3455 * (i-128);
for (i = 0; i < 256; i++) YUVRGB07169[i] = (float)0.7169 * (i-128);
for (i = 0; i < 256; i++) YUVRGB1779[i] = (float)1.779 * (i-128);
}
main.cpp部分代码
/* point to the specified file names */ yuvFileName = argv[1]; rgbFileName = argv[2]; frameWidth = atoi(argv[3]); frameHeight = atoi(argv[4]); /* open the yuv file */ yuvFile = fopen(yuvFileName, "rb"); if (yuvFile == NULL) { printf("cannot find yuv file\n"); exit(1); } else { printf("The input yuv file is %s\n", yuvFileName); } /* open the RAW file */ rgbFile = fopen(rgbFileName, "wb"); if (rgbFile == NULL) { printf("cannot find rgb file\n"); exit(1); } else { printf("The output rgb file is %s\n", rgbFileName); } /* get an input buffer for a frame */ rgbBuf = (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); if (rgbBuf == NULL || yBuf == NULL || uBuf == NULL || vBuf == NULL) { printf("no enought memory\n"); exit(1); } while (fread(yBuf, 1, frameWidth * frameHeight ,yuvFile)&&fread(uBuf, 1, frameWidth * frameHeight /4, yuvFile)&&fread(vBuf, 1, frameWidth * frameHeight /4, yuvFile)) { if(RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, flip)) { printf("error"); return 0; } fwrite(rgbBuf, 1, frameWidth * frameHeight * 3, rgbFile); printf("\r...%d", ++videoFramesWritten); }
4、实验结果及分析
程序第一次执行时,yuv转换成rgb,再转换为yuv,用yuv播放器打开后图像为下图,色彩严重失真
我检查了代码,发现原来是把上采样的代码写成了下采样,修改后,再次执行程序
原图1转换后图像1
原图2转换后图像2
原图3转换后图像3
原图4转换后图像4