說真的,這一整學期的課程規劃我覺得是很不錯的,老師潛能開發式的教導、學生間的互相研究...等等,讓大多數同學的潛力有一半都被開發出來了,以前覺得某些同學好像對撰寫程式不太在行,像我就是其中一位,雖說不是倒數幾個,可就不是那種可以很快的把理論靈活運用的人,但在這學期的課程中,我學到了很重要的一點,就是:如何自我學習。
一開始的確碰到了很多難題,但在每次的Blog作業記錄了每次所遇到的新難題,我如何去解決或找尋的方向是甚麼,這也是培養問題解決能力中很重要的一環。因為第一次修老師的課,學期初的時候還真的不太習慣呢,作業也都是一個拖一個,後來下定決心要完成第一個作業、第二個...漸漸的,在完成這些作業後,不知不覺也培養出實力。
還有,心中一直對遲到這件事感到很後悔,因為如果沒有遲到就能聽到老師的講課而且又不用扣分(單純的腦子),只是這樣想著,哈哈,這也算讓我學習到了準時上課的重要性!另外,老師上課所問之問題一答:
作業繳交方式 : 我覺得滿ok的,因為沒有人一出生就是文筆好,也是經過不斷訓練才有的成果,而且有自己實作過或真正了解作業涵義才能撰寫出有內容的文章,總而言之,要付出一定努力才能有的。
最後,感謝老師這學期的指導,辛苦啦!!~外加新年快樂~
2010年1月17日 星期日
2010年1月16日 星期六
HW7 - 邊緣偵測 (Sobel operator)。
嗯,這次的作業是把一張圖片做邊緣偵測,也就是把圖片顏色梯度變化最大的地方顯現出來。實作的方法有很多種,而我是使用兩個Sobel operator的運算遮罩(一個是對x方向作用;一個是對y方向作用)來跟圖片做運算後取絕對值相加,這個方法可以讓出來的結果比較精準。而兩個Sobel operator的運算係數值如下:
對x方向作用↓

對y方向作用↓

我用的公式↓

-------------------------------------------------
M(x,y) : (x,y)這點的梯度大小。
gx : 圖片的值與對x方向作用的sobel遮罩運算結果。
gy : 圖片的值與對y方向作用的sobel遮罩運算結果。
-------------------------------------------------
這次又是因為遲到沒有聽到老師的講解,一開始當然是找陪我走過一學期的課本啦,但課本的內容並不是描述的很通順(?),在加上一拖拉庫的公式就先昏了,所以進而求救於浩瀚的宇宙,喔不,是無邊的網路。我找到了一些關於Sobel的基本定義和比較清楚的數學函意講解,在我的實作過程中都有幫助到。程式撰寫方面跟上次的作業差不多,要注意的地方就是彩色和灰階所使用的矩陣個數不同(使用channel方式也可),彩色的RGB排列方式...等,以上就簡略帶過,而套用完公式後,還要再經過一些微調,才會使邊緣更清楚俐落。那廢話不多說,來看我的實作結果吧!
彩色原圖↓

彩色圖片邊緣偵測↓

灰階原圖↓

灰階圖片邊緣偵測↓

以上就是我的實作結果,光是找圖就花了不少時間呀(汗),不過努力沒有白費,最後做出了滿意的成果!
補充 :
後來把SUBARU 的Impreza跑車轉成灰階圖片去跑邊緣偵測,覺得也滿漂亮的~給大家參考一下嚕。
灰階Impreza原圖↓

灰階Impreza邊緣偵測↓
對x方向作用↓

對y方向作用↓

我用的公式↓

-------------------------------------------------
M(x,y) : (x,y)這點的梯度大小。
gx : 圖片的值與對x方向作用的sobel遮罩運算結果。
gy : 圖片的值與對y方向作用的sobel遮罩運算結果。
-------------------------------------------------
這次又是因為遲到沒有聽到老師的講解,一開始當然是找陪我走過一學期的課本啦,但課本的內容並不是描述的很通順(?),在加上一拖拉庫的公式就先昏了,所以進而求救於浩瀚的宇宙,喔不,是無邊的網路。我找到了一些關於Sobel的基本定義和比較清楚的數學函意講解,在我的實作過程中都有幫助到。程式撰寫方面跟上次的作業差不多,要注意的地方就是彩色和灰階所使用的矩陣個數不同(使用channel方式也可),彩色的RGB排列方式...等,以上就簡略帶過,而套用完公式後,還要再經過一些微調,才會使邊緣更清楚俐落。那廢話不多說,來看我的實作結果吧!
彩色原圖↓

彩色圖片邊緣偵測↓
灰階原圖↓
灰階圖片邊緣偵測↓
以上就是我的實作結果,光是找圖就花了不少時間呀(汗),不過努力沒有白費,最後做出了滿意的成果!
補充 :
後來把SUBARU 的Impreza跑車轉成灰階圖片去跑邊緣偵測,覺得也滿漂亮的~給大家參考一下嚕。
灰階Impreza原圖↓
灰階Impreza邊緣偵測↓
2010年1月3日 星期日
HW6 - 空間濾波器。
這次的作業是空間濾波器的實作,要能由程式自行判斷處理灰階或彩色影像,而且使用者可以輸入濾波器的值。
由於老師有公佈了範例程式碼,所以灰階圖片的空間濾波很快的就可以出來,卡比較久的地方是在彩色濾波器的部分。原本以為跟上個作業一樣直接把值拿出來處理就好,但突然想起上個作業是做灰階圖片的處理,不過經由上次的經驗,知道24bit的圖片每一列的像素排列為B1G1R1B2G2R2...,所以把原本灰階圖片的一個陣列的處理改為RGB三個陣列分別去做,如下所示:
1. 首先讓三個指標陣列都讀取影像的同一列起始位置
bPtrResultImage_B = (Byte *)Image2->Picture->Bitmap->ScanLine[i];
...
2. 接著,跑濾波器(套用原理)
如果我們要處理某點的B值位於j = 3,那麼G值就會在j = 4,而R值就會在j = 5,而要抓某點左邊那點的B值時就要在j = 3 - 3 = 0這格去抓,同理,如果需要右邊那格的B值,就要在j = 3 + 3 = 6這格去抓(因為BGR的排列...),其餘依此類推。
濾波器原理的部分就要看一下課本啦。以下為我的實作結果:
灰階圖片實作↓

彩色圖片實作↓

這邊再貼上原圖和儲存後的結果會比較清楚,如下:
灰階原圖↓

灰階圖片濾波後↓

彩色原圖↓

彩色圖片濾波後↓

PS.濾波後的圖片會出現一個白色外框,我想應該是因為最外圈的值有部分的鄰近值無法參考,所以最多只能做到圖片外框往內1格的部分。
由於老師有公佈了範例程式碼,所以灰階圖片的空間濾波很快的就可以出來,卡比較久的地方是在彩色濾波器的部分。原本以為跟上個作業一樣直接把值拿出來處理就好,但突然想起上個作業是做灰階圖片的處理,不過經由上次的經驗,知道24bit的圖片每一列的像素排列為B1G1R1B2G2R2...,所以把原本灰階圖片的一個陣列的處理改為RGB三個陣列分別去做,如下所示:
1. 首先讓三個指標陣列都讀取影像的同一列起始位置
bPtrResultImage_B = (Byte *)Image2->Picture->Bitmap->ScanLine[i];
...
2. 接著,跑濾波器(套用原理)
如果我們要處理某點的B值位於j = 3,那麼G值就會在j = 4,而R值就會在j = 5,而要抓某點左邊那點的B值時就要在j = 3 - 3 = 0這格去抓,同理,如果需要右邊那格的B值,就要在j = 3 + 3 = 6這格去抓(因為BGR的排列...),其餘依此類推。
濾波器原理的部分就要看一下課本啦。以下為我的實作結果:
灰階圖片實作↓

彩色圖片實作↓

這邊再貼上原圖和儲存後的結果會比較清楚,如下:
灰階原圖↓

灰階圖片濾波後↓
彩色原圖↓

