本文主要介紹了自適應的中值濾波器,並基於OpenCV實現了該濾波器,而且將自適應的中值濾波器和常規的中值濾波器對不一樣機率的椒鹽噪聲的過濾效果進行了對比。最後,對中值濾波器的優缺點了進行了總結。算法
一個空間濾波器包括兩個部分:函數
一個濾波器就是在選定的鄰域像素上執行預先定義好的操做產生新的像素,並用新的像素替換掉原來像素造成新的圖像。
一般,也能夠將濾波器稱之爲核(kernel),模板(template)或者窗口(window)。學習
根據預約義的操做,能夠將濾波器分爲:測試
而根據濾波器最終對圖像形成的影響,能夠將濾波器分爲:spa
中值濾波器是一種經常使用的非線性濾波器,其基本原理是選擇待處理像素的一個鄰域中各像素值的中值來代替待處理的像素,其主要功能是像素的灰度值與周圍像素比較接近,從而消除孤立的噪聲點,因此中值濾波器可以很好的消除椒鹽噪聲。不只如此,中值濾波器在消除噪聲的同時,還能有效的保護圖像的邊界信息,不會對圖像形成很大的模糊(相比於均值濾波器)。3d
中值濾波器的效果受濾波窗口尺寸的影響較大,在消除噪聲和保護圖像的細節存在着矛盾:濾波窗口較小,則能很好的保護圖像中的某些細節,但對噪聲的過濾效果就不是很好;反之,窗口尺寸較大有較好的噪聲過濾效果,可是會對圖像形成必定的模糊。另外,根據中值濾波器原理,若是在濾波窗口內的噪聲點的個數大於整個窗口內像素的個數,則中值濾波就不能很好的過濾掉噪聲。code
上面提到常規的中值濾波器,在噪聲的密度不是很大的狀況下(根據經驗,噪聲的出現的機率小於0.2),效果不錯。可是當機率出現的機率較高時,常規的中值濾波的效果就不是很好了。有一個選擇就是增大濾波器的窗口大小,這雖然在必定程度上能解決上述的問題,可是會給圖像形成較大的模糊。blog
常規的中值濾波器的窗口尺寸是固定大小不變的,就不能同時兼顧去噪和保護圖像的細節。這時就要尋求一種改變,根據預先設定好的條件,在濾波的過程當中,動態的改變濾波器的窗口尺寸大小,這就是自適應中值濾波器 Adaptive Median Filter。在濾波的過程當中,自適應中值濾波器會根據預先設定好的條件,改變濾波窗口的尺寸大小,同時還會根據必定的條件判斷當前像素是否是噪聲,若是是則用鄰域中值替換掉當前像素;不是,則不做改變。排序
自適應中值濾波器有三個目的:文檔
自適應濾波器不但可以濾除機率較大的椒鹽噪聲,並且可以更好的保護圖像的細節,這是常規的中值濾波器作不到的。自適應的中值濾波器也須要一個矩形的窗口\(S_{xy}\),和常規中值濾波器不一樣的是這個窗口的大小會在濾波處理的過程當中進行改變(增大)。須要注意的是,濾波器的輸出是一個像素值,該值用來替換點\((x,y)\)處的像素值,點\((x,y)\)是濾波窗口的中心位置。
在描述自適應中值濾波器時須要用到以下的符號:
自適應中值濾波器有兩個處理過程,分別記爲:A和B。
A :
A1 = \(Z_{med}-Z_{min}\)
A2 = \(Z_{med}-Z_{max}\)
若是A1 > 0 且 A2 < 0,跳轉到 B;
不然,增大窗口的尺寸
若是增大後窗口的尺寸 \(\leq S_{max}\),則重複A過程。
不然,輸出\(Z_{med}\)
B:
B1 = \(Z_{xy}-Z_{min}\)
B2 = \(Z_{xy}-Z_{max}\)
若是B1 > 0 且 B2 < 0,則輸出\(Z_{xy}\)
不然輸出\(Z_{med}\)
過程A的目的是肯定當前窗口內獲得中值\(Z_{med}\)是不是噪聲。若是\(Z_{min} < Z_{med} < Z_{max}\),則中值\(Z_{med}\)不是噪聲,這時轉到過程B測試,當前窗口的中心位置的像素\(Z_{xy}\)是不是一個噪聲點。若是\(Z_{min} < Z_{xy} < Z_{max}\),則\(Z_{xy}\)不是一個噪聲,此時濾波器輸出\(Z_{xy}\);若是不知足上述條件,則可斷定\(Z_{xy}\)是噪聲,這是輸出中值\(Z_{med}\)(在A中已經判斷出\(Z_{med}\)不是噪聲)。
若是在過程A中,獲得則\(Z_{med}\)不符合條件\(Z_{min} < Z_{med} < Z_{max}\),則可判斷獲得的中值\(Z_{med}\)是一個噪聲。在這種狀況下,須要增大濾波器的窗口尺寸,在一個更大的範圍內尋找一個非噪聲點的中值,直到找到一個非噪聲的中值,跳轉到B;或者,窗口的尺寸達到了最大值,這時返回找到的中值,退出。
從上面分析可知,噪聲出現的機率較低,自適應中值濾波器能夠較快的得出結果,不須要去增長窗口的尺寸;反之,噪聲的出現的機率較高,則須要增大濾波器的窗口尺寸,這也符合種中值濾波器的特色:噪聲點比較多時,須要更大的濾波器窗口尺寸。
有了算法的詳細描述,藉助於OpenCV對圖像的讀寫,自適應中值濾波器實現起來也不是很困難。
int minSize = 3; // 濾波器窗口的起始尺寸 int maxSize = 7; // 濾波器窗口的最大尺寸 Mat im1; // 擴展圖像的邊界 copyMakeBorder(im, im1, maxSize / 2, maxSize / 2, maxSize / 2, maxSize / 2, BorderTypes::BORDER_REFLECT); // 圖像循環 for (int j = maxSize / 2; j < im1.rows - maxSize / 2; j++) { for (int i = maxSize / 2; i < im1.cols * im1.channels() - maxSize / 2; i++) { im1.at<uchar>(j, i) = adaptiveProcess(im1, j, i, minSize, maxSize); } }
首先定義濾波器最小的窗口尺寸以及最大的窗口尺寸。
要進行濾波處理,首先要擴展圖像的邊界,以便對圖像的邊界像素進行處理。copyMakeBorder
根據選擇的BorderTypes
使用不一樣的值擴充圖像的邊界像素,具體可參考OpenCV的文檔信息。
下面就是遍歷圖像的像素,對每一個像素進行濾波處理。須要注意一點,不論濾波器多麼的複雜,其每次的濾波過程,都是值返回一個值,來替換掉當前窗口的中心的像素值。函數adpativeProcess
就是對當前像素的濾波過程,其代碼以下:
uchar adaptiveProcess(const Mat &im, int row,int col,int kernelSize,int maxSize) { vector<uchar> pixels; for (int a = -kernelSize / 2; a <= kernelSize / 2; a++) for (int b = -kernelSize / 2; b <= kernelSize / 2; b++) { pixels.push_back(im.at<uchar>(row + a, col + b)); } sort(pixels.begin(), pixels.end()); auto min = pixels[0]; auto max = pixels[kernelSize * kernelSize - 1]; auto med = pixels[kernelSize * kernelSize / 2]; auto zxy = im.at<uchar>(row, col); if (med > min && med < max) { // to B if (zxy > min && zxy < max) return zxy; else return med; } else { kernelSize += 2; if (kernelSize <= maxSize) return adpativeProcess(im, row, col, kernelSize, maxSize); // 增大窗口尺寸,繼續A過程。 else return med; } }
首先,根據當前窗口的大小,取得全部像素值存放到vector中,而後對vector進行排序,取得像素的最小值、最大值和中值。而後測試當前取得的中值是否在(min,max)之間,若是是,則中值不是噪聲點,則開始對當前像素值進行處理,判斷其是不是噪聲點。若是,測試當前已取得的中值是噪聲點,則擴大窗口的尺寸,在更大的空間中從新尋找中值。
上面自適應中值濾波器實現起來比較簡單,因此問題就來了:效率及其的低下。這裏,這是對自適應中值濾波器的原理的學習,能夠忽略這個沒必要要的細節。
左邊是添加機率爲0.2的椒鹽噪聲,右邊是原圖。下面是使用常規的中值濾波和本文實現的自適應中值濾波器後的處理結果
左邊是自適應中值濾波器(最小窗口爲3,最大窗口爲7)的結果,右圖是常規中值濾波器(窗口大小爲5)的結果。能夠看出,不管是中值濾波仍是自適應的中值濾波,都能過濾掉圖像中的噪聲,自適應中值濾波器的效果要好些,常規的還有一些噪聲沒有過濾掉。並且,常規的中值濾波器對圖像形成的模糊較明顯,而自適應中值濾波器很好的的保存了圖像中的細節。
下面測試更大機率噪聲下,兩種濾波器的工做狀況。噪聲機率爲0.4時,
能夠看出,常規的中值濾波器已經不能很好的過濾掉噪聲,而自適應的中值濾波還能夠勝任。