YUV420 和RGB之间的转换的程序,YUV采样频率采用cif

本文提供了一段用于YUV420格式与RGB格式互相转换的C/C++代码实现,包括从YUV420格式转换到RGB格式,并将结果保存为BMP文件,以及从RGB格式转换到YUV420格式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

YUV420 和RGB之间的转换的程序。

测试使用的cif文件:http://trace.eas.asu.edu/yuv/tempete.zip


【C/C++ code】 #include < stdio.h > #include < stdlib.h >
#define WIDTH 352
#define HEIGHT 288
// 转换矩阵
double YuvToRgb[ 3 ][ 3 ] = { 1 ,       0 1.4022 ,
                        
1 ,    - 0.3456 , - 0.7145 ,
                        
1 ,   1.771 ,       0 };

// 根据RGB三分量写BMP
int WriteBmp( int width, int height, unsigned char * R,unsigned char * G,unsigned char * B, char * BmpFileName);

// 转换函数
int Convert( char * file, int width, int height, int n)
{
   
// 变量声明
    int i = 0 ;
   
int temp = 0 ;
   
int x = 0 ;
   
int y = 0 ;
   
int fReadSize = 0 ;
   
int ImgSize = width * height;
    FILE
* fp = NULL;
    unsigned
char * yuv = NULL;
    unsigned
char * rgb = NULL;
    unsigned
char * cTemp[ 6 ];
   
char BmpFileName[ 256 ];

   
// 申请空间
    int FrameSize = ImgSize + (ImgSize >> 1 );
    yuv
= (unsigned char * )malloc(FrameSize); rgb = (unsigned char * )malloc(ImgSize * 3 );
   
// 读取指定文件中的指定帧
    if ((fp = fopen(file, " rb " )) == NULL)
       
return 0 ;
    fseek(fp, FrameSize
* (n - 1 ), SEEK_CUR);
    fReadSize
= fread(yuv, 1 , FrameSize, fp);
    fclose(fp);
   
if (fReadSize < FrameSize)
       
return 0 ;
   
// 转换指定帧       cTemp[ 0 ] = yuv;                        // y分量地址
    cTemp[ 1 ] = yuv + ImgSize;            // u分量地址
    cTemp[ 2 ] = cTemp[ 1 ] + (ImgSize >> 2 );    // v分量地址
    cTemp[ 3 ] = rgb;                        // r分量地址
    cTemp[ 4 ] = rgb + ImgSize;            // g分量地址
    cTemp[ 5 ] = cTemp[ 4 ] + ImgSize;        // b分量地址
    for (y = 0 ; y < height; y ++ )
       
for (x = 0 ; x < width; x ++ )
        {
           
// r分量
            temp = cTemp[ 0 ][y * width + x] + (cTemp[ 2 ][(y / 2 ) * (width / 2 ) + x / 2 ] - 128 ) * YuvToRgb[ 0 ][ 2 ];
            cTemp[
3 ][y * width + x] = temp < 0 ? 0 : (temp > 255 ? 255 : temp);
           
// g分量
            temp = cTemp[ 0 ][y * width + x] + (cTemp[ 1 ][(y / 2 ) * (width / 2 ) + x / 2 ] - 128 ) * YuvToRgb[ 1 ][ 1 ]
                                      
+ (cTemp[ 2 ][(y / 2 ) * (width / 2 ) + x / 2 ] - 128 ) * YuvToRgb[ 1 ][ 2 ];
            cTemp[
4 ][y * width + x] = temp < 0 ? 0 : (temp > 255 ? 255 : temp);
           
// b分量
            temp = cTemp[ 0 ][y * width + x] + (cTemp[ 1 ][(y / 2 ) * (width / 2 ) + x / 2 ] - 128 ) * YuvToRgb[ 2 ][ 1 ];
            cTemp[
5 ][y * width + x] = temp < 0 ? 0 : (temp > 255 ? 255 : temp);
        }

   
// 写到BMP文件中
    sprintf(BmpFileName, " %s%05d.bmp " , file, n);
    WriteBmp(width, height, cTemp[
3 ], cTemp[ 4 ], cTemp[ 5 ], BmpFileName);

    free(yuv);
    free(rgb);
   
return n;
}
// 入口 void main()
{
   
int i = 1 ;
//     for( i=0; i<260; i++)
        Convert( " tempete.cif " , WIDTH, HEIGHT, i); // 获取文件的第i帧
}

