因為公司的主要業務是圖像識別相關的,因此對圖像處理、識別是我學習的重點。雖然寫程序也不少年了,但是對於圖像處理領域,我還是一個新兵。對很多基礎的概念也還是存在盲區,所以想在邊學邊做的過程中,對一些概念的梳理和學習心得進行記錄。
BMP文件格式
BMP(Bitmap-File)圖形文件,又叫位圖文件,是Windows采用的圖形文件格式,在Windows環境下運行的所有圖象處理軟件都支持BMP圖象文件格式。Windows系統內部各圖像繪制操作都是以BMP為基礎的。一個BMP文件由四部分組成:
- 位圖文件頭
- 位圖信息段
- 調色板
- 位圖數據
一個BMP文件,可以用代碼表示,如下:
typedef struct tagBITMAP_FILE{
BITMAPFILEHEADER bitmapheader;
BITMAPINFOHEADER bitmapinfoheader;
PALETTEENTRY palette[256];
UCHAR *buffer; //UCHAR 大小1字節(同BYTE), 在VC6下
} BITMAP_FILE;
1、 BMP文件頭:BITMAPFILEHEADER
typedef struct tagBITMAPFILEHEADER { // bmfh
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
bfType | 說明文件的類型,該值必需是0x4D42,也就是字符'BM',否則表示根本不是BMP |
bfSize | 說明該位圖文件的大小,用字節為單位 |
bfReserved1 | 保留,必須設置為0 |
bfReserved2 | 保留,必須設置為0 |
bfOffBits | 說明從文件頭開始到實際的圖象數據之間的字節的偏移量。這個參數是非常有用的,因為位圖信息頭和調色板的長度會根據不同情況而變化,所以你可以用這個偏移值迅速的從文件中讀取到位數據。 |
下面用Notepad++打開一個BMP文件:
這里:
bfType:0X040d(BM)
bfSize:0X0004a436 == 304182字節 == 297K字節,說明這個位圖文件的大小為297K字節,和我看到的符合:
跳過4字節的保留字節,
bfOffBits:0X00000036 == 54字節
2、位圖信息段:BITMAPINFOHEADER
typedef struct tagBITMAPINFOHEADER{ // bmih
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
biSize | 說明BITMAPINFOHEADER結構所需要的字節數 |
biWidth | 說明圖象的寬度,以象素為單位 |
biHeight | 說明圖象的高度,以象素為單位。注:這個值除了用於描述圖像的高度之外,它還有另一個用處,就是指明該圖像是倒向的位圖,還是正向的位圖。如果該值是一個正數,說明圖像是倒向的,即:數據的第一行其實是圖像的最后一行,如果該值是一個負數,則說明圖像是正向的。大多數的BMP文件都是倒向的位圖,也就是時,高度值是一個正數。 |
biPlanes | 表示bmp圖片的平面屬,顯然顯示器只有一個平面,所以恆等於1 |
biBitCount | 說明比特數/象素,其值為1、4、8、16、24、或32。 |
biCompression | 說明圖象數據壓縮的類型,其中: BI_RGB:沒有壓縮 BI_RLE8:每個象素8比特的RLE壓縮編碼,壓縮格式由2字節組成(重復象素計數和顏色索引); BI_RLE4:每個象素4比特的RLE壓縮編碼,壓縮格式由2字節組成 BI_BITFIELDS:每個象素的比特由指定的掩碼決定。 BI_JPEG:JPEG格式 |
biSizeImage | 說明圖象的大小,以字節為單位。當用BI_RGB格式時,可設置為0。 |
biXPelsPerMeter | 說明水平分辨率,用象素/米表示。 |
biYPelsPerMeter | 說明垂直分辨率,用象素/米表示。 |
biClrUsed | 說明位圖實際使用的彩色表中的顏色索引數(設為0的話,則說明使用所有調色板項)。 |
biClrImportant | 說明對圖象顯示有重要影響的顏色索引的數目,如果是0,表示都重要。 |
biSize:位圖信息段結構BITMAPINFOHEADER的字節數 0x00000028 ==40字節
biWidth:352像素;
biHeight:288像素;
和圖片信息相符:
biPlanes:1
biBitCount :24位圖
biCompression:沒有壓縮;
biSizeImage:0x4a400 == 304128字節 ,當用BI_RGB格式時,可設置為0,為什么這里是304128呢?這里的304128是怎么出來的呢?
原來biSizeImage = biWidth*biHeight*每個像素的字節數
那么我們這里應該是:352*288*24/8 = 304128。(我們這里的位數/像素為24,所以每個像素的字節數為3)
注:這里的biWidth必須是4的倍數,如果不是4的倍數,則需要取4的倍數,比如241,則取244;為什么必須是4的倍數?這里涉及到一個行對齊的問題:
由於Windows在進行行掃描的時候最小的單位為4個字節,所以當
圖片寬 X 每個像素的字節數 != 4的整數倍
時要在每行的后面補上缺少的字節,以0填充
biXPelsPerMeter:0x00000000
biYPelsPerMeter:0x00000000
biClrUsed:0x00000000 使用所有調色板項
biClrImportant:00000000
3、調色板
上面這張BMP圖片是否有調色板呢?答案是否定的。
因為從bfOffBits = 54字節可以看出,剛好是sizeof(BITMAPFILEHEADER )+sizeof(BITMAPINFOHEADER);
那么究竟調色板是什么東西?有什么用?為什么我們這種圖片不帶調試板呢?
我們先來說說三元色RGB概念。
我們知道,自然界中的所有顏色都可以由紅、綠、藍(R,G,B)組合而成。有的顏色含有紅色成分多一些,如深紅;有的含有紅色成分少一些,如淺紅。針對含有紅色成分的多少,可以分成0到255共256個等級,0級表示不含紅色成分;255級表示含有100%的紅色成分。同樣,綠色和藍色也被分成256級。這種分級概念稱為量化。
表1.1 常見顏色的RGB組合值
當一幅圖中每個象素賦予不同的RGB值時,能呈現出五彩繽紛的顏色了,這樣就形成了彩色圖。
讓我們舉例說明什么是調色板?為什么需要調色板?
有一個長寬各為200個象素,顏色數為16色的彩色圖,每一個象素都用R、G、B三個分量表示。因為每個分量有256個級別,要用8位(bit),即一個字節(byte)來表示,所以每個象素需要用3個字節。整個圖象要用200×200×3,約120k字節,可不是一個小數目呀!如果我們用下面的方法,就能省的多。
因為是一個16色圖,也就是說這幅圖中最多只有16種顏色,我們可以用一個表:表中的每一行記錄一種顏色的R、G、B值。這樣當我們表示一個象素的顏色時,只需要指出該顏色是在第幾行,即該顏色在表中的索引值。舉個例子,如果表的第0行為255,0,0(紅色),那么當某個象素為紅色時,只需要標明0即可。
讓我們再來計算一下:16種狀態可以用4位(bit)表示,所以一個象素要用半個字節。整個圖象要用200×200×0.5,約20k字節,再加上表占用的字節為3×16=48字節.整個占用的字節數約為前面的1/6,省很多吧?
這張R、G、B的表,就是我們常說的調色板(Palette),另一種叫法是顏色查找表LUT(Look Up Table),似乎更確切一些。調色板在windows里的結構定義如下:
typedef struct tagPALETTEENTRY { // pe
BYTE peRed;
BYTE peGreen;
BYTE peBlue;
BYTE peFlags;
} PALETTEENTRY;
那么為什么我們這張BMP不帶調色板呢?
是因為我們這張BMP是24位真彩色的BMP,所謂真彩色圖(true color),就是它的顏色數高達256×256×256種,也就是說包含我們上述提到的R、G、B顏色表示方法中所有的顏色。真彩色圖並不是說一幅圖包含了所有的顏色,而是說它具有顯示所有顏色的能力,即最多可以包含所有的顏色。表示真彩色圖時,每個象素直接用R、G、B三個分量字節表示,而不采用調色板技術。原因很明顯:如果用調色板,表示一個象素也要用24位,這是因為每種顏色的索引要用24位(因為總共有256×256×256種顏色,即調色板有256×256×256行),和直接用R,G,B三個分量表示用的字節數一樣,不但沒有任何便宜,還要加上一個256×256×256×3個字節的大調色板。所以真彩色圖直接用R、G、B三個分量表示,它又叫做24位色圖。
這么看來BMP文件不能一概而論了,其是否用調色板或者是RGB掩碼,位圖數據中的數據的真正含義直接與biBitCount 有關,不同類型的位圖,其中的設計原理也不同,下面對此作一個對比:
4、位圖數據
上面基本把調色板及相關取色策略梳理清楚了,接着回到我們上面的例子。24位BMP圖,每3個字節表示一個像素,3個字節分別表示R、G、B的分量值
這里每3個字節表示一個像素的顏色,注意:由於位圖信息頭中的圖像高度是正數,所以位圖數據在文件中的排列順序是從左下角到右上角,以行為主序排列的。
參考了BMP文件格式詳解(BMP file format)的學習思路,對BMP格式進行了梳理和學習。
參考資源: