前面一定也有很多人寫過這樣的文章了,但是想把我的這個系列作一個完整的小結,我就再囉嗦一番了。
還是以24位色圖像為例子,每種色彩都可以用0-255,一共256種深度來表示。如果我們把它畫在一個二維坐標上,正好是一條直線。
比如我們將像素的色深作為橫坐標,輸出色深作為縱坐標的畫,正好是一條經過原點(0,0)的45度斜線。
![]() |
如圖中直線A所表示的,角T為45度,表示它的對比度正好為1。那麼很容易就可以寫出它的直線方程:Out = In * 1 ,係數1就是對比度的概念如果把條直線加上一個偏移量變成B,那麼它的直線方程就成為:Out = In * 1 + (ab) 偏移量(ab)就是亮度的增量。
只要有初中的代數知識就很容易看出它滿足一條直線方程:Y= A * X + B。
但是,我們這裡要處理的情況稍微有些不同,在圖像處理中,對比度和亮度要分別對待。不能因為改變而改變亮度,因為我們習慣上把灰色(127,127)這 一點作為中心點。比如,我們加大了對比度,原來的直線A就變成如直線D所表示的,在改變了對比度的同時,也增加了亮度(ab),而我們心目中的變化應該是 入直線C那樣。也就是說,我們把(127,127)這一點映射成了坐標系的原點。
那麼我們就要把原來的直線公式修改成:Y=( X - 127 ) * A + B + 127。A表示對比度,B表示亮度增量。我們驗證一下:只要亮度增量 B=0,無論怎麼改變對比度 A,該直線始終通過中心點(127,127),也就是說改變對比度的同時,亮度沒有改變。
由此,我們就可以推導出顏色的對比度亮度計算公式了:
NewRed = (OldRed -127 ) * A + 127+ B NewGreen = (OldGreen -127 ) * A + 127+B NewBlue = (OldBlue -127 ) * A + 127+B |
現在你是否已經準備著手用這個公式來寫出你自己的亮度對比度子程序了呢?
慢著,再多做一步吧。我們是在遍程序,不是在做初中代數考試。這多出來的一步將使你的程序的執行效率更高一些。
我們把上面的公式再推導一下:
Y=( X - 127 ) * A + B + 127 => Y = X * A - 127 * A + 127+B (1)
令:B = B -127 * A +127 (2)
由上面(1),(2)兩步,得到一個新的公式:Y = X * A + B
咦?怎麼又變回來了??
是的公式的形式確實是變回來了,不過B所代表的東西已經不同了。
或許你又會說我這是多此一舉,請聰明的讀者想像一下:在一個普通的圖片做亮度對比度運算的時候,我們上面這些小小的變化將帶來什麼樣的效率提升。假設一張圖片大小是1027*768
一共有786432個像素,而每個像素又要分別計算紅綠藍三種顏色。
那麼,上述這個公式就需要計算786432 * 3 = 2359296 次,經過這麼多次運算的放大,哪怕是小小的一個重複計算都將浪費很長的時間。
因為在調用子程序的時候亮度和對比度都已經確定,那麼B = B -127 * A +127這一步就可以放在循環的外面先作好。從而減少了程序的運算時間。
下面給出我的程序,以供參考:
Public Sub BrightnessAndContrast(ByVal RedOffset As Long, ByVal GreenOffset As Long, ByVal BlueOffset As Long, Optional ByVal RedContrast As Single = 1, Optional ByVal GreenContrast As Single = 1, Optional ByVal BlueContrast As Single = 1) Dim X As Long Dim Y As Long Dim MidR As Integer Dim MidG As Integer Dim MidB As Integer Dim Max As Long On Error GoTo ErrLine Done = False TimeFilter = timeGetTime MidR = RedOffset - 127 * (RedContrast - 1) '計算新的位移量B MidG = GreenOffset - 127 * (GreenContrast - 1) MidB = BlueOffset - 127 * (BlueContrast - 1) Max = 255 For X = 0 To OutPutWid For Y = 0 To OutPutHei R = ColOut(2, X, Y) G = ColOut(1, X, Y) B = ColOut(0, X, Y) R = R * RedContrast + MidR '計算Y = X * A + B G = G * GreenContrast + MidG B = B * BlueContrast + MidB If R > Max Then R = Max '輸出值判斷是否在0到255之間 If R < 0 Then R = 0 If G > Max Then G = Max If G < 0 Then G = 0 If B > Max Then B = Max If B < 0 Then B = 0 ColOut(2, X, Y) = R ColOut(1, X, Y) = G ColOut(0, X, Y) = B Next Next Done = True TimeFilter = timeGetTime - TimeFilter Exit Sub ErrLine: MsgBox Err.Description Done = True End Sub |
因為在亮度對比度的過程中會出現計算值超出(0,255)的範圍,因此需要對它做一個判斷,把結果限定在這個範圍之內。
這個程序很簡單,可以根據給定的紅綠藍的亮度偏移量和對比度參數計算。由於把三種顏色的6個參數分開,也可以只調整單獨的一種顏色。
還有一個好處,就是當你將對比度參數設為負值的時候,可以直接得到原圖片的反色輸出。(這也是將前面的坐標系原點移動到127這一點的一個好處。)
下面是用我的程序處理得到的效果:
原圖:
![]() |
亮度+20,對比度1.5效果:
![]() |
對比度 -1,反相色彩效果:
![]() |
作為這個系列的最後一篇文章,我在我的程序ImageCast中所用到的所效果的算法和主要代碼都已經貼出來了。也算是對自己對大家的一個小小交待吧。
沒有留言:
張貼留言