• 沒有找到結果。

Digital Image Processing

N/A
N/A
Protected

Academic year: 2022

Share "Digital Image Processing"

Copied!
11
0
0

加載中.... (立即查看全文)

全文

(1)

Digital Image Processing

submission date:2010/10/04 Assignment#1 B97902030 資工三 林運生 E-mail:[email protected]

檔案資料夾共有四份文件,分別為 problem1.c、problem2.c、README.pdf 以 及 README(在 linux 系統下編輯而成的 makefile 檔)。

作業環境為 windows XP,使用 Dev-C++,然後編寫 README 時,使用 pietty 連接系上工作站 linux7,使用方法為 make –f README,預設的輸入圖檔檔名及 輸出圖檔檔名,皆為作業要求,Problem1 的輸入圖檔檔名為 “sample.raw”,接下 來會產生 “C.raw”、”E.raw”、”Q.raw”以及輸出圖檔檔名 “O.raw”。在 Problem2 中,要求的輸出圖檔檔名依次為

“puppy_impulse_low.raw”、”puppy_uniform_low.raw”、”puppy_impulse_high.ra w”、”puppy_uniform_high.raw”以及輸出圖檔檔名”puppy_output.raw”。

Problem1::Getting started & Image Enhancement

給定一個 sample.raw 的灰階圖檔,分別做改善圖片的處理,

第一:利用線性內插的方法,擴大原來圖片的 dynamic range,取結果為 C 第二:use histogram equalization,取結果為 E

第三:將第二的結果,分別對應到五個灰階值,取結果為 Q 第四:結合原圖、第一、第二和第三,取結果為 O

在 function main(int argc, char *argv[])中,傳入的參數分別為 “執行檔”、”

輸入圖檔檔名” 以及 “輸出圖檔檔名”,以這次作業的範例加上 make –f README為 solution1 sample.raw O.raw(此亦為預設值)。

C.raw,會自動產生,大小為 256*256,在 problem1.c 中,為 function void linear_C(),使用的方法為線性內插法,首先找出原圖的灰階 range(0~255)

(2)

最大值和最小值,接著利用線性內插的數學式,將每個灰階值重新對應到新的灰 階值。

先找出原圖檔的最大灰階值及最小灰階值,作為線性內插的依據 Size = 256

for(i = 0; i < Size; i++){

for(j = 0; j < Size; j++){

if(Imgdata[i][j] > Max) Max = Imgdata[i][j];

if(Imgdata[i][j] < min) min = Imgdata[i][j];

} }

dif = Max-min;

if(dif){

for(i = 0; i < Size; i++){

for(j = 0; j < Size; j++){

ImgdataC[i][j] = Imgdata[i][j]*255/dif - 255*min/dif;

} } }

ImgdataC 為 C.raw 的陣列,線性內插的意義為

255……….0 <= ImgdataC ↖ ↖ ↑ ↗ ↗

Max………min <= sample.raw

按照線性內插的數學式來比較,可以發現圖檔黑的地方更黑,白的地方更白,對 比變得比較明顯。

(C.raw)

E.raw 也是自動產生,大小同樣為 256*256,在 problem1.c 中為 function

(3)

void histogram_E(),運用的方法為統計每個 pixel 代表的灰階值總數,接著除以 全部面積(256*256),此時得到的量值介於 0~1 之間,可以視為某種機率表示法,

接下來做累積直方圖,目的是使每個灰階值都有數值,達到平均的概念,且值與 值之間差異不大,同時也是為了使愈靠近 255(白點)的值可以更靠近 1,因為原 本只是統計數量,並非對應到實際灰階值,最後再乘以 255,使得 0~1 可以變 成灰階值的 0~255,並把原本各個 pixel 對應到灰階值對應到新的灰階值,就大 功告成了。

for(i = 0; i < Size; i++){

for(j = 0; j < Size; j++){

tmp[Imgdata[i][j]]++; <= 做灰階數量統計,放到 tmp[]裡面 }

}

for(i = 0; i < 256; i++)

tmp[i] /= (Size*Size); <= 將量值變成類似機率模式,介於 0~1 之間 for(i = 1; i < 256; i++)

