YUV420转YUV444

在最近的CCP测试中,需要使用YUV444的测试序列,而平时使用的全都是YUV420的序列,因此自己尝试用C写了一个YUV420转YUV444的程序。


1、YUV分三种采样方式:

YUV420转YUV444

YUV444:对于每一个像素都对应一个Y分量、一个U分量、一个V分量。

YUV422:对于一个像素都对应一个Y分量,但是每两个像素(或者说Y分量)对应一个U分量和一个V分量。

YUV420:对于一个像素都对应一个Y分量,但是每四个像素(或者说Y分量)对应一个U分量和一个V分量。


2、YUV的存储格式:

YUV在存储时是以数组的形式存储的,可以看做连续的三个数组。三个数组分别单独存储Y、U、V分量。

以一副1920*1080的YUV444图像为例,如图,YUV分量分别存储在大小为1920*1080的数组中,因此对于数据的操作十分简单。

YUV420转YUV444

同理对于YUV420和YUV422,只是U和V的数组大小的不同而已。

总数据量来看,YUV444需要存储1920*1080*3个值,YUV422需要存储1920*1080*2个值,YUV420需要存储1920*1080*3/2个值。


3、YUV420转YUV444主要思路

以U分量为例,其序列如下

YUV420转YUV444

对U进行插值,每个田字格四个位置使用一个U值。

YUV420转YUV444

在代码中,可以直接通过对数组循环赋值即可完成。

对V分量的操作相同。


4、代码实现

YUV420转YUV444函数:

[cpp] view plain copy
  1. #include "YUV.h"  
  2. #include<malloc.h>  
  3. #include<memory.h>  
  4.   
  5. typedef unsigned char   UINT8;  
  6. typedef signed short    INT16;  
  7. typedef signed int      INT32;  
  8.   
  9. #define Y_SIZE          (PIC_W*PIC_H)  
  10. #define YUV420_SIZE        (Y_SIZE*3/2)       //4:2:0格式  
  11. #define YUV422_SIZE        (Y_SIZE*2)       //4:2:2格式  
  12. #define YUV444_SIZE        (Y_SIZE*3)      //4:4:4格式  
  13.   
  14. int YUV2YUV(unsigned char *yuv_buff,unsigned char *yuv2_buff, int PIC_W, int PIC_H)  
  15. {  
  16.     UINT8 *y_buf=NULL;  
  17.     y_buf = (UINT8*)malloc(YUV444_SIZE);  
  18.     if(y_buf == NULL)  
  19.     {  
  20.         printf("Error: malloc buf.\n");  
  21.         exit(1);  
  22.     }  
  23.   
  24.     int h,v;  
  25.     //Y分量转换;  
  26.     for(v=0; v<PIC_H; v++)  
  27.     {  
  28.         for(h=0; h<PIC_W; h++)  
  29.         {  
  30.             y_buf[v*PIC_W+h] = yuv_buff[(v*PIC_W+h)];  
  31.         }  
  32.     }  
  33.     //UV分量转换  
  34.     for(v=0; v<PIC_H; v+=2)  
  35.     {  
  36.         for(h=0; h<PIC_W; h+=2)  
  37.         {  
  38.             y_buf[PIC_H*PIC_W+v*PIC_W+h] = yuv_buff[PIC_H*PIC_W+v/2*PIC_W/2+h/2];  
  39.             y_buf[PIC_H*PIC_W+v*PIC_W+h+1] = yuv_buff[PIC_H*PIC_W+v/2*PIC_W/2+h/2];  
  40.             y_buf[PIC_H*PIC_W+(v+1)*PIC_W+h] = yuv_buff[PIC_H*PIC_W+v/2*PIC_W/2+h/2];  
  41.             y_buf[PIC_H*PIC_W+(v+1)*PIC_W+h+1] = yuv_buff[PIC_H*PIC_W+v/2*PIC_W/2+h/2];  
  42.   
  43.             y_buf[2*PIC_H*PIC_W+v*PIC_W+h] = yuv_buff[5*PIC_H*PIC_W/4+v/2*PIC_W/2+h/2];  
  44.             y_buf[2*PIC_H*PIC_W+v*PIC_W+h+1] = yuv_buff[5*PIC_H*PIC_W/4+v/2*PIC_W/2+h/2];  
  45.             y_buf[2*PIC_H*PIC_W+(v+1)*PIC_W+h] = yuv_buff[5*PIC_H*PIC_W/4+v/2*PIC_W/2+h/2];  
  46.             y_buf[2*PIC_H*PIC_W+(v+1)*PIC_W+h+1] = yuv_buff[5*PIC_H*PIC_W/4+v/2*PIC_W/2+h/2];  
  47.         }  
  48.     }  
  49.   
  50.   
  51.     memcpy(yuv2_buff,y_buf,YUV444_SIZE);   
  52.   
  53.     free(y_buf);  
  54.     y_buf=NULL;  
  55.   
  56.     return 1;         
  57.   
  58. }  


main函数如下,主要完成对YUV数据的读取和存储:

[cpp] view plain copy
  1. #include "YUV.h"  
  2.   
  3. #define _CRT_SECURE_NO_WARNINGS  
  4. #define IMAGEWIDTH 1024    //图像的宽  
  5. #define IMAGEHEIGHT 768    //高  
  6.   
  7.   
  8.   
  9.   
  10. int main(int argc, char *argv[])  
  11. {  
  12.     //读入参数,共有3个参数  
  13.     if( argc != 3 )   
  14.     {  
  15.         printf ("Please input infile and outfile!\n");  
  16.         exit(-1);  
  17.     }  
  18.   
  19.     FILE * input_yuvfile;    //输入YUV420图像  
  20.     FILE * output_yuvfile;     //输出YUV444图像  
  21.   
  22.     if(NULL == (input_yuvfile =  fopen(argv[1], "rb")))  
  23.     {  
  24.         printf("File input is can't open!\n");  
  25.         return -1;  
  26.     }  
  27.     if(NULL == (output_yuvfile = fopen(argv[2], "wb")))  
  28.     {  
  29.         printf("File output is can't open!\n");  
  30.         return -1;  
  31.     }  
  32.   
  33.   
  34.   
  35.     int readsize;  
  36.     unsigned char *in_buff;  
  37.     in_buff =  (unsigned char *)malloc(IMAGEWIDTH*IMAGEHEIGHT*sizeof(unsigned char)*3/2);   
  38.   
  39.     unsigned char *out_buff,*yuv_buff;  
  40.     out_buff=(unsigned char *)malloc(IMAGEWIDTH*IMAGEHEIGHT*sizeof(unsigned char)*3);  
  41.     memset (out_buff,0,IMAGEWIDTH*IMAGEHEIGHT*sizeof(unsigned char)*3);  
  42.     yuv_buff=(unsigned char *)malloc(IMAGEWIDTH*IMAGEHEIGHT*sizeof(unsigned char)*3/2);  
  43.     memset (yuv_buff,0,IMAGEWIDTH*IMAGEHEIGHT*sizeof(unsigned char)*3/2);  
  44.   
  45.   
  46.     while(1)  
  47.     {  
  48.         readsize=fread(in_buff,1 , IMAGEWIDTH*IMAGEHEIGHT*3/2,input_yuvfile);  
  49.         if(readsize<IMAGEWIDTH*IMAGEHEIGHT*3/2) //读取的数据量少于IMAGEWIDTH*IMAGEHEIGHT*3/2时跳出  
  50.             break;  
  51.   
  52.         memcpy(yuv_buff,in_buff,IMAGEWIDTH*IMAGEHEIGHT*sizeof(unsigned char)*3/2);  
  53.   
  54.         YUV2YUV(yuv_buff, out_buff,IMAGEWIDTH,IMAGEHEIGHT);  
  55.   
  56.         fwrite(out_buff,1,IMAGEWIDTH*IMAGEHEIGHT*3,output_yuvfile);  
  57.     }  
  58.   
  59.     free(in_buff);  
  60.     in_buff=NULL;  
  61.     free(out_buff);  
  62.     out_buff=NULL;  
  63.     free(yuv_buff);  
  64.     yuv_buff=NULL;  
  65.   
  66.     fclose(input_yuvfile);  
  67.     fclose(output_yuvfile);  
  68.   
  69. }