袁智勇 劉文林
摘? 要:該文首先介紹了灰度位圖的背景知識,包括灰度位圖的定義、特點、應用范圍。接著介紹了全彩色和灰度色彩轉換的算法。最后演示了基于GDI+的,將全彩色位圖轉換為灰度位圖的核心代碼。該代碼使用了GDI+的Bitmap類,并通過其成員函數ConvertFormat進行位圖格式轉換。特點是代碼高度簡單,程序員無須了解位圖格式轉換,顏色轉換等的細節,大大降低了編碼難度和復雜度。
關鍵詞:灰度位圖;轉換;GDI+
中圖分類號:TP391? ? ? ? ? ? ? 文獻標志碼:A
0 引言
網上關于灰度位圖(grayscale bitmap)的介紹雖然不少,但大多數都只是觸及點皮毛,沒有交代清楚其原理,使初學者一知半解。該文對灰度位圖做了一個原理性的介紹,使初學者徹底弄明白灰度圖像的原理。同樣的,網上關于彩色圖像轉換為灰度圖像的代碼也很多,但過于煩瑣,該文也介紹了1種簡便的轉換方法。
1 灰度位圖的定義
顧名思義,灰度位圖的所有像素都是灰色的。灰色是一類特殊的顏色,其R(紅色),G(綠色),B(藍色)三原色分量的值都是一樣的。如果以(R,G,B)的格式表示顏色,那么(0,0,0),(1,1,1),(2,2,2),……,(254,254,254),(255,255,255),總共256種顏色都是灰色。全0的黑色和全255的白色都是灰色的特例,其中黑色最暗,白色最亮。R,G,B三原色分量的大小代表了三原色的亮度,因此各種灰色的差別在于其亮度不同。
因為顏色僅限于256種灰色(這256種灰色構成灰度位圖的顏色表),為了減少存儲空間,灰度位圖統一使用索引位圖的格式來存儲。也就是說,灰度位圖的像素值不是直接存儲為24 bit的(R,G,B)顏色,而是存儲為顏色表的索引號。例如如果某個灰度位圖的像素值是1,那么它對應的實際顏色是顏色表中編號為1的顏色,也就是(1,1,1)。可以看出,索引號同時代表了對應灰度顏色的亮度。例如,當索引號為0時,對應的顏色是黑色(0,0,0),亮度為0;當索引號為255時,對應的顏色時白色(255,255,255),亮度為255。表達256種索引號只需8 bit(1字節)數據,而直接表達(R,G,B)顏色需要24 bit(3字節)數據,所以使用索引位圖格式能大大節省存儲空間。
將有16 777 216(224)種顏色的24 bit全彩色位圖轉換為只有256(28)種灰色的灰度位圖無疑會丟失圖像的細節,盡管如此,灰度位圖的應用卻非常廣泛。
首先,這種轉換能將彩色圖像轉換為黑白圖像,這是一種非常有用的特效。
其次,這種轉換在丟失細節的同時,往往能使圖像中物體的輪廓變得更明顯。就像黑白證件照的底片,雖然細節很模糊,但人物的輪廓卻很明顯。這使得灰度位圖在文字識別、圖像識別中得到了廣泛的應用。
2 顏色轉換
將24bit全彩色位圖轉換為8bit灰色位圖的原則是將彩色轉換為與之最接近的灰色。關于什么是最接近,在不同的場合下,解讀是不同的。對于灰度圖像轉換,我們是依據全彩色圖像的亮度,將其轉換為同等亮度的灰度顏色。其公式為:
I= R× 0.299 + G×0.587 + B×0.114 ? ? ? ? ? ? ? (1)
I代表索引號。前面提到過,索引號同時代表了對應灰度顏色的亮度。所以上面的公式實際上按照全彩色R、G、B顏色分量的亮度,將其映射到對應亮度的灰度顏色。0.299、0.587 、0.114分別代表了R、G、B顏色分量的權重。可以看出,綠色分量的權重最大,這是因為人類對綠色亮度的變化更敏感。
3 關于GDI+
GDI+是微軟針對傳統的GDI(Graphic Device Interface,圖形設備界面)技術的改進。和GDI不同,GDI+的編程接口是面向對象的,將底層代碼封裝于各種類中,這使得編程難度大大降低。其次,在圖像格式轉換、圖像變換等方面引入了很多新的類成員函數,程序員簡單調用這些函數就可以完成以前通過GDI無法直接完成的工作。
舉個例子,在GDI+中位圖被封裝為Bitmap類,以下C++代碼可以讀取硬盤上的位圖文件test.bmp(假定其為24 bit全彩色位圖),輕松構造一個Bitmap類:
Bitmap bmp=new Bitmap(L”C:\\test.bmp”);
下一步,我們可以通過Bitmap的類成員函數操作test.bmp,例如將其轉換為灰度位圖。對應的函數如下:
ConvertFormat(PixelFormat format,
DitherType dithertype,PaletteType palettetype,
ColorPalette *palette,REAL alphaThresholdPercent);
format參數指定轉換后的位圖的格式,須設置為PixelFormat8bppIndexed(8bit索引位圖)。
dithertype參數指定抖動顏色采用的方法,須設置為DitherTypeSolid(抖動到實體顏色)。
palettetype參數指定灰度位圖使用的顏色表(在GDI+中稱為調色板)的類型,須設置為PaletteTypeCustom(自定義調色板)。
palette為指向灰度位圖的顏色表數據結構指針,調用這個函數的關鍵一步是構造顏色表。如何構造灰度圖像的顏色表請參考下一節中的核心代碼。
alphaThresholdPercent參數和像素透明化處理有關,一般轉換不涉及像素透明化處理,須設置為0。
4 核心代碼
代碼使用visual C++開發,因為僅為演示代碼,其他不重要的代碼都已經略去。
void GrayScale(Bitmap* bmp){
void* p=malloc(sizeof(Gdiplus::ColorPalette)+255*sizeof(ARGB));
Gdiplus::ColorPalette*cpal=(Gdiplus::ColorPalette*)p;
for(int i=0;i<256;i++)cpal->Entries[i]=Color::MakeARGB(0,i,i,i);//構造顏色表
cpal->Flags=PaletteFlagsGrayScale;
cpal->Count=256;
bmp->ConvertFormat(PixelFormat8bppIndexed,DitherTypeSolid,PaletteTypeCustom,cpal,0);
free(p);}
顏色表數據結構包含2個部分:頭和數據。頭部有2個字段Flags和Count。Flags設置為PaletteFlagsGrayScale,表示顏色表是灰度位圖顏色表。Count設置為256,表示有256中灰度顏色。數據部分是256種灰度顏色,從(0,0,0)一直到(255,255,255)。要注意的是,在標準顏色表中,每種顏色占用32 bit空間,所以要通過宏MakeARGB擴充到32 bit。
5 結語
通過GDI+將全彩色圖像轉化為灰度圖像是非常簡單的,無須和位圖格式細節打交道,也無須直接用公式進行色彩轉換,非常簡便高效。
參考文獻
[1]周鳴揚,趙景亮.精通GDI+編程[M].北京:清華大學出版社,2004.
[2]Ivor Horton.Visual C++2010入門經典(第5版)[M].北京:清華大學出版社,2010.