yuv2rgb
实验原理:`
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
为了使色差信号的动态范围控制在0.5之间,需要进行归一化,对色差信号引入压缩系数。归一化后的色差信号为:
U=-0.1684R-0.3316G+0.5B
V=0.5R-0.4187G-0.0813B
得出YUV与RGB空间的转换公式:
R = Y+ 1.4075(V - 128)
G = Y - 0.3455(U - 128) - 0.7169(V - 128)
B = Y + 1.779(U - 128)
色度格式
4:2:0格式是指色差信号U,V的取样频率为亮度信号取样频率的四分之一,在水平方向和垂直方向上的取样点数均为Y的一半。RGB格式的视频按每个像素B、G、R的顺序储存数据;所占空间大小为Width*Height*Frame*3。YUV格式的视频将整帧图像的Y打包存储,依次再存整帧的U、V,然后再是下一帧的数据;YUV格式按4:2:0取样的视频所占空间大小为Width*Height*Frame*1.5(Width*Height*Frame*+Width*Height*Frame*1/4+Width*Height*Frame*1/4)将YUV文件转换为RGB文件后,由于RGB文件的颜色是8bit量化,则数值不在0-255范围内的颜色会出现溢出。因此需对R,G,B做是否溢出的判断,超过255的就令其显示为255,小于0的就令其显示为0.
实验流程
1.程序读取参数,打开文件。
2读取yuv文件,并写入。
3调用函数yuv2rgb 实行 yuv到rgb的转换。
4将RGB缓存写入文件中。
5.释放内存。
实验代码:
Main.cpp
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include"yuv2rgb.h"
#defineu_int8_t unsigned __int8
#defineu_int unsigned __int32
#defineu_int32_t unsigned __int32
#defineFALSE false
#defineTRUE true
intmain(int argc, char** argv)
{
u_int frameWidth = 352;
u_int frameHeight = 240;
bool flip = TRUE;
unsigned int i;
FILE* yuvFile = NULL;
FILE* rgbFile = NULL;
char* rgbFileName = NULL;
char* yuvFileName = NULL;
u_int8_t* rgbBuf = NULL;
u_int8_t* yBuf = NULL;
u_int8_t* uBuf = NULL;
u_int8_t* vBuf = NULL;
u_int32_t videoFramesWritten = 0;
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 yuvfile\n");
/*exit(1);*/
}
else
{
printf("The input yuv file is%s\n", yuvFileName);
}
rgbFile = fopen(rgbFileName,"wb+");
if (rgbFile == NULL)
{
printf("can't find rgbfile\n");
exit(1);
}
else
{
printf("The output file is%s\n", rgbFileName);
}
/* get an input buffer */
yBuf = (u_int8_t*)malloc(frameWidth *frameHeight);
uBuf = (u_int8_t*)malloc((frameWidth *frameHeight) / 4);
vBuf = (u_int8_t*)malloc((frameWidth *frameHeight) / 4);
/* get an output buffer */
rgbBuf = (u_int8_t*)malloc(frameWidth *frameHeight * 3);
if (rgbBuf == NULL || yBuf == NULL || uBuf== NULL || vBuf == NULL)
{
printf("no enought memory\n");
exit(1);
}
/* yuv2rgb*/
fread(yBuf, 1, frameWidth * frameHeight,yuvFile);
fread(uBuf, 1, frameWidth * frameHeight / 4,yuvFile);
fread(vBuf, 1, frameWidth * frameHeight / 4,yuvFile);
//DAI TIANXIE
if (YUV2RGB(frameWidth, frameHeight, yBuf,uBuf, vBuf, rgbBuf, flip))
{
printf("error");
return 0;
}
if (fwrite(rgbBuf, 1, frameWidth*frameHeight * 3, rgbFile))
printf("\n%u %ux%u video frameswritten\n",
++videoFramesWritten, frameWidth, frameHeight);
/* cleanup */
if (rgbBuf)
free(rgbBuf);
if (yBuf)
free(yBuf);
if (uBuf)
free(uBuf);
if (vBuf)
free(vBuf);
if (rgbFile)
fclose(rgbFile);
if (yuvFile)
fclose(yuvFile);
return(0);
}
Yuv2rgb.cpp
#include"stdlib.h"
#include"yuv2rgb.h"
staticfloat YUVRGB14075[256];
staticfloat YUVRGB07169[256], YUVRGB03455[256];
staticfloat YUVRGB1779[256];
intYUV2RGB(int x_dim, int y_dim, void *y_int, void *u_int, void *v_int, void*out_rgb, int flip)
{
static int init_done = 0;
long i, j, size; //define buffer
float r_tmp, b_tmp, g_tmp;
unsigned char *y, *u, *v;
unsigned char *r,*g,*b;
unsigned char *y_buffer, *v_buffer,*u_buffer;
if (init_done == 0)
{
InitLookupTable();
init_done = 1;
}
if ((x_dim % 2) || (y_dim % 2)) return 1;
size = x_dim * y_dim;
y_buffer = (unsigned char *)y_int;
u_buffer = (unsigned char *)u_int;
v_buffer = (unsigned char *)v_int;
y = y_buffer;
v = v_buffer;
u = u_buffer;
b = (unsigned char *)out_rgb;
if (!flip)
{
}
else
{
for (j = 0; j < y_dim; j++)
{
for (i = 0; i < x_dim; i++)
{
g = b + 1;
r = b + 2;
r_tmp = ((*y) +YUVRGB14075[*v]);
g_tmp = ((*y) - YUVRGB07169[*v]- YUVRGB03455[*u]);
b_tmp = ((*y) + YUVRGB1779[*u]);
*r = (unsigned char)(r_tmp<0? 0 : r_tmp>255 ? 255 : r_tmp);
*g = (unsigned char)(g_tmp<0? 0 : g_tmp>255 ? 255 : g_tmp);
*b = (unsigned char)(b_tmp<0? 0 : b_tmp>255 ? 255 : b_tmp);
b += 3;
y++;
u = u_buffer + (j / 2)*x_dim/2 +i / 2;
v = v_buffer + (j / 2)*x_dim/2 +i / 2;
}
}
}
return 0;
}
voidInitLookupTable()
{
int i;
for (i = 0; i < 256; i++)YUVRGB14075[i] =(float)1.14075*(i-128);
for (i = 0; i < 256; i++)YUVRGB07169[i] =(float)0.7169*(i-128);
for (i = 0; i < 256; i++)YUVRGB03455[i] =(float)0.3455*(i-128);
for (i = 0; i < 256; i++)YUVRGB1779[i] =(float)1.779*(i-128);
}
实验结果:
左侧为原yuv文件,右侧为转换过的yuv文件
可以看出两张图虽然色度有些不同,但无法仔细分辨,所以图像转换湿疹