tmp[i] = tmp[i] + tmp[i-1]; <= 做累積直方圖,順便使每個灰階值都有值 for(i = 0;i < 256; i++)

tmp[i] *= 255; <= 將灰階直方圖轉為灰階值 0~255

這種方法做起來,會發現暗的地方變亮一點,因為原圖最低點不一定會是 0,整 體效果說來跟線性內插法也有點像,但是最低點以下可能不會碰到,最高點也是 一樣。

(E.raw)

以下是原始 sample.raw 的灰階直方圖,x 座標是 0~255,y 座標是個數

(4)

0 500 1000 1500 2000

10 30 50 70 90 110 130 150 170 190 210 230 250

灰階個數

下圖為上圖的累積直方圖,由此圖可以發現出 E.raw 明亮的原因,因為許多灰階 都對應到相同的值,一樣 x 座標為灰階值 0~255,y 座標為個數。

0 10000 20000 30000 40000 50000 60000 70000

10 30 50 70 90 110 130 150 170 190 210 230 250

灰階累積直方圖

Q.raw 也是一樣自動產生,大小為 256*256,在 problem1.c 中為 function void quantize_Q(),因為要求將 E.raw 對應到五個灰階值,0, 64, 128, 192, 255,

所以採取平均的概念,將灰階值介於 0~32 的 pixel 對應到 0,灰階值 32~96 的 pixel 對應到 64,灰階值介於 96~160 的 pixel 對應到 128,灰階值介於 160~224 的 pixel 對應到 192,灰階值介於 224~255 的 pixel 對應到 255。

觀察這樣的結果,發現線條變得比較不明顯,因為只剩下 5 個灰階值,開 E.raw 來看還比較明顯,因為 E.raw 的每個灰階值都有值,是有類似平均過後的 概念,相反地,如果用同樣的方法看 sample.raw 或 C.raw,就會變得很模糊。

(Q.raw)

(5)

下面兩張圖是用 Q 的方法,開啟 sample.raw(左圖)和 C.raw(右圖)

最後是 O.raw 檔,也是自動產生,大小為 512*512,就只是單純將前面的結 果結合起來,寫在一個檔案裡面,在 problem1.c 中,為 function

void combine_O(char *output_name),其中參數 output_name 為輸出最後結果檔的 檔名,預設為 O.raw。

(O.raw)

(6)

Problem2::Noice Removal

給定四個灰階圖檔,大小皆為 256*256,目的是去除圖片中的雜訊,使得給 定圖檔變得比較清晰可看,這四個圖檔分別

為”puppy_impulse_low.raw”、”puppy_uniform_low.raw”、”puppy_impulse_high .raw”以及”puppy_uniform_high.raw”,最後將這四張圖檔處理過後的檔案,結 合成一個大圖檔(512*512)”puppy_output.raw”。

在 problem2.c 中,int main(int argc, char *argv[]),所傳遞的參數有五個,前面 四個即為四個圖檔,而且順序不可以亂掉,最後一個為最後的輸出圖檔檔名,以 這次作業為例即為

“solution2 puppy_impulse_low.raw puppy_uniform_low.raw puppy_impulse_high.raw puppy_uniform_high.raw puppy_output.raw”。

而其中會分別自動產生出四個處理過後的檔案,大小皆為 256*256,分別 為”puppy_li.raw”、”puppy_lu.raw”、”puppy_hi.raw”以及”puppy_hu.raw”。

圖檔 puppy_li.raw 的處理方法為 Median filtering,首先先將 3*3 大小的 pixel 中位數找出來,然後將中間的數值換成中位數,這部份分了三個小節,第一是整 張圖的角落四點,採用 even 的方法,copy 鄰近的數值;第二小節是四個邊,一 樣採用 even 法;第三就是中間的那一大塊。

在 problem2.c 中,這部份程式在void puppy_li(char *input_name)裡面,參數 input_name 即為圖檔檔名。

以第三小節為例 for(i = 1; i < 255; i++){

for(j = 1; j < 255; j++){

cmp_arr[0] = Imgdata[i-1][j-1], cmp_arr[1] = Imgdata[i-1][j], cmp_arr[2] = Imgdata[i-1][j+1], cmp_arr[3] = Imgdata[i][j-1], cmp_arr[4] = Imgdata[i][j], cmp_arr[5] = Imgdata[i][j+1], cmp_arr[6] = Imgdata[i+1][j-1], cmp_arr[7] = Imgdata[i+1][j],

cmp_arr[8] = Imgdata[i+1][j+1];

qsort(cmp_arr, 9, sizeof(unsigned char), cmp);

ImgdataLi[i][j] = cmp_arr[4];

} }

陣列 cmp_arr[]為暫時儲存要排序的陣列,然後利用 qsort(),最後得到中位數 cmp_arr[4]。

(7)

(puppy_li.raw)

圖檔 puppy_lu.raw 的處理方法,是使用 low-passing filter,為什麼叫做

low-passing?因為他可以把圖檔中反差較強的部份壓抑掉,讓整張圖片看起來柔 和一點,模糊一點,在 problem2.c 中,程式碼在void puppy_lu(char *input_name) 裡面,參數 input_name 一樣為圖檔檔名。

至於 low-passing 的 mask,試過以下五種

1 1 1 1 1 1 1 2 1 1 3 1 1 4 1 1 1 1 1 2 1 2 4 2 3 9 3 1161 1 1 1 1 1 1 1 2 1 1 3 1 1 4 1

效果是愈靠右邊愈清晰,推論的理由應該是加權的權重愈重,愈不會模糊,愈能 保持原本的樣子,不過就算加權比重再種,基本上 low-passing 就是會有一定程度 的模糊化。最後選取最右邊的 mask,因為感覺這樣比較清晰好看。

實做方法也是一樣分了三小節,第一小節是處理四個角落;第二小節是四個 邊;第三小節是中間那一大塊。

以第三小節為例 for(i = 1; i < 255; i++){

for(j = 1; j < 255; j++){

tmp = Imgdata[i-1][j-1]*(1)+Imgdata[i-1][j]*(4)+Imgdata[i-1][j+1]*(1)+

Imgdata[i][j-1]*(4)+Imgdata[i][j]*16+Imgdata[i][j+1]*(4)+

Imgdata[i+1][j-1]*(1)+Imgdata[i+1][j]*(4)+Imgdata[i+1][j+1]*(1);

tmp = tmp / 36;

ImgdataLu[i][j] = (unsigned char)tmp;

} }

最後要記得除以 36,而且要算好,不然圖片就會變成全黑。

(8)

(puppy_lu.raw) 圖檔 puppy_hi.raw 的處理方法,如同 puppy_li.raw 的處理方法,Median filtering,因為這樣的處理方法也可以適用於 puppy_impulse_high.raw 上,而且效果 也不錯,在 problem2.c 中,程式碼放在void puppy_hi(char *input_name)中。

(puppy_hi.raw)

圖檔 puppy_hu.raw 就比較麻煩一點,試過了許多方法,還是無法得到非常清 晰的圖片,只能退而求其次,找出相較之下比較好的方法,在 problem2.c 中,程 式碼放在void puppy_hu(char *input_name)中。

使用的方法為先用 Median filtering 找出中位數,再用 outlier detection 找出不 一樣的點,利用 3*3mask 的中間點和周圍相異兩個標準差為基準,將中間的 pixel 換成中位數,最後再用 low-passing 的方法,模糊一次,總結來說,就是先去除大 部分雜訊,再模糊一次。

為了找出相較之下比較好的結果,試過了 5*5mask 的 low-passing,3*3mask 的 low-passing 做兩次,結果都是得到模糊一點的情況,原本白色的雜訊還是沒有 去掉很多。如果全部都用 outlier detection 的方法,將中間值換成原本的值,結果 也是比較模糊,Median filtering 亦同。

程式一樣分了三個小節,也是為了分別處理角落、邊和中間那一大塊的問題。

以角落為例:

(9)

for(i = 0; i < 4; i++) cmp_arr[i] = Imgdata[0][0];

cmp_arr[4] = cmp_arr[5] = Imgdata[0][1], cmp_arr[6] = cmp_arr[7] = Imgdata[1][0], cmp_arr[8] = Imgdata[1][1];

