主流USB视频摄像头的媒体格式为RGB24和I420,如何把这些数据变成BMP位图存下来呢?请看本文。 首先,我们了解一下BMP的格式,BMP有四部分组成,用表格表示如下:
第一部分,文件信息头的格式如下: typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; 共有14个字节,其中bfType为文件类型,BMP的类型为0×4d42,也就是字母m和b;bfSize是文件大小,为1,2,3,4部分大小的总和;bfReserved1和bfReserved2为1,2,3部分大小的总和。 第二部分,位图信息头,定义如下: typedef struct tagBITMAPINFOHEADER{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER; 总共40个字节,字段比较多,可以查看MSDN中的说明,对于RGB24的位图,这个结构体一般定义如下: BITMAPINFOHEADER bih; bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = width; bih.biHeight = height; bih.biPlanes = 1; bih.biBitCount = 24; bih.biCompression = 0; bih.biSizeImage = size; bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0; 第三部分是调色板信息,定义如下: typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD; 这部分用来表示RGB各色的强度,一般情况我们不把这一部分写到文件中。 第四部分就是真正的数据,比如宽度和高度分别是320和240,这部分数据的长度应该为320*240*3(每个像素点上有3个字节,分别用来表示b,g,r的颜色)。 根据对BMP格式的说明,我们可以轻易的写出一个生成BMP图像的函数,如下所示: // pData为rgb24数据,width为位图宽度,height为位图高度,filename为位图文件的名字 void Snapshot( BYTE * pData, int width, int height, const char * filename ) { int size = width*height*3; // 每个像素点3个字节 // 位图第一部分,文件信息 BITMAPFILEHEADER bfh; bfh.bfType = 0×4d42; //bm bfh.bfSize = size // data size + sizeof( BITMAPFILEHEADER ) // first section size + sizeof( BITMAPINFOHEADER ) // second section size ; bfh.bfReserved1 = 0; // reserved bfh.bfReserved2 = 0; // reserved bfh.bfOffBits = bfh.bfSize - size; // 位图第二部分,数据信息 BITMAPINFOHEADER bih; bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = width; bih.biHeight = height; bih.biPlanes = 1; bih.biBitCount = 24; bih.biCompression = 0; bih.biSizeImage = size; bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0;
FILE * fp = fopen( filename, “wb” ); if( !fp ) return; fwrite( &bfh, 1, sizeof(BITMAPFILEHEADER), fp ); fwrite( &bih, 1, sizeof(BITMAPINFOHEADER), fp ); fwrite( pData, 1, size, fp ); fclose( fp ); } 如果要对摄像头采集到的数据进行截图,这里可以直接把数据送给这个函数,就可以生成一张位图了。当然也可以自己生成一段数据,用图片的形式保存下来。下面我将给一个例子,说明怎么生成位图,本例中说明了如何生成一个320*240的图像,黑色的背景,中部有一个100*100的矩形,代码如下: void GenerateBMP() { int i=0, j=0; struct { BYTE b; BYTE g; BYTE r; } pRGB[240][320]; // 定义位图数据 memset( pRGB, 0, sizeof(pRGB) ); // 设置背景为黑色 // 在中间画一个100*100的矩形 for( int i=70;i<170;i++ ){ for( int j=110;j<210;j++ ){ pRGB[i][j].r = 0xff; } } // 生成BMP图片 Snapshot( (BYTE *)pRGB, 320, 240, “C:\\rgb.bmp” ); } 生成图片如下所示: 上面所说的都是对于RGB24的数据,对于I420,可以先转换成RGB24,然后在生成位图。 BMP的数据量是很大的,没有经过任何的压缩,我们可以计算一下,对于一副320*240的图像,图片的大小是320*240*3 = 230400 bytes = 225 Kbytes,普通电脑一副屏幕截图就要1024*768*3=2.3M。所以我们要用一些流行的算法对图片进行压缩才便于存储,主流USB视频摄像头的媒体格式为RGB24和I420,如何把这些数据变成BMP位图存下来呢?请看本文。首先,我们了解一下BMP的格式,BMP有四部分组成,用表格表示如下:
第一部分,文件信息头的格式如下: typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; 共有14个字节,其中bfType为文件类型,BMP的类型为0×4d42,也就是字母m和b;bfSize是文件大小,为1,2,3,4部分大小的总和;bfReserved1和bfReserved2为1,2,3部分大小的总和。 第二部分,位图信息头,定义如下: typedef struct tagBITMAPINFOHEADER{ DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER; 总共40个字节,字段比较多,可以查看MSDN中的说明,对于RGB24的位图,这个结构体一般定义如下: BITMAPINFOHEADER bih; bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = width; bih.biHeight = height; bih.biPlanes = 1; bih.biBitCount = 24; bih.biCompression = 0; bih.biSizeImage = size; bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0; 第三部分是调色板信息,定义如下: typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD; 这部分用来表示RGB各色的强度,一般情况我们不把这一部分写到文件中。 第四部分就是真正的数据,比如宽度和高度分别是320和240,这部分数据的长度应该为320*240*3(每个像素点上有3个字节,分别用来表示b,g,r的颜色)。 根据对BMP格式的说明,我们可以轻易的写出一个生成BMP图像的函数,如下所示: // pData为rgb24数据,width为位图宽度,height为位图高度,filename为位图文件的名字 void Snapshot( BYTE * pData, int width, int height, const char * filename ) { int size = width*height*3; // 每个像素点3个字节 // 位图第一部分,文件信息 BITMAPFILEHEADER bfh; bfh.bfType = 0×4d42; //bm bfh.bfSize = size // data size + sizeof( BITMAPFILEHEADER ) // first section size + sizeof( BITMAPINFOHEADER ) // second section size ; bfh.bfReserved1 = 0; // reserved bfh.bfReserved2 = 0; // reserved bfh.bfOffBits = bfh.bfSize - size; // 位图第二部分,数据信息 BITMAPINFOHEADER bih; bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = width; bih.biHeight = height; bih.biPlanes = 1; bih.biBitCount = 24; bih.biCompression = 0; bih.biSizeImage = size; bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0;
FILE * fp = fopen( filename, “wb” ); if( !fp ) return; fwrite( &bfh, 1, sizeof(BITMAPFILEHEADER), fp ); fwrite( &bih, 1, sizeof(BITMAPINFOHEADER), fp ); fwrite( pData, 1, size, fp ); fclose( fp ); } 如果要对摄像头采集到的数据进行截图,这里可以直接把数据送给这个函数,就可以生成一张位图了。当然也可以自己生成一段数据,用图片的形式保存下来。下面我将给一个例子,说明怎么生成位图,本例中说明了如何生成一个320*240的图像,黑色的背景,中部有一个100*100的矩形,代码如下: void GenerateBMP() { int i=0, j=0; struct { BYTE b; BYTE g; BYTE r; } pRGB[240][320]; // 定义位图数据 memset( pRGB, 0, sizeof(pRGB) ); // 设置背景为黑色 // 在中间画一个100*100的矩形 for( int i=70;i<170;i++ ){ for( int j=110;j<210;j++ ){ pRGB[i][j].r = 0xff; } } // 生成BMP图片 Snapshot( (BYTE *)pRGB, 320, 240, “C:\\rgb.bmp” ); } 生成图片如下所示: 上面所说的都是对于RGB24的数据,对于I420,可以先转换成RGB24,然后在生成位图。 BMP的数据量是很大的,没有经过任何的压缩,我们可以计算一下,对于一副320*240的图像,图片的大小是320*240*3 = 230400 bytes = 225 Kbytes,普通电脑一副屏幕截图就要1024*768*3=2.3M。所以我们要用一些流行的算法对图片进行压缩才便于存储,请选中您要保存的内容,粘贴到此文本框 |
|