程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> GDI+中常見的幾個問題(9)

GDI+中常見的幾個問題(9)

編輯:關於.NET

今天來講講上個星期遺留下來的東西:ColorMatrix。

9. Color Matrix

圖像的本質是什麼?對不同的人來說這是不同的東西。在計算機的世界中,啥東西都是數 據,圖像也是一種數據。從自然界的光變成計算機的數據,需要通過采樣和量化的處理。圖 像在計算機中,其實是一個二維數組,從數學上來說,這其實是一個矩陣。圖像中的每一個 點都是個四維向量,也就是(R,G,B,A), 在RGBA色彩空間中,我們可以使用一個矩陣對每一 個點(R,G,B,A)作矩陣乘法運算,這樣就可以對圖像色彩進行變換。這種做法其實是從三維空 間坐標系中的仿射變換類推過來的。具體關於仿射變換,可以參考 http://en.wikipedia.org/wiki/Affine_transformation對於仿射變換的介紹。

色彩矩陣就是這個用來對色彩作仿射變換的矩陣。這是一個5*5的矩陣,如圖

其實和在空間中的仿射變換完全一樣,可以實現縮放,旋轉,平移等功能。我看到網上有 個人寫了一篇深入淺出的文章"GDI+ ColorMatrix的完全揭秘與代碼實現" http://blog.csdn.net/maozefa/archive/2008/09/08/2896752.aspx 寫得不錯,只是沒有 理解到ColorMatrix應用的精髓。簡單套用了一些什麼顏色剪切,顏色旋轉,顏色平移的概念 ,這些東西其實在三維空間中很好理解,但是在色彩空間中,就完全不是那麼回事情了,什 麼叫做顏色旋轉60度呢? 這東西忽悠人很有用,只是看完了還是不知道怎麼用,有興趣的同 學可以去看看。我下面舉幾個例子,說明ColorMatrix的具體應用。

a.灰度化

灰度化是指去除圖像的彩色信息,講所有的色調歸為0,所有的飽和度也歸為零。這個世 界上有很多種不同的灰度化的算法,隨便寫個算法,弄篇paper搞個碩士畢業應該不成問題, 比如說所有的顏色替換成R' = G' = B' = (R+B+G)/3。有一種很通用的灰度化算法如下,這 其實是NTSC的色彩權重。

R'=B'=G' = 0.299*R + 0.587*G + 0.114*B

那如果我們要使用ColorMatrix, 可以用以下的矩陣:

// ColorMatrix elements
float[][] ptsArray =
{
new float[] {0.299f, 0.299f, 0.299f, 0, 0},
new float[] {0.518f, 0.518f, 0.518f, 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}
};

再引用一下博客園裡的這篇文章 http://www.cnblogs.com/sunbingzibo/archive/2008/09/11/1289260.html,如果用他的算 法,那麼矩陣如下  

