YUV420 和RGB之间的转换的程序。
测试使用的cif文件:http://trace.eas.asu.edu/yuv/tempete.zip
#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 ); } } }