2014年11月16日 星期日

99363031 HW3


這次作業用MDI來寫,也將上次作業也整合進來,並增加一些功能。
MDI是Multiple document interface,就是在視窗內還有視窗,外層的視窗為父視窗,其餘為子視窗。其中,除了父視窗外,我新增了5個視窗,分別有顯示color histogram、level編輯、curves編輯、顯示圖片以及debug用的視窗。下圖是將上次作業整合進來後的畫面。

Color histogram

接下來是這次作業level及curves。
元件裡雖然有TrackBar可以用,但Input及Output皆有2個值max及min,而TrackBar只能有1個slider,為了解決這問題,我改用2個button充當slider,如下圖。

Level-01
Level-02

在color histogram下方有1條黑線及2個button,黑線是Canvas所畫的,button是藉由MouseDown及MouseMove配合去更改button位置,四個button分別對到4個edit,而每個edit都有updown可進行微調,另外每個button跟edit都是動態調整,即改變button位置則相對應的edit值也會自動改變,或是更改edit值,button也會改變。下圖為程式碼片段



藉由MouseDown取得原始座標,MouseMove取得新座標,將兩個座標相減即為button該移動的距離,因為只有X軸需要更動,所以Y軸Mark掉了。至於程式碼中的常數27及282是button距離TabControl的Left的值。在VCL設計中,每個元間都會有父子或兄弟關係,而我的button與TabControl之間是屬於父子關係,而子元件位置是根據父親改變的,所以button的Top跟Left屬性是根據TabControl在變動的。

另外圖片也會隨著Level動態改變




雖然只看圖看不出來,實際上是藉由Timer來執行,計算值的參考為Input Output的max即min四個edit內的值,Timer每100ms會抓取四個參數並計算出新的色階表,再套用置圖片上,至於計算公式為高中數學直線方程的兩點式。


另外,level的調整中,如果input的範圍小於output的範圍會造成部分色彩值不存在





上面3張分別是調整前、調整中及調整後,在調整中,我將input範圍縮小,output不動,修改後的histogram可以看到很多空白夾在histogram裡,以第2張為例,input是32到229,output是0到255,計算出來的公式是
output = 1.294*input - 41.421
一些數字代入後
input       output
40        10.339
41        11.633
42        12.927
43        14.221
44        15.515

可以發現output中"13"的色彩沒有被對應到。







接下來是curves,要畫曲線,還有座標表示與螢幕座標不同...有很多問題需要考慮,比Level麻煩許多。兩點構成一個直線,所以在基礎上必須先預設兩個點(0,0)和(255,255),理論上這2個點可以自由移動,但會增加一些困擾,所以我將他們預設為無法更動。然後三點構成一個二次曲線,以函數表示
y = f(x) = ax2+bx+c

從其中可以看出x及y皆為已知,也就是在這函數裡要求的是係數,2個點可以構成直線,3個點構成2次曲線...以此類推n個點構成n-1次曲線。而1個點帶入會有1個式子,n個點會有n個式子,所以當有n個點時會有以下函數

a+ a1x+ a2x0+ ... + an-2x0n-2 + an-1x0n-1 = y0
a+ a1x+ a2x1+ ... + an-2x1n-2 + an-1x1n-1 = y1
a+ a1x+ a2x2+ ... + an-2x0n-2 + an-1x2n-1 = y2



a+ a1xn-2 + a2xn-2+ ... + an-2xn-2n-2 + an-1xn-2n-1 = yn-2
a+ a1xn-1 + a2xn-1+ ... + an-2xn-1n-2 + an-1xn-1n-1 = yn-1


由於x和y皆為已知,所以上述式子可以看成n元一次方程式求解只要求出a0an-1,使用二維陣列並將x與y存入,再以線性代數的高斯消去法即可算出所有係數。



上圖為使用結果,在圖上點擊左鍵會新增point,每個point皆可拖動,但拖出範圍外會自動delete該point,如果拖動的point座標使計算出的結果為無解,也會自動delete該point,方法一樣是使用Timer,每間隔200ms自動重畫,上面的point並非使用canvas畫的,而是新增自訂元件,並將大小設為11x11,在將黑色圖片塞入後的結果,雖然說是自訂元件,但實際上不過就是繼承TImage的類別,由於TImage並不會存放座標,所以這自訂元件只是TImage加上座標值而已,最後同樣的圖片會隨著Curves改變而改變



最後增加了一些東西,開啟jpg檔、上一步(undo)、下一步(redo)跟存檔(save),開jpg檔只是include <jpeg.hpp>,用TJPEGImage開啟再assign給TBitmap而已。而上一步跟下一步是用堆疊來達成功能,上面的Level跟Curves都有Apply跟Cancel按鈕,在編輯調整前先將原始圖片複製,之後調整後若cancel則把原本複製的圖貼回即可,若是apply則把原始圖片丟入堆疊中即可。




上面2張是由剛剛curves的apply結果,在視窗左上方會有箭頭圖示可按,按"上一步"時必須自動將目前圖片丟入"下一步"堆疊裡,所以"上一步"後可以看見"下一步"的按鈕。
最後存檔就是使用TSavedialog完成。


這次作業是level 跟 Curves 






沒有留言:

張貼留言