http://big5.webasp.net/article/16/15941.htm
前幾次為大家講述了如何通過操作像素來實現一些簡單的濾鏡效果。
這次想更大家講述一下用灰度直方圖均衡來調整圖像的色彩空間。
先給大家介紹一下一些顏色的小常識。
以電腦的顏色來說,顏色的組成是右紅、綠、藍三種顏色組成。
以最容易的24位色來說,紅色、綠色、藍色各用1個字節來表示,1個字節有8位,所以加在一起正好是24位。由於電腦無法用連續的模擬值來表示一個自然量,只能將它們分成一段一段來顯示,分得越多就越接近自然。1個字節是2^8=256,所以在24位色中每一個單色都有256種不同的強度,三種顏色按照不同的強度混合,可以得到2^24種色彩。大約可以表達1677萬種色彩,對於人的眼睛來說已經和自然色彩沒有區別了。
如果我們用PHOTOSHOP來打開一張圖片,選擇LEVEL工具,就可以察看這張圖片的色彩分佈了。
原圖:
灰度通道:紅色通道:
綠色通道:藍色通道:
由上面的四個通道圖,我們可以發現,這張圖片的色彩都是以低亮度為主,紅綠藍三色在高亮度區域的分佈都很少,而灰度通道也表明整張圖片的亮度值很低。
在前面的文章中,我已經和大家講過,人眼對於灰度(亮度)的敏感程度最高。因此,如果我們能通過一種方法把這章圖片的灰度提高,那麼它在我們的視覺中就會有更好的表現。
或許有朋友說只要把圖片加亮度,不是就可以了嗎?不錯,通過提高所有色彩的亮度,可以把原來處於第亮區域的色彩轉移到中亮度或高亮度區域,但是大家也知道,在算法中,加亮度只是很簡單的在R、G、B三個值後面直接加上一個偏移量:NewRed=OldRed+Offset,NewGreen=OldGreen+Offset,NewBlue+Offset,但是這種做法只是「粗暴」地將整個色彩空間搬了一個位置,而沒有改變其分佈。請看下面,我在這張圖片加上了120點亮度:再看看此時的色彩分佈你就知道我為什麼說它「粗暴」了
灰度通道:紅色通道:
綠色通道:藍色通道:
可以看到,原圖上的高亮度部分的色彩信息全部丟失,而低亮度部分(0-120)則是一片空白,
如果說原來的圖片是2^8×2^8×2^8 一共1677萬色的話,那麼現在的圖片則是:
(256-120)^3=251萬色,也就是說,通過我們給圖片加了120點的亮度,我們丟失了一大半的顏色信息。
(選擇加120點亮度是為了使圖片的整體亮度和直方圖均衡後的亮度相當,易於比較。)
那麼,有什麼方法可以在不丟失,或丟失很少的顏色信息的前提下做到是圖片顯示更好呢?
有,這就是今天要說的「灰度直方圖均衡」的方法。
先給大家看一下效果:下面是將原來的圖片通過灰度直方圖的方法處理後的效果和前面的比較。
原圖:
提高亮度120:
灰度直方圖均衡: 通過直方圖均衡後的顏色分佈如下:
灰度通道:紅色通道:
綠色通道:藍色通道:
通過對比,我們可以發現,灰度直方圖均衡,是對原圖中的色彩分佈按照出現的頻率作了一個分佈。
將出現最多的色彩「分」開,將出現很少的色彩「擠」得更緊,這樣作的好處就是把我們眼睛所看到的主體表示得更鮮明瞭。
好了,關於效果,也已經說得很多了,下面我們就來說明一下這個算法是如何實現的。
首先,我們需要獲取要處理的圖片中所有像素的色彩分佈統計,也就是上面的幾個通道所作那樣。
假設有一張圖(我們直接用灰度來表示):
100 50 20
20 40 50
100 250 200
統計入下:
20:2
40:1
50:2
100:2
200:1
250:1
這張圖一共有9個像素,我們用比例來表示每種顏色的出現比例:
20:2 / 9
40:1 / 9
50:2 / 9
100:2 / 9
200:1 / 9
250:1 / 9
由於所有的色彩出現的次數不可能超過圖片的總像素,因此,將所有色彩的比例相加也不會超過1(大家已經可以看出正好是1)
最後我們按照從低到高的順序,把各個色彩的比例進行加權統計,也就是當前點的「權」等於該點的原有比例加上前一個點的「權」,我們得到一個新的統計表:
20:2 / 9
40:3 / 9
50:5 / 9
100:7 / 9
200:8 / 9
250:9 / 9
最後,根據這個新的統計表,我們來把像素的亮度用一個新的亮度來代替,算法為:
新亮度=該點「權」×255
20:2 / 9 >> 20 (第一點不動,依然用20)
40:3 / 9×255=85
50:5 / 9×255=141
100:7 / 9×255=198
200:8 / 9×255=226
250:9 / 9×255=255
這時我們得到了新的圖:
100 50 20 198 141 20
20 40 50 >> 10 85 141
100 250 200 198 255 226
原圖中相對出現頻率多的部分的寬度變大了。而出現較少的部分則變窄了。
所以,灰度直方圖均衡的作用就是把一張圖片上出現多的色彩拓展,而把出現少的色彩壓縮。
從而得到了更「均衡」的色彩分佈。
下面附上我的例程:
Private Type ColorChart
ColorCount(255) As Long '統計原來圖片中的亮度出現次數
PixcelCount As Long '記錄圖片的像素個數
ColRatio(255) As Single '記錄每一個亮度的出現比例
NewVal(255) As Byte '存放新的亮度索引
End Type
Dim ColChart As ColorChart
Public Sub StatisticsChart()
Dim R As Byte
Dim G As Byte
Dim B As Byte
Dim Gray As Integer
Dim X As Long
Dim Y As Long
Dim I As Long
Dim L As Long
Dim M As Long
Dim C As Double
On Error GoTo ErrLine
Done = False
TimeFilter = timeGetTime
With ColChart
For X = 0 To 255 '先把數組清零
.ColorCount(X) = 0
Next
For X = 0 To OutPutWid '這兩個循環用來掃瞄圖片數據,記錄每個點的灰度和出現次數
For Y = 0 To OutPutHei
R = ColVal(2, X, Y)
G = ColVal(1, X, Y)
B = ColVal(0, X, Y)
Gray = R * 3 + G * 6 + B
Gray = Gray \ 10
.ColorCount(Gray) = .ColorCount(Gray) + 1
Next
Next
.PixcelCount = X * Y '獲得圖片的像素總量
C = 1 / .PixcelCount
.ColRatio( 0) = .ColorCount(M, 0) * C '計算每個亮度的出現比例
.NewVal( 0) = 0 '色值最小的色彩總是為0,不參與計算
L = 0
For I = 1 To 255
.ColRatio(I) = .ColorCount( I) * C + .ColRatio( L) '進行加權
.NewVal(I) = .ColRatio( I) * 255 '計算新的顏色索引
L = L + 1
Next
For X = 0 To OutPutWid
For Y = 0 To OutPutHei
R = Colval(2, X, Y) '讀取原來點的顏色
G = Colval(1, X, Y)
B = Colval(0, X, Y)
R = .NewVal( R) '查表得到新的顏色
G = .NewVal( G)
B = .NewVal( B)
ColOut(2, X, Y) = R '把新的顏色放到輸出數組中
ColOut(1, X, Y) = G
ColOut(0, X, Y) = B
Next
Next
End With
Done = True
TimeFilter = timeGetTime - TimeFilter
Exit Sub
ErrLine:
Done = True
MsgBox Err.Description
End Sub
如果讀者對這個過程中的一些數組和變量不清楚,請參考我前面的幾篇文章,其中有詳細說明:
VB圖像處理,(一)像素的獲取和輸出
VB圖像處理,(二)二次線性插值的應用
VB圖像處理,(三)幾個常用濾鏡的實現1
VB圖像處理,(四)幾個常用濾鏡的實現2
下一篇將繼續為大家講述顏色對比度和亮度的調節算法,以及彩色圖片轉換到灰度圖片的算法。
不要以為這個很簡單,中間還是有一些小問題要注意的哦。
(這裡只是說了我自己在寫程序的時候用到的方法,存在很多的不足。並且因為在貼上來的時候作了部分修改,可能會存在部分錯誤,請各位高手不吝賜教,將您用到的更好的方法提供一下,我將不勝感激。) |