彩色圖片濾波後↓
PS.濾波後的圖片會出現一個白色外框,我想應該是因為最外圈的值有部分的鄰近值無法參考,所以最多只能做到圖片外框往內1格的部分。
2009年12月28日 星期一
HW5 - 逐段線性轉換函式(位元切平面)。
又是費經千辛萬苦阿...終於給他寫出來了!!(小小抒發,馬上回歸正題吧~)
這次的作業是把一張八位元灰階圖片的每個位元切平面顯示出來,我所使用的方法為,利用ScanLine[i]的方式把圖片每一列的第一個點的記憶體位址取出給一個型態為Byte的陣列指標當做起始位置,另一方面也宣告一個指標來接收你將來要顯示的圖片的起始記憶體位置,接著跑圖片的三倍寬度次數,利用記錄原始圖片值的陣列,把這一列上的每個點和某位元平面值做and運算,如果為該位元平面的點,就把用來顯示圖片的一維陣列對應位置的值設成255,如果不是的話就設成0。(這個部分不知道為什麼要跑圖片寬的三倍,我用原始圖片寬度時,只會出現1/3寬的圖片結果,等待高手指點。)
以上就是整個程式中比較重要的部分,其它像是個位元平面的值,可能就要去網路上搜尋一下了。那麼現在就來展示一下實作成果:
開啟圖片↓

第一位元平面↓

第二位元平面↓

第三位元平面↓

第四位元平面↓

第五位元平面↓

第六位元平面↓

第七位元平面↓

第八位元平面↓

以上就是我的實作結果,下面提供程式內ScanLine的語法:
-----------------------------------------------------------------
Byte *Ptr;
Ptr = (Byte *)Image->Picture->Bitmap->ScanLine[Index];
-----------------------------------------------------------------
補充:
後來為了解決上述的疑問,在網路上找到了一些資料,像是某個網站中所提到如果圖片為24bits的bmp圖片,那麼scanline所讀的那一列的pixel排列會為:
B1 G1 R1 B2 G2 R2 ... Bn Gn Rn
如此排列,後來我去看了一下我的圖片格式,是為24bits的bmp圖片,因為當初使用小畫家存圖時,存成8bits的bmp圖片會失真,4bits也會,如下圖所示:
8bits bmp picture↓

4bits bmp picture↓

所以最後就把它存成24bits的格式了,這也就是為甚麼需要三倍寬度的原因。
這次的作業是把一張八位元灰階圖片的每個位元切平面顯示出來,我所使用的方法為,利用ScanLine[i]的方式把圖片每一列的第一個點的記憶體位址取出給一個型態為Byte的陣列指標當做起始位置,另一方面也宣告一個指標來接收你將來要顯示的圖片的起始記憶體位置,接著跑圖片的三倍寬度次數,利用記錄原始圖片值的陣列,把這一列上的每個點和某位元平面值做and運算,如果為該位元平面的點,就把用來顯示圖片的一維陣列對應位置的值設成255,如果不是的話就設成0。(這個部分不知道為什麼要跑圖片寬的三倍,我用原始圖片寬度時,只會出現1/3寬的圖片結果,等待高手指點。)
以上就是整個程式中比較重要的部分,其它像是個位元平面的值,可能就要去網路上搜尋一下了。那麼現在就來展示一下實作成果:
開啟圖片↓

第一位元平面↓

第二位元平面↓

第三位元平面↓

第四位元平面↓

第五位元平面↓

第六位元平面↓

第七位元平面↓

第八位元平面↓

以上就是我的實作結果,下面提供程式內ScanLine的語法:
-----------------------------------------------------------------
Byte *Ptr;
Ptr = (Byte *)Image->Picture->Bitmap->ScanLine[Index];
-----------------------------------------------------------------
補充:
後來為了解決上述的疑問,在網路上找到了一些資料,像是某個網站中所提到如果圖片為24bits的bmp圖片,那麼scanline所讀的那一列的pixel排列會為:
B1 G1 R1 B2 G2 R2 ... Bn Gn Rn
如此排列,後來我去看了一下我的圖片格式,是為24bits的bmp圖片,因為當初使用小畫家存圖時,存成8bits的bmp圖片會失真,4bits也會,如下圖所示:
8bits bmp picture↓

4bits bmp picture↓

