直方圖均衡化和空間濾波
1習題
1.1 直方圖均衡化
假設你對一張圖已經進行了一次直方圖均衡化的操作。如果對這張圖進行第二次直方圖均衡化,得到的結果跟第一次均衡化的結果一樣嗎?請給予證明。
直方圖均衡化處理是把原始圖像的灰度直方圖從比較集中的某個灰度區間變成在全部灰度範圍內的均勻分佈,就是對圖像進行非線性拉伸,重新分配圖像像素值,使一定灰度範圍內的像素數量大致相同。它的基本思想是對圖像中像素個數多的灰度級進行展寬,而對圖像中像素個數少的灰度進行壓縮,從而擴展像原取值的動態範圍。
L爲圖像灰度級,
所以由直方圖均衡化變化的原理可以得出結論,對圖片第二次直方圖均衡化之後的變換函數跟第一次直方圖均衡化結果一樣,直方圖均衡化結果也相同。
1.2 空間濾波
給定一張 4 x 4 的灰度圖和一個 3 x 3 的濾波器:
圖像:
濾波器:
- 用給定的濾波器對這張灰度圖(邊界補零)進行卷積,寫出卷積後的結果(大小應爲 4 x
4)。
- 請說出你得到的卷積結果中正數和負數分別表示什麼含義。
正數表示從垂直方向由上往下灰度值遞減,負數表示從垂直方向由上往下灰度值遞曾,即看絕對值。
- 根據你所學到的知識, 談一談題目中給出的 3 x 3 濾波器可以有哪些應用。
可做水平匹配濾波邊緣檢測
2編程題
2.1直方圖均衡化
- 計算並顯示圖像的直方圖, 並把結果粘貼到報告裏。注意:你必須用你自己實現的函數
來計算直方圖,但是允許調用現成的 API 來顯示直方圖。 (例如,你不能調用 Matlab 的“imhist”
來計算直方圖,但是可以調用“subplot” , “hist”來顯示直方圖。 )
進行直方圖均衡化,將均衡化後的結果和相應的直方圖粘貼到報告裏。
- 分析直方圖均衡化後的結果,字數不能超過一頁。
直方圖均衡化處理之後,原來比較少像素的灰度會被分配到別的灰度去,像素相對集中, 處理後灰度範圍變大,對比度變大,清晰度變大,所以能有效增強圖像。
原圖中灰度強的點比較多,所以直方圖均衡化後,分佈在灰度弱的點也比較多。
3.詳細描述你是如何實現直方圖均衡化操作的,也就是說,針對“equalize_hist”函數進
行算法說明,字數不能超過兩頁。請集中在算法描述方面,不要過多地複製/粘貼代碼到報告上。
直方圖均衡化遵循上面的公式
先計算出圖像中每個的的灰度級的點數,然後求CDF,在將原來點灰度級別重新分配。
直方圖均衡化主要代碼
double k = (double)255 / (double)(height * width);
double[] c = new double[256];
c[0] = k * array[0];
for (int i = 1; i < 256; i++) {
c[i] = c[i - 1] + k * array[i];
}
2.2空間濾波
- 分別用 3 x 3, 7 x 7 和 11 x 11 的均值濾波器來平滑你輸入的圖像,將相應的三個輸出結
果粘貼到報告裏。
3×3
7×7
11×11
2.用 3 x 3 的拉普拉斯濾波器來銳化你輸入的圖像(課本上有 4 種拉普拉斯濾波器,參見圖
3.37, 你可以使用其中任意一種),並將輸出結果放在報告中。除此之外,請簡單介紹一下爲什
麼拉普拉斯濾波器可以用於圖像的銳化。
使用矩陣進行拉普拉斯變換
實驗結果:
拉普拉斯銳化圖像是根據圖像某個像素的周圍像素到此像素的突變程度有關,也就是說它的依據是圖像像素的變化程度。我們知道,一個函數的一階微分描述了函數圖像是朝哪裏變化的,即增長或者降低;而二階微分描述的則是圖像變化的速度,急劇增長下降還是平緩的增長下降。
當鄰域中心像素灰度低於它所在的領域內其它像素的平均灰度時,此中心像素的灰度應被進一步降低,當鄰域中心像素灰度高於它所在的鄰域內其它像素的平均灰度時,此中心像素的灰度應被進一步提高,以此實現圖像的銳化處理。
3.將高提升濾波(high-boost filter) 用在輸入的圖像中 (也就是說,
g(x,y)=f(x,y)+k∗gmax(x,y) 其他細節參見課本式(3.6-9))。過程中涉及的平滑部分應用用課本圖 3.32(a)所示的濾波器來完成。請自行選擇合適的 k(式(3.6-9)中的權值)。在報告中,你需要說明你選擇的 k的值,並貼上對應的輸出結果。
我們選擇k=2
實驗結果:
- 詳細描述你是如何實現空間濾波操作的,也就是說,針對“filter2d”函數進行算法說
明,字數不能超過兩頁。
用濾波矩陣對圖像矩陣進行卷積操作,濾波變換原圖像的點數不變,控制好邊緣的點對應相乘相加。
關鍵代碼:
public int[][] getFilteringArray(int[][] imageArray, int[][] filteringArray) {
int height = imageArray.length, width = imageArray[0].length;
int[][] temp = new int[height][width];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
temp[i][j] = getFilteringValue(i, j, imageArray, filteringArray);
}
}
return temp;
}
public int getFilteringValue(int row, int col, int[][] imageArray, int[][] filteringArray) {
int count = 0;
int height = imageArray.length, width = imageArray[0].length;
int filterLength = filteringArray.length;
int gap = (filterLength - 1) / 2;
for (int i = 0; i < filterLength; i++) {
for (int j = 0; j < filterLength; j++) {
if (row + i - gap >= 0 && row + i - gap < height &&
col + j - gap >= 0 && col + j - gap < width) {
count += imageArray[row + i - gap][col + j - gap];
}
}
}
return count / (filterLength * filterLength);
}
將完整代碼放在github上了,需要的可以參考。