基本原理
彩色空间转化的公式及其分析
根据查询可以得到用 YUV计算得出RGB的公式
R=Y+1.4075(V−128)
G=Y−0.3455(U−128)−0.7169(V−128)
B=Y+1.779(U−128)
分析:根据
Cr=0.713(R−Y)
Cb=0.564(B−Y)转换并归一化
yuv文件存储方式是依次分别存完整的y、u、v、用三个指针分别指向,但是rgb文件在存储的过程中是按照bgrbgr的顺序存储的,所以在程序中将b的地址等于bmp之后rg分量可以用g = b + 1;r = b + 2;表示。
实验的流程分析
1、程序初始化(打开两个文件、定义变量和缓冲区等)
2、读取YUV文件,抽取YUV数据写入缓冲区
3、调用YUV2RGB的函数实现YUV到RGB数据的转换
4、写RGB文件
5、程序收尾工作(关闭文件,释放缓冲区)
实验过程中一定要注意指针的使用,不能越界,开辟的指针空间在判断之后要记得释放
关键代码及其分析
main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include “yuv2rgb.h”
定义int型
#define u_int8_t unsigned __int8
#define u_int unsigned __int32
#define u_int32_t unsigned __int32
#define FALSE false
#define TRUE true
int main(int argc, char** argv)
{
/* variables controlable from command line */
u_int frameWidth = 352;/* --width=<uint> */
u_int frameHeight = 240;/* --height=<uint> */
bool flip = TRUE;/* --flip */
unsigned int i;
/* internal variables */
char* rgbFileName = NULL;
char* yuvFileName = NULL;
/*两个文件指针*/
FILE* rgbFile = NULL;
FILE* yuvFile = NULL;
/*四个buffer,YUV*/
u_int8_t* yBuf = NULL;
u_int8_t* uBuf = NULL;
u_int8_t* vBuf = NULL;
u_int8_t* rgbBuf = NULL;
u_int32_t videoFramesWritten = 0;
/* begin process command line */
/* point to the specified file names */
通过项目-》属性-》配置属性-》调试 设置输入输出的文件名以及文件的宽高
yuvFileName = argv[1];
rgbFileName = argv[2];
frameWidth = atoi(argv[3]);
frameHeight = atoi(argv[4]);
/* open the RGB 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 */
开辟空间 注意输入的yuv文件中的ubuf和vbuf空间是ybuf的四分之一
yBuf = (u_int8_t*)malloc(frameWidth * frameHeight );
uBuf = (u_int8_t*)malloc(frameWidth * frameHeight/4);
vBuf = (u_int8_t*)malloc(frameWidth * frameHeight/4);
/* get the output buffers for a frame */
输出的rgb文件只需要一个指针,因此rgbbuf开辟的空间宽乘高乘三
rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight*3);
if (yBuf == NULL || uBuf == NULL || vBuf == NULL || rgbBuf == 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 (YUV2RGB(frameWidth, frameHeight, yBuf,uBuf,vBuf, rgbBuf, flip))
{
printf("error");
return 0;
}
fwrite(rgbBuf, 1, frameWidth * frameHeight*3, rgbFile);
printf("\r...%d", ++videoFramesWritten);
}
printf("\n%u %ux%u video frames written\n",
videoFramesWritten, frameWidth, frameHeight);
/* cleanup */
if (yuvFile != NULL)
{
fclose(yuvFile);
}
if (rgbFile != NULL)
{
fclose(rgbFile);
}
if (yBuf != NULL)
free(yBuf);
if (uBuf != NULL)
free(uBuf);
if (vBuf != NULL)
free(vBuf);
if (rgbBuf != NULL)
free(rgbBuf);
return(0);
}
/* This file contains RGB to YUV transformation functions. */
#include "stdlib.h"
#include "yuv2rgb.h"
static float RGBYUV14075[256], RGBYUV03455[256], RGBYUV07169[256];
static float RGBYUV17790[256];
/************************************************************************
*
* int RGB2YUV (int x_dim, int y_dim, void *bmp, YUV *yuv)
*
* Purpose :It takes a 24-bit RGB bitmap and convert it into
* YUV (4:2:0) format
*
* Input : x_dimthe x dimension of the bitmap
* y_dimthe y dimension of the bitmap
* bmppointer to the buffer of the bitmap
* yuvpointer to the YUV structure
*
* Output : 0OK
* 1wrong dimension
* 2memory allocation error
*
* Side Effect :
* None
*
* Date :09/28/2000
*
* Contacts:
*
* Adam Li
*
* DivX Advance Research Center <darc@projectmayo.com>
*
************************************************************************/
int YUV2RGB(int x_dim, int y_dim, void *yin,void *uin,void *vin, void *bmp , int flip)
{
static int init_done = 0;
long i, j, size;
unsigned char *r, *g, *b;
unsigned char *y, *u, *v;
float r1, g1, b1;
unsigned char *pu1,*pu2,*pv1,*pv2,*psu,*psv;
unsigned char *y_buffer,*u_buffer,*v_buffer;
unsigned char *up_u_buf, *up_v_buf;
if (init_done == 0)
{
InitLookupTable();
init_done = 1;
}
y_buffer =(unsigned char*) yin;
u_buffer = (unsigned char*)uin;
v_buffer = (unsigned char*)vin;
// 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是一样的
up_u_buf = (unsigned char *)malloc(size*sizeof(unsigned char));
up_v_buf = (unsigned char *)malloc(size*sizeof(unsigned char));
if (!(up_u_buf && up_v_buf))
{
if (up_u_buf) free(up_u_buf);
if (up_v_buf) free(up_v_buf);
return 2;
}
y = y_buffer;
u = up_u_buf;
v = up_v_buf;
b = (unsigned char*)bmp;
//upsample UV
根据RGB2YUV程序中的下采样指针地址的赋值,此处没有做过多调整,上采样的过程四个像素点YU分量分别赋相同的值
for (j = 0; j < y_dim/2; j++)
{
psu = u_buffer + j * x_dim / 2;
psv = v_buffer + j * x_dim / 2;
pu1 = up_u_buf + 2 * j * x_dim;
pu2 = up_u_buf + (2 * j + 1) * x_dim;
pv1 = up_v_buf + 2 * j * x_dim;
pv2 = up_v_buf + (2 * j + 1) * x_dim;
for (i = 0; i < x_dim / 2; i++)
{
*pu1 = *psu;
*(pu1+1) = *psu;(此处如果用*(pu1++)下面用pu1++有错误)
*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 RGB to YUV
为了防止色彩溢出用一个float型的中间变量控制
for (i = 0; i < size; i++)
{
g = b + 1;
r = b + 2;
r1 = *y + RGBYUV14075[*v ];
g1 = *y - RGBYUV03455[*u ] - RGBYUV07169[*v];
b1 = *y + RGBYUV17790[*u ];
if (r1 < 0) r1 = 0;
if (r1 > 255) r1 = 255;
if (g1 < 0) g1 = 0;
if (g1 > 255) g1 = 255;
if (b1 < 0) b1 = 0;
if (b1 > 255) b1 = 255;
*r = (unsigned char)r1;
*g = (unsigned char)g1;
*b = (unsigned char)b1;
b += 3;
y++;
u++;
v++;
}
if (up_u_buf != NULL)free(up_u_buf);
if (up_v_buf != NULL)free(up_v_buf);
return 0;
}
此处如果用float1.4075*i有错
void InitLookupTable()
{
int i;
for (i = 0; i < 256; i++) RGBYUV14075[i] = (float)1.4075 * (i-128);
for (i = 0; i < 256; i++) RGBYUV03455[i] = (float)0.3455 * (i - 128);
for (i = 0; i < 256; i++) RGBYUV07169[i] = (float)0.7169 * (i - 128);
for (i = 0; i < 256; i++) RGBYUV17790[i] = (float)1.7790 * (i - 128);
}
实验结果及分析
经过不同输入文件的对比,我们可以看出来,通过yuv转换到rgb再转换到yuv的过程中,yuv文件基本上没有太大的变化,可以证明程序的正确性,这说明rgb文件的确和yuv文件存在一定程度上的差别。
结论
经过分析,可以看得出来,转换成rgb格式的yuv文件存在一定程度上的色彩失真。