RGB与YUV相互转换C++实现

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时同样存在强转,又省略了一次小数点。

你可能感兴趣的:(RGB与YUV相互转换C++实现)