第一種,直接調(diào)用GetPixel/SetPixel方法。
我們都知道,圖像在計(jì)算機(jī)中的存在形式是位圖,也即一個(gè)矩形點(diǎn)陣,每一個(gè)點(diǎn)被稱為一個(gè)像素。在這種方法中,我們通過GDI+中提供的GetPixel方法來讀取像素的顏色,并加以計(jì)算,然后再使用SetPixel方法將計(jì)算后的顏色值應(yīng)用到相應(yīng)的像素上去,這樣便可以得到灰度圖像。
上邊提到的“計(jì)算”便是指得到灰度圖像的計(jì)算,其公式是:
r = (像素點(diǎn)的紅色分量 + 像素點(diǎn)的綠色分量 + 像素點(diǎn)的藍(lán)色分量) / 3
最后得到的r便是需要應(yīng)用到原像素點(diǎn)的值。具體的編程實(shí)現(xiàn)也非常的簡(jiǎn)單,只需要遍歷位圖的每一個(gè)像素點(diǎn),然后使用SetPixel方法將上邊計(jì)算得到的值應(yīng)用回去即可。主要代碼如下所示:
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();
以上代碼非常簡(jiǎn)單,不需要做太多的解釋。需要注意的是,在使用SetPixel方法的時(shí)候,其三色分量值均為我們公式計(jì)算得到的結(jié)果r。
如果讀者親自測(cè)試過第一種方式,就會(huì)發(fā)現(xiàn)通過循環(huán)遍歷位圖所有像素,并使用SetPixel方法來修改每個(gè)像素的各顏色分量是非常耗時(shí)的。而現(xiàn)在介紹的第二種方法則是一種更好的實(shí)現(xiàn)方式――使用ColorMatrix類。
在介紹具體的實(shí)現(xiàn)之前,有必要先向讀者介紹一下相關(guān)的背景知識(shí)。在GDI+中,顏色使用32位來保存,紅色、綠色、藍(lán)色和透明度分別占8位,因此每個(gè)分量可以有28=256(0~255)種取值。這樣一來,一個(gè)顏色信息就可以用一個(gè)向量 (Red,Green,Blue,Alpha) 來表示,例如不透明的紅色可以表示成為(255,0,0,255)。向量中的Alpha值用來表示顏色的透明度,0 表示完全透明,255 表示完全不透明。到這里讀者朋友可能應(yīng)該想到了,我們只需要按照一定的規(guī)則改變這些向量里各個(gè)分量的值,便可以得到各種各樣的顏色變換效果,所以我們獲得灰度圖這個(gè)要求也就能夠?qū)崿F(xiàn)了。
現(xiàn)在關(guān)鍵問題便是按照什么規(guī)則來改變各分量值。在上邊介紹的第一種方式中我們提到了計(jì)算灰度圖像的公式,其實(shí)它還有另外一個(gè)表示方式,如下:
r = 像素點(diǎn)的紅色分量×0.299 + 像素點(diǎn)的綠色分量×0.587 + 像素點(diǎn)的藍(lán)色分量×0.114
這一公式便是我們的規(guī)則。我們只需要對(duì)每一個(gè)顏色向量做上邊的變化即可。這里的變換就需要用到ColorMatrix類,此類定義在System.Drawing.Imaging名字空間中,它定義了一個(gè)5×5的數(shù)組,用來記錄將和顏色向量進(jìn)行乘法計(jì)算的值。ColorMatrix對(duì)象配合ImageAttributes類一起使用,實(shí)際上GDI+里的顏色變換就是通過ImageAttributes對(duì)象的SetColorMatrix 進(jìn)行的。
第二種的主要實(shí)現(xiàn)代碼如下:
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();
細(xì)心的讀者可能會(huì)問,明明顏色是由4個(gè)分量組成的,那么與之相乘的矩陣也應(yīng)該是一個(gè)4×4的矩陣啊,為什么這里定義的顏色變換矩陣卻是5×5的呢?這個(gè)問題可以參考MSDN上的一篇文章(《使用顏色矩陣對(duì)單色進(jìn)行變換》)便可得解。
請(qǐng)讀者朋友們輸入以上代碼并編譯執(zhí)行。大家會(huì)發(fā)現(xiàn)其變換速度極快,幾乎是瞬間完成。其實(shí),只要知道了矩陣各行、列必要的參數(shù)值,那么使用ColorMatrix來實(shí)現(xiàn)顏色變換是非常方便的。諸如讓某色透明這樣的功能用這種方式實(shí)現(xiàn)起來也是非常方便高效的。
上邊簡(jiǎn)要地介紹了兩種獲得灰度圖像的方法。在實(shí)際開發(fā)中,使用第二種方式遠(yuǎn)遠(yuǎn)優(yōu)于第一種,其在運(yùn)算速度方面的優(yōu)勢(shì),是第一種遠(yuǎn)遠(yuǎn)沒法比的。
聯(lián)系客服