主流USB視頻攝像頭的媒體格式為RGB24和I420,如何把這些數(shù)據(jù)變成BMP位圖存下來呢?請看本文。 首先,我們了解一下BMP的格式,BMP有四部分組成,用表格表示如下:
第一部分,文件信息頭的格式如下: typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; 共有14個(gè)字節(jié),其中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個(gè)字節(jié),字段比較多,可以查看MSDN中的說明,對于RGB24的位圖,這個(gè)結(jié)構(gòu)體一般定義如下: 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; 第三部分是調(diào)色板信息,定義如下: typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD; 這部分用來表示RGB各色的強(qiáng)度,一般情況我們不把這一部分寫到文件中。 第四部分就是真正的數(shù)據(jù),比如寬度和高度分別是320和240,這部分?jǐn)?shù)據(jù)的長度應(yīng)該為320*240*3(每個(gè)像素點(diǎn)上有3個(gè)字節(jié),分別用來表示b,g,r的顏色)。 根據(jù)對BMP格式的說明,我們可以輕易的寫出一個(gè)生成BMP圖像的函數(shù),如下所示: // pData為rgb24數(shù)據(jù),width為位圖寬度,height為位圖高度,filename為位圖文件的名字 void Snapshot( BYTE * pData, int width, int height, const char * filename ) { int size = width*height*3; // 每個(gè)像素點(diǎn)3個(gè)字節(jié) // 位圖第一部分,文件信息 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; // 位圖第二部分,數(shù)據(jù)信息 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 ); } 如果要對攝像頭采集到的數(shù)據(jù)進(jìn)行截圖,這里可以直接把數(shù)據(jù)送給這個(gè)函數(shù),就可以生成一張位圖了。當(dāng)然也可以自己生成一段數(shù)據(jù),用圖片的形式保存下來。下面我將給一個(gè)例子,說明怎么生成位圖,本例中說明了如何生成一個(gè)320*240的圖像,黑色的背景,中部有一個(gè)100*100的矩形,代碼如下: void GenerateBMP() { int i=0, j=0; struct { BYTE b; BYTE g; BYTE r; } pRGB[240][320]; // 定義位圖數(shù)據(jù) memset( pRGB, 0, sizeof(pRGB) ); // 設(shè)置背景為黑色 // 在中間畫一個(gè)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的數(shù)據(jù),對于I420,可以先轉(zhuǎn)換成RGB24,然后在生成位圖。 BMP的數(shù)據(jù)量是很大的,沒有經(jīng)過任何的壓縮,我們可以計(jì)算一下,對于一副320*240的圖像,圖片的大小是320*240*3 = 230400 bytes = 225 Kbytes,普通電腦一副屏幕截圖就要1024*768*3=2.3M。所以我們要用一些流行的算法對圖片進(jìn)行壓縮才便于存儲(chǔ),主流USB視頻攝像頭的媒體格式為RGB24和I420,如何把這些數(shù)據(jù)變成BMP位圖存下來呢?請看本文。首先,我們了解一下BMP的格式,BMP有四部分組成,用表格表示如下:
第一部分,文件信息頭的格式如下: typedef struct tagBITMAPFILEHEADER { WORD bfType; DWORD bfSize; WORD bfReserved1; WORD bfReserved2; DWORD bfOffBits; } BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER; 共有14個(gè)字節(jié),其中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個(gè)字節(jié),字段比較多,可以查看MSDN中的說明,對于RGB24的位圖,這個(gè)結(jié)構(gòu)體一般定義如下: 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; 第三部分是調(diào)色板信息,定義如下: typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD; 這部分用來表示RGB各色的強(qiáng)度,一般情況我們不把這一部分寫到文件中。 第四部分就是真正的數(shù)據(jù),比如寬度和高度分別是320和240,這部分?jǐn)?shù)據(jù)的長度應(yīng)該為320*240*3(每個(gè)像素點(diǎn)上有3個(gè)字節(jié),分別用來表示b,g,r的顏色)。 根據(jù)對BMP格式的說明,我們可以輕易的寫出一個(gè)生成BMP圖像的函數(shù),如下所示: // pData為rgb24數(shù)據(jù),width為位圖寬度,height為位圖高度,filename為位圖文件的名字 void Snapshot( BYTE * pData, int width, int height, const char * filename ) { int size = width*height*3; // 每個(gè)像素點(diǎn)3個(gè)字節(jié) // 位圖第一部分,文件信息 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; // 位圖第二部分,數(shù)據(jù)信息 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 ); } 如果要對攝像頭采集到的數(shù)據(jù)進(jìn)行截圖,這里可以直接把數(shù)據(jù)送給這個(gè)函數(shù),就可以生成一張位圖了。當(dāng)然也可以自己生成一段數(shù)據(jù),用圖片的形式保存下來。下面我將給一個(gè)例子,說明怎么生成位圖,本例中說明了如何生成一個(gè)320*240的圖像,黑色的背景,中部有一個(gè)100*100的矩形,代碼如下: void GenerateBMP() { int i=0, j=0; struct { BYTE b; BYTE g; BYTE r; } pRGB[240][320]; // 定義位圖數(shù)據(jù) memset( pRGB, 0, sizeof(pRGB) ); // 設(shè)置背景為黑色 // 在中間畫一個(gè)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的數(shù)據(jù),對于I420,可以先轉(zhuǎn)換成RGB24,然后在生成位圖。 BMP的數(shù)據(jù)量是很大的,沒有經(jīng)過任何的壓縮,我們可以計(jì)算一下,對于一副320*240的圖像,圖片的大小是320*240*3 = 230400 bytes = 225 Kbytes,普通電腦一副屏幕截圖就要1024*768*3=2.3M。所以我們要用一些流行的算法對圖片進(jìn)行壓縮才便于存儲(chǔ),請選中您要保存的內(nèi)容,粘貼到此文本框 |
|