// ColorMatrix elements
float[][] ptsArray =
{
new float[] {cr,  cr, cr, 0, 0},
new float[] {cg, cg, cg, 0, 0},
new float[] {cb, cb, cb, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
};

b.調整色彩

使用ColorMatrix調整色彩很簡單,用m11對紅色乘一個系數,用m51對紅色加一個值,這 樣就可以簡單地調整紅色。其他B,G,A通道以此類推。例如下面這個矩陣可以把增加紅色25.5 個像素(如果使用24bppArgb):

// ColorMatrix elements
float[][] ptsArray =
{
 new float[] {1, 0, 0, 0, 0},
 new float[] {0, 1, 0, 0, 0},
 new float[] {0, 0, 1, 0, 0},
 new float[] {0, 0, 0, 1, 0},
 new float[] {0.1f, 0, 0, 0, 1}
};

c. 調整 亮度, 可以用以下矩陣,將每個通道增加25.5的亮度

// ColorMatrix  elements
float[][] ptsArray =
{
 new float[] {1, 0, 0, 0, 0},
 new float[] {0, 1, 0, 0, 0},
 new float[] {0, 0, 1, 0, 0},
 new float[] {0, 0, 0, 1, 0},
 new float[] {0.1f, 0.1f, 0.1f, 0, 1}
};

d.調整 對比度,可以使用以下矩陣,將每個通道升高10%的對比度

// ColorMatrix  elements
float[][] ptsArray =
{
 new float[] {1.1f, 0, 0, 0, 0},
 new float[] {0, 1.1f, 0, 0, 0},
 new float[] {0, 0, 1.1f, 0, 0},
 new float[] {0, 0, 0, 1, 0},
 new float[] {0, 0, 0, 0, 1}
};

很不幸 ,這是錯的。這個算法裡面有個關鍵的問題是Overflow,如果我們直接使用這個矩陣,你會看 到圖像上會有溢出,導致你的圖像慘不忍睹。我在網上查到有個很發指的做法可以解決這個 問題,雖然發指,但是能解決!就是把最下面的項修正一點點,這樣圖像就不溢出了。看下 面這個矩陣。

// ColorMatrix elements
float[][] ptsArray =
{
 new float[] {1.5f, 0, 0, 0, 0},
 new float[] {0, 1.5f, 0, 0, 0},
 new float[] {0, 0, 1.5f, 0, 0},
 new float[] {0, 0, 0, 1, 0},
 new float[] {0.001f, 0.001f, 0.001f, 0, 1}
};

e.調整 飽和度

這個矩陣比較復雜,飽和度需要通過不同的色彩權值來修正。我這裡只提供一 個能用的矩陣,具體可以參考這篇 paper:http://www.graficaobscura.com/matrix/index.html

float rwgt =  0.3086f;
float gwgt = 0.6094f;
float bwgt = 0.0820f;

float s = 1.2f;
float[][] ptsArray =
{
 new float[] {(1f-s)*rwgt+s, (1f-s)*rwgt, (1f-s)*rwgt, 0, 0},
 new float[] {(1f-s)*gwgt, (1f-s)*gwgt +s, (1f-s)*gwgt, 0, 0},
 new float[] {(1f-s)*bwgt, (1f-s)*bwgt, (1f-s)*bwgt + s, 0, 0},
 new float[] {0, 0, 0, 1, 0},
 new float[] {0, 0, 0, 0, 1}
};

講了那 麼多個矩陣,最後讓我們來看看在GDI+裡面ColorMatrix這個類到底怎麼用:

FileStream fs = new FileStream(image, FileMode.Open,  FileAccess.Read);
Image img = Image.FromStream(fs, false, false);
Bitmap bmp = new Bitmap(img);
img.Dispose();
fs.Close();

Graphics g = this.CreateGraphics();

float rwgt = 0.3086f;
float gwgt = 0.6094f;
float bwgt = 0.0820f;

float s = 1.2f;
float[][] ptsArray =
{
 new float[] {(1f-s)*rwgt+s, (1f-s)*rwgt, (1f-s)*rwgt, 0, 0},
 new float[] {(1f-s)*gwgt, (1f-s)*gwgt +s, (1f-s)*gwgt, 0, 0},
 new float[] {(1f-s)*bwgt, (1f-s)*bwgt, (1f-s)*bwgt + s, 0, 0},
 new float[] {0, 0, 0, 1, 0},
 new float[] {0, 0, 0, 0, 1}
};

// Create a ColorMatrix
ColorMatrix matrix = new ColorMatrix(ptsArray);

ImageAttributes attr = new ImageAttributes();
// Set color matrix
attr.SetColorMatrix(matrix,
ColorMatrixFlag.Default,
ColorAdjustType.Default);
// Draw image with no affects
g.DrawImage(bmp, 0, 0, 200, 150);
// Draw image with ImageAttributes
g.DrawImage(bmp,
new Rectangle(205, 0, 200, 150),
0, 0, bmp.Width, bmp.Height,
GraphicsUnit.Pixel, attr);
// Dispose
bmp.Dispose();
g.Dispose();

多少博士大牛在研究這些不同的矩陣以期獲得更強悍的效果。此外還有好多人申請了各種 各樣的專利來保護這個色彩變換,所以如果大家想混一篇簡單的paper好畢業,這是個很好的 方向。隨便改兩個數字,一個新的矩陣就出來了,然後版面費一交,就可以發表了。當然, 這也是個蠻有意思的題目,可以做很多比較和研究,這些就不是我這種IT民工該講的東西了 。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved