2007年11月2日 星期五

VB圖像處理之圖像的亮度對比度調整

  在圖像處理中,恐怕大家最熟悉的就是對於圖像的亮度和對比度調整了。
  前面一定也有很多人寫過這樣的文章了,但是想把我的這個系列作一個完整的小結,我就再囉嗦一番了。
  還是以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中所用到的所效果的算法和主要代碼都已經貼出來了。也算是對自己對大家的一個小小交待吧。

2007年11月1日 星期四

直接使用色彩設定

z RGB 色彩有效範圍
y0 16,777,215 (&HFFFFFF&)
z色彩設定 : 4-位元的整數
y高位元數等於 0,而較低的三個位元,從最低到最高顯著的位元組,分別決定了紅、綠、藍三種色彩的數目
y紅、綠、藍三種元件皆使用 0 255 (&HFF) 之間的數值表示
z十六進位數指定色彩語法:
y&HBBGGRR&
y每個部分都是兩位從 00 FF 的十六進位數。中間值為 80
&H808080&
[object.] point (x, y)
z傳回指定位置的色彩值:
PointColor = Point (500, 500)

調整圖形亮度

改變Picture亮度

●這個範例用到的物件有Picture1及Command1(執行命令用)。
●這個範例是利用Point函數來取得RGB顏色數值,用運算式提高或減低數值,然後在原圖以改變後的數值當顏色再重新畫圖。

Private Sub Command1_Click()
  Dim Bright As Integer '亮度
  Bright = 20 '設亮度增20%(若用負數則亮度變暗如-20)
  Picture1.AutoRedraw = True
  For Y = 1 To Picture1.ScaleHeight Step 15
    For X = 1 To Picture1.ScaleWidth Step 15
      Tmp& = Picture1.Point(X, Y)
      If Len(Hex(Tmp&)) < color="blue">Then RS = Right(Hex(Tmp&), 2)
      If Len(Hex(Tmp&)) = 6 Then
        BS = Left(Hex(Tmp&), 2)
        GS = Mid(Hex(Tmp&), 3, 2)
      End If
      If Len(Hex(Tmp&)) = 4 Then
        GS = Left(Hex(Tmp&), 2)
      End If
      If Len(Hex(Tmp&)) > 1 Then R = Val("&H" + RS) Else R = 0
      If Len(Hex(Tmp&)) > 3 Then G = Val("&H" + GS) Else G = 0
      If Len(Hex(Tmp&)) > 5 Then B = Val("&H" + BS) Else B = 0
      If Len(Hex(Tmp&)) = 8 Then R = 1: G = 1: B = 1
      PerC = (100 + Bright) / 100
      R = Fix(R * PerC): G = Fix(G * PerC): B = Fix(B * PerC)
      If R > 255 Then R = 255
      If G > 255 Then G = 255
      If B > 255 Then B = 255
      If R = 0 Then R = Bright
      If G = 0 Then G = Bright
      If B = 0 Then B = Bright
      Picture1.PSet (X, Y), RGB(R, G, B)
    Next
  Next
  Picture1.AutoRedraw = False
End Sub