论YUV422(YUYV)与YUV420相互转换

Example 2.13. V4L2_PIX_FMT_YUYV 4 × 4 pixelimagehtml

start + 0:linux

Y'00spa

Cb00.net

Y'01htm

Cr00blog

Y'02ip

Cb01get

Y'03string

Cr01it

start + 8:

Y'10

Cb10

Y'11

Cr10

Y'12

Cb11

Y'13

Cr11

start + 16:

Y'20

Cb20

Y'21

Cr20

Y'22

Cb21

Y'23

Cr21

start + 24:

Y'30

Cb30

Y'31

Cr30

Y'32

Cb31

Y'33

Cr31

YUV422码流存放位置

(转自http://www.chineselinuxuniversity.net/kerneldocs/media/V4L2-PIX-FMT-YUYV.html)

Example 2.18. V4L2_PIX_FMT_YUV420 4 × 4 pixelimage

start + 0:

Y'00

Y'01

Y'02

Y'03

start + 4:

Y'10

Y'11

Y'12

Y'13

start + 8:

Y'20

Y'21

Y'22

Y'23

start + 12:

Y'30

Y'31

Y'32

Y'33

start + 16:

Cb00

Cb01

 

 

start + 18:

Cb10

Cb11

 

 

start + 20:

Cr00

Cr01

 

 

start + 22:

Cr10

Cr11

 

 

 

 

 

 

YUV420码流存放位置

(转自http://www.chineselinuxuniversity.net/kerneldocs/media/re18.html该处是YVU420)

 

这里要顺带提一下YUV444,既无损YUV色彩空间.一个Y带一个Cb一个Cr,即YCbCr.

YUV422采样即从YUV444基础上,从第一个Y开始只保留Cb,剔去Cr,第二个Y只保留Cr剔去Cb…...这样交替采样,长度大小为width*height*2,Y:U:V=4:2:2,一个色彩份量占一个字节.

而YUV420即从YUV422基础上进行隔行采样,例如第一行只保留Cb,第二行只保留Cr……这样交替进行,Y:U:V=4:2:0并非没有V份量,也能够是Y:U:V=4:0:2.相信这样你们容易理解.最后在这个基础上,把Y,U,V三种份量打包排列,即如上图,长度大小为width*height*3/2.

 

说了这么多,是时候贴上具体代码.

 

[cpp]  view plain  copy
 
  1. <span style="font-size:14px;">#include <stdio.h>  
  2. #include <string.h>  
  3.   
  4.   
  5. #define     READ_WRITE_FILE_SIZE    176*144*2  //YUV422 图像分辨率为177x144  
  6.   
  7. unsigned char filebuf[38017] = {0};  
  8.   
  9. int YUV422To420(unsigned char yuv422[], unsigned char yuv420[], int width, int height)  
  10. {          
  11.   
  12.        int ynum=width*height;  
  13.        int i,j,k=0;  
  14.     //获得Y份量  
  15.        for(i=0;i<ynum;i++){  
  16.            yuv420[i]=yuv422[i*2];  
  17.        }  
  18.     //获得U份量  
  19.        for(i=0;i<height;i++){  
  20.            if((i%2)!=0)continue;  
  21.            for(j=0;j<(width/2);j++){  
  22.                if((4*j+1)>(2*width))break;  
  23.                yuv420[ynum+k*2*width/4+j]=yuv422[i*2*width+4*j+1];  
  24.                        }  
  25.             k++;  
  26.        }  
  27.        k=0;  
  28.     //获得V份量  
  29.        for(i=0;i<height;i++){  
  30.            if((i%2)==0)continue;  
  31.            for(j=0;j<(width/2);j++){  
  32.                if((4*j+3)>(2*width))break;  
  33.                yuv420[ynum+ynum/4+k*2*width/4+j]=yuv422[i*2*width+4*j+3];  
  34.                 
  35.            }  
  36.             k++;  
  37.        }  
  38.          
  39.          
  40.        return 1;  
  41. }  
  42.   
  43. int main(void)  
  44. {  
  45.     int len = 0;  
  46.     FILE *fpr, *fpw;  
  47.     unsigned char buf[READ_WRITE_FILE_SIZE];  
  48.     fpr = fopen( "WEBCAM-00012.YUV", "rb" );  
  49.     fpw = fopen( "yuyv_2_yy_u_v.yuv", "wb" );  
  50.     if( fpr == NULL || fpw == NULL )  
  51.     {  
  52.         printf("can not read or write file\n");  
  53.         fcloseall();  
  54.         return 1;  
  55.     }  
  56.     fread( buf, READ_WRITE_FILE_SIZE, 1, fpr );  
  57.     if(YUV422To420(buf,filebuf,176,144))printf("ok\n");  
  58.     printf("size:%d",sizeof(filebuf));  
  59.     fwrite( &filebuf, sizeof(filebuf), 1, fpw );  
  60.     fcloseall();  
  61.     return 0;  
  62. }  
  63. </span>  
[cpp]  view plain  copy
 
  1. <span style="font-size:14px;">#include <stdio.h>  
  2. #include <string.h>  
  3.   
  4.   
  5. #define     READ_WRITE_FILE_SIZE    176*144*2  //YUV422 图像分辨率为177x144  
  6.   
  7. unsigned char filebuf[38017] = {0};  
  8.   
  9. int YUV422To420(unsigned char yuv422[], unsigned char yuv420[], int width, int height)  
  10. {          
  11.   
  12.        int ynum=width*height;  
  13.        int i,j,k=0;  
  14.     //获得Y份量  
  15.        for(i=0;i<ynum;i++){  
  16.            yuv420[i]=yuv422[i*2];  
  17.        }  
  18.     //获得U份量  
  19.        for(i=0;i<height;i++){  
  20.            if((i%2)!=0)continue;  
  21.            for(j=0;j<(width/2);j++){  
  22.                if((4*j+1)>(2*width))break;  
  23.                yuv420[ynum+k*2*width/4+j]=yuv422[i*2*width+4*j+1];  
  24.                        }  
  25.             k++;  
  26.        }  
  27.        k=0;  
  28.     //获得V份量  
  29.        for(i=0;i<height;i++){  
  30.            if((i%2)==0)continue;  
  31.            for(j=0;j<(width/2);j++){  
  32.                if((4*j+3)>(2*width))break;  
  33.                yuv420[ynum+ynum/4+k*2*width/4+j]=yuv422[i*2*width+4*j+3];  
  34.                 
  35.            }  
  36.             k++;  
  37.        }  
  38.          
  39.          
  40.        return 1;  
  41. }  
  42.   
  43. int main(void)  
  44. {  
  45.     int len = 0;  
  46.     FILE *fpr, *fpw;  
  47.     unsigned char buf[READ_WRITE_FILE_SIZE];  
  48.     fpr = fopen( "WEBCAM-00012.YUV", "rb" );  
  49.     fpw = fopen( "yuyv_2_yy_u_v.yuv", "wb" );  
  50.     if( fpr == NULL || fpw == NULL )  
  51.     {  
  52.         printf("can not read or write file\n");  
  53.         fcloseall();  
  54.         return 1;  
  55.     }  
  56.     fread( buf, READ_WRITE_FILE_SIZE, 1, fpr );  
  57.     if(YUV422To420(buf,filebuf,176,144))printf("ok\n");  
  58.     printf("size:%d",sizeof(filebuf));  
  59.     fwrite( &filebuf, sizeof(filebuf), 1, fpw );  
  60.     fcloseall();  
  61.     return 0;