所以最後就把它存成24bits的格式了,這也就是為甚麼需要三倍寬度的原因。
2009年12月18日 星期五
HW4 - 乘冪率(Gamma)轉換。
這次的作業是把一張圖片做不同的Gamma值轉換,也就是把原本圖片的值經由一個公式轉換成顏色較深或較淡(對比度高或低)的圖片。轉換所用的公式和結果如下:
---------------------------------------------------
轉換公式 : s = c * r^γ
s : 轉換後的值
c : 常數值,用來調整轉換後的值落在0~255區間內
r : 原本的值
γ : Gamma值
---------------------------------------------------
黑白影像的實作結果 :
原圖 ↓

(圖片來源=>http://www.wuhunews.cn/whnews/200909/196116.html)
γ = 2.0 ↓

γ = 3.0 ↓

γ = 4.0 ↓

彩色影像的實作結果:
原圖 ↓

γ = 0.4 ↓

γ = 3.0 ↓

這次在程式撰寫上沒有甚麼問題,大略流程為宣告一個大小為256的一維陣列來存放0, 1, 2, ..., 255每個數值轉換後的值,再把原本的圖片值丟入那個一維陣列,就可以由原本圖片值當索引,找出轉換後的值再給原圖片陣列輸出。
PS. 旋轉作業和這次的程式撰寫,皆有需要讀入使用者的輸入值,所以學到了一個新的語法:
------------------------------------
gamma = StrToFloat(Edit1->Text);
------------------------------------
功用為把使用者在Edit物件所輸入的字串轉換成數值,在寫旋轉時卡這邊卡超久,不知道要怎麼取得它的輸入值,後來在書上找到語法,雖然是個小小發現,但對初學者的我來說是滿高興的一件事。
---------------------------------------------------
轉換公式 : s = c * r^γ
s : 轉換後的值
c : 常數值,用來調整轉換後的值落在0~255區間內
r : 原本的值
γ : Gamma值
---------------------------------------------------
黑白影像的實作結果 :
原圖 ↓

(圖片來源=>http://www.wuhunews.cn/whnews/200909/196116.html)
γ = 2.0 ↓
γ = 3.0 ↓
γ = 4.0 ↓
彩色影像的實作結果:
原圖 ↓

γ = 0.4 ↓
γ = 3.0 ↓
這次在程式撰寫上沒有甚麼問題,大略流程為宣告一個大小為256的一維陣列來存放0, 1, 2, ..., 255每個數值轉換後的值,再把原本的圖片值丟入那個一維陣列,就可以由原本圖片值當索引,找出轉換後的值再給原圖片陣列輸出。
PS. 旋轉作業和這次的程式撰寫,皆有需要讀入使用者的輸入值,所以學到了一個新的語法:
------------------------------------
gamma = StrToFloat(Edit1->Text);
------------------------------------
功用為把使用者在Edit物件所輸入的字串轉換成數值,在寫旋轉時卡這邊卡超久,不知道要怎麼取得它的輸入值,後來在書上找到語法,雖然是個小小發現,但對初學者的我來說是滿高興的一件事。
2009年12月17日 星期四
HW3 - 直方圖統計。
(又遲交了,嗄嗄嗄...。)
這次的作業是把一張圖做RGB值的統計並用直方圖顯示出來,實作方式為利用一個二維陣列和選擇Channel的方式去記錄RGB個別的值。這次主要卡在的地方是不知道要如何在圖片上畫出一段特定長度的線和畫出有顏色的線。一開始有自己的想法,想把一個R值的統計結果放在一個二維陣列,直接顯示到圖片上,不過這麼一來就要使用三個二維陣列去顯示,會很佔記憶體空間。後來老師公佈程式碼和同學的參考範例,知道了可以使用MoveTo和LineTo畫線的長度,還有使用Image2->Canvas->Pen->Color去畫線的顏色。實作結果如下:
原圖↓

R的直方圖統計結果圖↓

G的直方圖統計結果圖↓

B的直方圖統計結果圖↓

加上參考老師所寫的範例,可以調整顯示結果的比例,調整成更清楚的圖形分佈,而直方圖下方的拉吧範圍為0~255,可以自己隨意拉動,且依據拉到的位置顯示出該位置數值的像素數。
這次的作業是把一張圖做RGB值的統計並用直方圖顯示出來,實作方式為利用一個二維陣列和選擇Channel的方式去記錄RGB個別的值。這次主要卡在的地方是不知道要如何在圖片上畫出一段特定長度的線和畫出有顏色的線。一開始有自己的想法,想把一個R值的統計結果放在一個二維陣列,直接顯示到圖片上,不過這麼一來就要使用三個二維陣列去顯示,會很佔記憶體空間。後來老師公佈程式碼和同學的參考範例,知道了可以使用MoveTo和LineTo畫線的長度,還有使用Image2->Canvas->Pen->Color去畫線的顏色。實作結果如下:
原圖↓

R的直方圖統計結果圖↓

G的直方圖統計結果圖↓

B的直方圖統計結果圖↓

加上參考老師所寫的範例,可以調整顯示結果的比例,調整成更清楚的圖形分佈,而直方圖下方的拉吧範圍為0~255,可以自己隨意拉動,且依據拉到的位置顯示出該位置數值的像素數。
2009年12月13日 星期日
HW2 - 逆時針或順時針旋轉圖片(任意角度)。
又太晚PO文了...(跪)。
這是第二個作業,把圖片做逆時針旋轉,不過後來我加了個順時針旋轉的功能,以下就是旋轉後的結果:
原圖↓

逆時針旋轉30度↓

逆時針旋轉60度↓

逆時針旋轉90度↓

逆時針旋轉180度↓

順時針旋轉30度↓

順時針旋轉60度↓

順時針旋轉90度↓

結果如上,一開始我是想用旋轉後的四個角的座標位置,來計算新圖片寬高,不過卡在四個角的旋轉計算讓我覺得有點繁雜,就停工了一段時間,後來用老師的方法,使用對角線當做新圖片的寬高,但怎麼做都做不出來,可以旋轉正確的角度,但邊界的地方卻不能吻合。後來在某個網站找到了旋轉範例,而它計算新圖片寬高的方式,剛好就是我想要的四個角的計算方法,後來再依樣畫葫蘆把逆時針旋轉的公式套用進去(它提供的是順時針旋轉的計算方式),整個範例所提供的概念算是滿好理解的,發現其實四個角旋轉後的座標計算也不是很難,只是要靜下心去依照旋轉公式推算,就可以得到自己想要的結果。
PS. 我也去找了一下BCB存檔的語法,如老師所說的不用再去截圖,真的很好用!語法如下↓
#-------------------------------------------------------------------------
if(SavePictureDialog1->Execute())
Image2->Picture->SaveToFile(SavePictureDialog1->FileName+".BMP");
#-------------------------------------------------------------------------
並要在Form拉入Dialogs的SavePictureDialog的對話方塊才能存檔唷!
這是第二個作業,把圖片做逆時針旋轉,不過後來我加了個順時針旋轉的功能,以下就是旋轉後的結果:
原圖↓

逆時針旋轉30度↓
逆時針旋轉60度↓
逆時針旋轉90度↓
逆時針旋轉180度↓
順時針旋轉30度↓
順時針旋轉60度↓
順時針旋轉90度↓
結果如上,一開始我是想用旋轉後的四個角的座標位置,來計算新圖片寬高,不過卡在四個角的旋轉計算讓我覺得有點繁雜,就停工了一段時間,後來用老師的方法,使用對角線當做新圖片的寬高,但怎麼做都做不出來,可以旋轉正確的角度,但邊界的地方卻不能吻合。後來在某個網站找到了旋轉範例,而它計算新圖片寬高的方式,剛好就是我想要的四個角的計算方法,後來再依樣畫葫蘆把逆時針旋轉的公式套用進去(它提供的是順時針旋轉的計算方式),整個範例所提供的概念算是滿好理解的,發現其實四個角旋轉後的座標計算也不是很難,只是要靜下心去依照旋轉公式推算,就可以得到自己想要的結果。
PS. 我也去找了一下BCB存檔的語法,如老師所說的不用再去截圖,真的很好用!語法如下↓
#-------------------------------------------------------------------------
if(SavePictureDialog1->Execute())
Image2->Picture->SaveToFile(SavePictureDialog1->FileName+".BMP");
#-------------------------------------------------------------------------
並要在Form拉入Dialogs的SavePictureDialog的對話方塊才能存檔唷!
2009年10月23日 星期五
HW1 - 開啟一張bmp圖片。
(首先,這麼慢才PO文,抱歉,因為研究了很久...囧)
這次的作業是開啟一張bmp圖片,並且把RGB的值取出存入三個二維動態陣列儲存,且滑鼠在圖片上移動時,可以隨著滑鼠移動顯示圖片該點的RGB值。實作的流程和幾個比較重要的語法如下:
-------------------------------------------------------------
1.開啟一張bmp圖片
Image1->Picture->LoadFromFile(OpenPictureDialog1->FileName);
2.取得圖片寬高
Height = Image1->Picture->Height;
Width = Image1->Picture->Width;
3.宣告三個二維動態陣列
IMatrixR = new unsigned char *[Height];
4.取得圖片RGB值分別存入陣列
IMatrixR[i][j] = GetRValue(Image1->Canvas->Pixels[j][i]);
5.使用OnMouseMove把滑鼠移動到的點的RGB值輸出
Label4->Caption = AnsiString(GetRValue(Image1->Canvas->Pixels[Y][X]));
-------------------------------------------------------------
實作:
開圖(點圖放大)↓

秀圖(點圖放大)↓

心得:
一開始因為第一次接觸這個程式語言,光是一些初步的問題,如:怎麼輸出一段文字、要在哪個區塊打程式碼...等,就快把我搞掛了,不過我的個性比較衝動,所以下課鐘響就馬上衝到圖書館借了一本BCB的書,書中提到了簡單的操作,演練之後有了初步瞭解,發現它的邏輯其實與學過的C語言差不多,但它是屬於視窗化的程式設計語言,再加上使用到的函式語法不少,所以不知道的語法就要上網去找一下嚕。
這次實作大部分是參考老師和學長的程式碼外加書上的範例,卡關最久的地方就是隨滑鼠移動顯示值,這個部份的實作方式就是在顯示圖的物件上點一下再到左邊的小視窗,把標籤切換到"Event"後,有個叫"OnMouseMove"的欄位,在空白欄位上快點兩下,就會在程式碼那看到一個空白的副函式,它的宣告變數中就有X和Y,所以猜想可以利用這兩個變數去控制顯示滑鼠目前所在的位置的值,結果答對了~哈哈。
這次的作業是開啟一張bmp圖片,並且把RGB的值取出存入三個二維動態陣列儲存,且滑鼠在圖片上移動時,可以隨著滑鼠移動顯示圖片該點的RGB值。實作的流程和幾個比較重要的語法如下:
-------------------------------------------------------------
1.開啟一張bmp圖片
Image1->Picture->LoadFromFile(OpenPictureDialog1->FileName);
2.取得圖片寬高
Height = Image1->Picture->Height;
Width = Image1->Picture->Width;
3.宣告三個二維動態陣列
IMatrixR = new unsigned char *[Height];
4.取得圖片RGB值分別存入陣列
IMatrixR[i][j] = GetRValue(Image1->Canvas->Pixels[j][i]);
5.使用OnMouseMove把滑鼠移動到的點的RGB值輸出
Label4->Caption = AnsiString(GetRValue(Image1->Canvas->Pixels[Y][X]));
-------------------------------------------------------------
實作:
開圖(點圖放大)↓

秀圖(點圖放大)↓

心得:
一開始因為第一次接觸這個程式語言,光是一些初步的問題,如:怎麼輸出一段文字、要在哪個區塊打程式碼...等,就快把我搞掛了,不過我的個性比較衝動,所以下課鐘響就馬上衝到圖書館借了一本BCB的書,書中提到了簡單的操作,演練之後有了初步瞭解,發現它的邏輯其實與學過的C語言差不多,但它是屬於視窗化的程式設計語言,再加上使用到的函式語法不少,所以不知道的語法就要上網去找一下嚕。
這次實作大部分是參考老師和學長的程式碼外加書上的範例,卡關最久的地方就是隨滑鼠移動顯示值,這個部份的實作方式就是在顯示圖的物件上點一下再到左邊的小視窗,把標籤切換到"Event"後,有個叫"OnMouseMove"的欄位,在空白欄位上快點兩下,就會在程式碼那看到一個空白的副函式,它的宣告變數中就有X和Y,所以猜想可以利用這兩個變數去控制顯示滑鼠目前所在的位置的值,結果答對了~哈哈。
訂閱:
文章 (Atom)