// 写BMP  int WriteBmp( int width, int height, unsigned char * R,unsigned char * G,unsigned char * B, char * BmpFileName)
{
   
int x = 0 ;
   
int y = 0 ;
   
int i = 0 ;
   
int j = 0 ;
    FILE
* fp;
    unsigned
char * WRGB;
    unsigned
char * WRGB_Start;
   
int yu = width * 3 % 4 ;
   
int BytePerLine = 0 ;

    yu
= yu != 0 ? 4 - yu : yu;
    BytePerLine
= width * 3 + yu;

   
if ((fp = fopen(BmpFileName, " wb " )) == NULL)
       
return 0 ;
    WRGB
= (unsigned char * )malloc(BytePerLine * height + 54 );
    memset(WRGB,
0 , BytePerLine * height + 54 );
   
   
// BMP头
    WRGB[ 0 ] = ' B ' ;
    WRGB[
1 ] = ' M ' ;
   
* ((unsigned int * )(WRGB + 2 )) = BytePerLine * height + 54 ;
   
* ((unsigned int * )(WRGB + 10 )) = 54 ;
   
* ((unsigned int * )(WRGB + 14 )) = 40 ;
   
* ((unsigned int * )(WRGB + 18 )) = width;
   
* ((unsigned int * )(WRGB + 22 )) = height;
   
* ((unsigned short * )(WRGB + 26 )) = 1 ;
   
* ((unsigned short * )(WRGB + 28 )) = 24 ;
   
* ((unsigned short * )(WRGB + 34 )) = BytePerLine * height;

    WRGB_Start
= WRGB + 54 ;

   
for (y = height - 1 ,j = 0 ; y >= 0 ; y -- ,j ++ )
    {
       
for (x = 0 ,i = 0 ; x < width; x ++ )
        {
            WRGB_Start[y
* BytePerLine + i ++ ] = B[j * width + x];
            WRGB_Start[y
* BytePerLine + i ++ ] = G[j * width + x];
            WRGB_Start[y
* BytePerLine + i ++ ] = R[j * width + x];
        }
    }

    fwrite(WRGB,
1 , BytePerLine * height + 54 , fp);
    free(WRGB);
    fclose(fp);
   
return 1 ;
}
 
  【C/C++ code:RGB2YUV420 ,存储格式为cif】 
 
 
  #include 
  <
  stdio.h
  >
  
#include 
  <
  stdlib.h
  >
  
