在影像處理程式開發中,常會遇到將一幅彩色映像轉換成灰階映像的情況,筆者在最近的一個項目中便遇到了這點。經過一翻努力最終解決,想想有必要分享一下,於是便寫下此文。在本文中,將向各位讀者介紹兩種實現這一變換的方法,這也是筆者先後使用的兩種方法。本文的例子使用C#語言編寫,使用的整合式開發環境是Visual Studio 2005。
第一種,直接調用GetPixel/SetPixel方法。
我們都知道,映像在電腦中的存在形式是位元影像,也即一個矩形點陣,每一個點被稱為一個像素。在這種方法中,我們通過GDI+中提供的GetPixel方法來讀取像素的顏色,並加以計算,然後再使用SetPixel方法將計算後的顏色值應用到相應的像素上去,這樣便可以得到灰階映像。
上邊提到的“計算”便是指得到灰階映像的計算,其公式是:
r = (像素點的紅色分量 + 像素點的綠色分量 + 像素點的藍色分量) / 3
最後得到的r便是需要應用到原像素點的值。具體的編程實現也非常的簡單,只需要遍曆位元影像的每一個像素點,然後使用SetPixel方法將上邊計算得到的值應用回去即可。主要代碼如下所示:
Color currentColor;
int r;
Bitmap currentBitmap = new Bitmap(picBox.Image);
Graphics g = Graphics.FromImage(currentBitmap);
for (int w = 0; w < currentBitmap.Width; w++)
{
for (int h = 0; h < currentBitmap.Height; h++)
{
currentColor = currentBitmap.GetPixel(w, h);
r = (currentColor.R + currentColor.G + currentColor.B) / 3;
currentBitmap.SetPixel(w, h, Color.FromArgb(r, r, r));
}
}
g.DrawImage(currentBitmap, 0, 0);
picBox.Image = currentBitmap;
g.Dispose();
以上代碼非常簡單,不需要做太多的解釋。需要注意的是,在使用SetPixel方法的時候,其三色分量值均為我們公式計算得到的結果r。
第二種,使用ColorMatrix 類
如果讀者親自測試過第一種方式,就會發現通過迴圈遍曆位元影像所有像素,並使用SetPixel方法來修改每個像素的各顏色分量是非常耗時的。而現在介紹的第二種方法則是一種更好的實現方式――使用ColorMatrix類。
在介紹具體的實現之前,有必要先向讀者介紹一下相關的背景知識。在GDI+中,顏色使用32位來儲存,紅色、綠色、藍色和透明度分別佔8位,因此每個分量可以有28=256(0~255)種取值。這樣一來,一個顏色資訊就可以用一個向量 (Red,Green,Blue,Alpha) 來表示,例如不透明的紅色可以表示成為(255,0,0,255)。向量中的Alpha值用來表示顏色的透明度,0 表示完全透明,255 表示完全不透明。到這裡讀者朋友可能應該想到了,我們只需要按照一定的規則改變這些向量裡各個分量的值,便可以得到各種各樣的顏色變換效果,所以我們獲得灰階圖這個要求也就能夠實現了。
現在關鍵問題便是按照什麼規則來改變各分量值。在上邊介紹的第一種方式中我們提到了計算灰階映像的公式,其實它還有另外一個表示方式,如下:
r = 像素點的紅色分量×0.299 + 像素點的綠色分量×0.587 + 像素點的藍色分量×0.114
這一公式便是我們的規則。我們只需要對每一個顏色向量做上邊的變化即可。這裡的變換就需要用到ColorMatrix類,此類定義在System.Drawing.Imaging名字空間中,它定義了一個5×5的數組,用來記錄將和顏色向量進行乘法計算的值。ColorMatrix對象配合ImageAttributes類一起使用,實際上GDI+裡的顏色變換就是通過ImageAttributes對象的SetColorMatrix 進行的。
第二種的主要實現代碼如下:
Bitmap currentBitmap = new Bitmap(picBox.Image);
Graphics g = Graphics.FromImage(currentBitmap);
ImageAttributes ia = new ImageAttributes();
float[][] colorMatrix = {
new float[] {0.299f, 0.299f, 0.299f, 0, 0},
new float[] {0.587f, 0.587f, 0.587f, 0, 0},
new float[] {0.114f, 0.114f, 0.114f, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}};
ColorMatrix cm = new ColorMatrix(colorMatrix);
ia.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
g.DrawImage(currentBitmap, new Rectangle(0, 0, currentBitmap.Width, currentBitmap.Height), 0, 0, currentBitmap.Width, currentBitmap.Height, GraphicsUnit.Pixel, ia);
picBox.Image = currentBitmap;
g.Dispose();
細心的讀者可能會問,明明顏色是由4個分量組成的,那麼與之相乘的矩陣也應該是一個4×4的矩陣啊,為什麼這裡定義的顏色變換矩陣卻是5×5的呢?這個問題可以參考MSDN上的一篇文章(《使用顏色矩陣對單色進行變換》)便可得解。
請讀者朋友們輸入以上代碼並編譯執行。大家會發現其變換速度極快,幾乎是瞬間完成。其實,只要知道了矩陣各行、列必要的參數值,那麼使用ColorMatrix來實現顏色變換是非常方便的。諸如讓某色透明這樣的功能用這種方式實現起來也是非常方便高效的。
上邊簡要地介紹了兩種獲得灰階映像的方法。在實際開發中,使用第二種方式遠遠優於第一種,其在運算速度方面的優勢,是第一種遠遠沒法比的。
參考 :
http://blog.csdn.net/maozefa/archive/2007/12/27/1995949.aspx
<GDI+ for VCL基礎 -- 顏色調整矩陣ColorMatrix詳解>