qsort(cmp_arr, 9, sizeof(unsigned char), cmp);

tmp = Imgdata[0][0]*3+Imgdata[0][1]*2+Imgdata[1][0]*2+Imgdata[1][1]*1;

avg = (unsigned char)(tmp / 8);

tmp = (Imgdata[0][0]-avg)*(Imgdata[0][0]-avg)*3+

(Imgdata[0][1]-avg)*(Imgdata[0][1]-avg)*2+

(Imgdata[1][0]-avg)*(Imgdata[1][0]-avg)*2+

(Imgdata[1][1]-avg)*(Imgdata[1][1]-avg)*1;

tmp = tmp / 8;

s = (unsigned char)(sqrt(tmp));

if(Imgdata[0][0]-avg > s*2) ImgdataHu1[0][0] = cmp_arr[4];

else ImgdataHu1[0][0] = Imgdata[0][0];

一樣 qsort()是為了找出中位數,avg 是為了算出標準差 s,最後的 if 判斷式就 是結合了 outlier detection 的概念。最後有點像是暴力解法,不斷嘗試標準差要 1 倍還是 2 倍 3 倍,哪個結果比較好?還有就是 outlier detection 要換成中位數,還 是原來的值比較好?其實差異度都不大,只是感覺這樣的解法比較好看。

(puppy_hu.raw)

最後的圖檔 puppy_output.raw,如同 problem1 的解法,單純將前面的結果結 合起來,變成 512*512,在 problem2.c 中,程式碼在

void puppy_combine(char *output_name)中,output_name 預設為 puppy_output.raw。

(10)

(puppy_output.raw)

(11)

README(makefile) README(makefile) README(makefile)

README(makefile)大解析 大解析 大解析 大解析: : : :

CC=gcc LN=gcc

All : prob1 prob2 clean prob1 : problem1.c

@echo " Problem 1"

@echo " compiling and linking the code"

$(CC) -c problem1.c

$(LN) -o solution1 problem1.o

@echo " running the program, usage: solution1 inputImageName outputImageName"

solution1 sample.raw O.raw prob2 : problem2.c

@echo " Problem 2"

@echo " compiling and linking the code"

$(CC) -lm problem2.c -o solution2

@echo " running the program, usage: solution2 inputImageName1 inputImageName2 inputImageName3 inputImageName4 outputImageName"

solution2 puppy_impulse_low.raw puppy_uniform_low.raw

puppy_impulse_high.raw puppy_uniform_high.raw puppy_output.raw clean:

rm -rf problem1.o

所以最後會有兩個執行檔,solution1 和 solution2,分別對應到 problem1 和 problem2 所傳遞的參數如上可見。

參考文獻

相關文件

機器常數machine epsilon,以ϵmach表示,其值為1和比 1大的最小浮點數之間的距離。以下表格為IEEE 754浮點 數標準中各部份所佔的位元數: 精準度類型 符號部分 指數部分

※步進點主要應用於步進電路中。當不使 用步進指令時,步進點可作為一般的輔助 繼電器使用。 FX2 PLC的步進點可分為初

從這段文字中找 出調查用途,然 後填寫下方連結

重點 1: 「行為場所」 、 「行為背景分析」 ,某些固定的行為模式在同 一間隔(指時間)下重複地出現在特定的地點。使用者的行為及

要將變數變換法應用在定積分上,有兩種計算方法。其中的 一種便是先計算出不定積分,在利用微積分基本定理計算其

中國人 稱畢氏定理為勾股 (弦) 或商高定理。 傳統上, 勾股定理的證明是利用四個一樣的 直 角三角形依序排成一個大正方形, 中間空出一個小正方形, 然後利用面積關係得出 「勾股各自 乘,

一種廣為流傳的說法 (存在於涉及該問題的各種圖論教科書, 數學史書籍和數學科普讀 物中) 是: 歐拉將每一塊陸地用一個點來代替, 將每一座橋用連接相應兩個點的一條線來代替, 從而得到了圖2。

指示劑:利用不同酸鹼溶液中變色的性質,方便取得,但較不準確,指示 劑的變色為一漸進過程,有一定的 pH