#include 
  <
  string
  .h
  >
  


  //
  转换矩阵
  

  #define
   MY(a,b,c) (( a*  0.2989  + b*  0.5866  + c*  0.1145))
  

  #define
   MU(a,b,c) (( a*(-0.1688) + b*(-0.3312) + c*  0.5000 + 128))
  

  #define
   MV(a,b,c) (( a*  0.5000  + b*(-0.4184) + c*(-0.0816) + 128))
  

  //
  大小判断
  

  #define
   DY(a,b,c) (MY(a,b,c) > 255 ? 255 : (MY(a,b,c) < 0 ? 0 : MY(a,b,c)))
  

  #define
   DU(a,b,c) (MU(a,b,c) > 255 ? 255 : (MU(a,b,c) < 0 ? 0 : MU(a,b,c)))
  

  #define
   DV(a,b,c) (MV(a,b,c) > 255 ? 255 : (MV(a,b,c) < 0 ? 0 : MV(a,b,c)))
  

  //
  只处理352*288文件
  

  #define
   WIDTH 352
  

  #define
   HEIGHT 288
  


  //
  读BMP
  

  void
   ReadBmp(unsigned 
  char
   
  *
  RGB,FILE 
  *
  fp);


  //
  转换函数
  

  void
   Convert(unsigned 
  char
   
  *
  RGB, unsigned 
  char
   
  *
  YUV);


  //
  入口
  

  int
   main()
{
    
  int
   i
  =
  1
  ;
    
  char
   file[
  255
  ];
    FILE 
  *
  fp;
    FILE 
  *
  fp2;
    unsigned 
  char
   
  *
  YUV 
  =
   NULL;
    unsigned 
  char
   
  *
  RGB 
  =
   NULL;
    unsigned 
  int
   imgSize 
  =
   WIDTH
  *
  HEIGHT;

    
  if
  ((fp2 
  =
   fopen(
  "
  CIF文件
  "
  , 
  "
  wb
  "
  )) 
  ==
   NULL)
    {
        
  return
   
  0
  ;
    }

    RGB 
  =
   (unsigned 
  char
  *
  )malloc(imgSize
  *
  6
  );
    YUV 
  =
   (unsigned 
  char
  *
  )malloc(imgSize 
  +
   (imgSize
  >>
  1
  ));
   
    
  for
  (i
  =
  1
  ; i
  <=
  260
  ; i
  ++
  )
    {
        sprintf(file, 
  "
  RGB_%05d.bmp
  "
  , i);
  //
  生成文件名
  

          
  if
  ((fp 
  =
   fopen(file, 
  "
  rb
  "
  )) 
  ==
   NULL)
            
  continue
  ;

        printf(
  "
  打开文件%s/n
  "
  , file);
        ReadBmp(RGB, fp);
        Convert(RGB, YUV);
        fwrite(YUV, 
  1
  , imgSize
  +
  (imgSize
  >>
  1
  ), fp2);
  //
  写入文件
  

          fclose(fp);
    }

    fclose(fp2);
    
  if
  (RGB)
        free(RGB);

    
  if
  (YUV)
        free(YUV);

    printf(
  "
  完成/n
  "
  );
    system(
  "
  pause
  "
  );
    
  return
   
  1
  ;
}


  //
  读BMP
  

  void
   ReadBmp(unsigned 
  char
   
  *
  RGB,FILE 
  *
  fp)
{
    
  int
   i,j;
    unsigned 
  char
   temp;

    fseek(fp,
  54
  , SEEK_SET);

    fread(RGB
  +
  WIDTH
  *
  HEIGHT
  *
  3
  , 
  1
  , WIDTH
  *
  HEIGHT
  *
  3
  , fp);
  //
  读取
  

      
  for
  (i
  =
  HEIGHT
  -
  1
  ,j
  =
  0
  ; i
  >=
  0
  ; i
  --
  ,j
  ++
  )
  //
  调整顺序
  

      {
        memcpy(RGB
  +
  j
  *
  WIDTH
  *
  3
  ,RGB
  +
  WIDTH
  *
  HEIGHT
  *
  3
  +
  i
  *
  WIDTH
  *
  3
  ,WIDTH
  *
  3
  );
    }
    
    
  //
  顺序调整
  

      
  for
  (i
  =
  0
  ; (unsigned 
  int
  )i 
  <
   WIDTH
  *
  HEIGHT
  *
  3
  ; i
  +=
  3
  )
    {
        temp 
  =
   RGB[i];
        RGB[i] 
  =
   RGB[i
  +
  2
  ];
        RGB[i
  +
  2
  ] 
  =
   temp;
    }
}


  void
   Convert(unsigned 
  char
   
  *
  RGB, unsigned 
  char
   
  *
  YUV)
{
    
  //
  变量声明
  

      unsigned 
  int
   i,x,y,j;
    unsigned 
  char
   
  *
  Y 
  =
   NULL;
    unsigned 
  char
   
  *
  U 
  =
   NULL;
    unsigned 
  char
   
  *
  V 
  =
   NULL;
    
    Y 
  =
   YUV;
    U 
  =
   YUV 
  +
   WIDTH
  *
  HEIGHT;
    V 
  =
   U 
  +
   ((WIDTH
  *
  HEIGHT)
  >>
  2
  );

    
  for
  (y
  =
  0
  ; y 
  <
   HEIGHT; y
  ++
  )
        
  for
  (x
  =
  0
  ; x 
  <
   WIDTH; x
  ++
  )
        {
            j 
  =
   y
  *
  WIDTH 
  +
   x;
            i 
  =
   j
  *
  3
  ;
            Y[j] 
  =
   (unsigned 
  char
  )(DY(RGB[i], RGB[i
  +
  1
  ], RGB[i
  +
  2
  ]));

            
  if
  (x
  %
  2
   
  ==
   
  1
   
  &&
   y
  %
  2
   
  ==
   
  1
  )
            {
                j 
  =
   (WIDTH
  >>
  1
  ) 
  *
   (y
  >>
  1
  ) 
  +
   (x
  >>
  1
  );
                
  //
  上面i仍有效
  

                  U[j] 
  =
   (unsigned 
  char
  )
                       ((DU(RGB[i  ], RGB[i
  +
  1
  ], RGB[i
  +
  2
  ]) 
  +
   
                         DU(RGB[i
  -
  3
  ], RGB[i
  -
  2
  ], RGB[i
  -
  1
  ]) 
  +
  
                         DU(RGB[i  
  -
  WIDTH
  *
  3
  ], RGB[i
  +
  1
  -
  WIDTH
  *
  3
  ], RGB[i
  +
  2
  -
  WIDTH
  *
  3
  ]) 
  +
  
                         DU(RGB[i
  -
  3
  -
  WIDTH
  *
  3
  ], RGB[i
  -
  2
  -
  WIDTH
  *
  3
  ], RGB[i
  -
  1
  -
  WIDTH
  *
  3
  ]))
  /
  4
  );

                V[j] 
  =
   (unsigned 
  char
  )
                       ((DV(RGB[i  ], RGB[i
  +
  1
  ], RGB[i
  +
  2
  ]) 
  +
   
                         DV(RGB[i
  -
  3
  ], RGB[i
  -
  2
  ], RGB[i
  -
  1
  ]) 
  +
  
                         DV(RGB[i  
  -
  WIDTH
  *
  3
  ], RGB[i
  +
  1
  -
  WIDTH
  *
  3
  ], RGB[i
  +
  2
  -
  WIDTH
  *
  3
  ]) 
  +
  
                         DV(RGB[i
  -
  3
  -
  WIDTH
  *
  3
  ], RGB[i
  -
  2
  -
  WIDTH
  *
  3
  ], RGB[i
  -
  1
  -
  WIDTH
  *
  3
  ]))
  /
  4
  );
            }

        }
}
 
 


 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值