我想學過圖像處理的人沒有人會不知道中值濾波的,最早的時候我是在岡薩雷斯的圖像處理課本[1]中學到的,后來在看Sonka的書[2]的時候又看到了中值濾波的介紹,下面我試着結合課本所學和網上的資料自己整理一篇中值濾波的介紹。
中值濾波器是一種統計排序濾波器,由Tukey於1971年在文獻[3]中提出。所謂的統計排序濾波器是一種非線性的空間濾波器,它的響應基於圖像濾波器包圍的圖像區域中像素的排序,然后用統計排序結果決定的值代替中心像素的值。除了中值濾波器外,最大值濾波器和最小值濾波器也是統計排序濾波器。在介紹中值濾波器之前,我們先來了解一下中值的概念,中值是一個將概率分布的高半部分與低半部分分開的值。對一個隨機變量x而言,x<M的概率為0.5。對於有限實數集,其排序后中間的數值即為它的中值。這樣,我們就可以很清楚的知道,中值濾波就是將鄰域內像素(包括中心像素值)灰度值的中值代替中心像素的值。
在圖像處理中,中值濾波的使用非常的普遍,這是因為對於一定類型的隨機噪聲,它提供了一種優秀的去噪能力,相比於小尺寸的線性平滑濾波器的模糊程度要低很多。而且它對處理脈沖噪聲(椒鹽噪聲)非常有效。那它為什么能夠去噪呢?我們知道,因為噪聲的出現,使某像素點比周圍的像素亮(暗)許多,若與周圍的像素值一起排序,噪聲點則位於序列的前端或末端,序列中值通常沒有受到噪聲污染,因此,可以用中值取代原像素值來達到出去噪聲的效果。
下面我們看一個直觀的例子:
f = imread('C:/a.jpg'); f_gray = rgb2gray(f); subplot(1,3,1); imshow(f_gray); title('原圖'); fn = imnoise(f_gray, 'salt & pepper', 0.2); subplot(1,3,2); imshow(fn); title('椒鹽噪聲'); fm = medfilt2(fn, 'symmetric'); subplot(1,3,3); imshow(fm); title('中值濾波');
從上圖可以看出,中值濾波后的效果還是相當不錯的。
接下來,我們着重看看如何實現中值濾波。
Pseudo Code:
allocate outputPixelValue[image width][image height]
edgex := (window width / 2) rounded down edgey := (window height / 2) rounded down for x from edgex to image width - edgex for y from edgey to image height - edgey allocate colorArray[window width][window height] for fx from 0 to window width for fy from 0 to window height colorArray[fx][fy] := inputPixelValue[x + fx - edgex][y + fy - edgey] sort all entries in colorArray[][] outputPixelValue[x][y] := colorArray[window width / 2][window height / 2]
C++ Code:
bool median_Filter (unsigned char* input, unsigned char* output, int height, int weight) { if (input == NULL) { return false; } memset (output, 0, sizeof(unsigned char)*height*weight); for (int i = 1; i < height-1; ++i) { for (int j = 1; j < weight-1; ++j) { int k = 0; unsigned char filter_Region[9]; for (int ii = i-1; ii < i+2; ++ii) { for (int jj = j-1; jj < j+2; ++jj) { filter_Region[k++] = input[ii+width + jj]; } } for (int m = 0; m < 5; ++m) { int min = m; for (int n = m+1; n < 9; ++n) { if (filter_Region[n] < filter_Region[min]) { min = n; } } unsigned char tmp = filter_Region[m]; filter_Region[m] = filter_Region[min]; filter_Region[min] = tmp; } output[i*width + j] = filter_Region[4]; } } return true; }
從上面的程序可以發現,在每個像素位置上都要對一個矩形內部的所有像素進行排序,這樣的開銷會變得很大。因此下面介紹一種更為有效的方法[4],我們注意到當窗口沿着行移動一列時,窗口內容的變化只是丟掉最左邊的列取代為一個新的右側列,對於m行n列的中值窗口,mn-2*m個像素沒有變化,並不需要重新排序。算法如下: