快速中值濾波算法
中值濾波算法:
在圖像處理中,在進行如邊緣檢測這樣的進一步處理之前,通常需要首先進行一定程度的降噪。中值濾波是一種非線性數字濾波器技術,經常用於去除圖像或者其它信號中的噪聲。這個設計思想就是檢查輸入信號中的采樣並判斷它是否代表了信號,使用奇數個采樣組成的觀察窗實現這項功能。觀察窗口中的數值進行排序,位於觀察窗中間的中值作為輸出。然后,丟棄最早的值,取得新的采樣,重復上面的計算過程。中值濾波是圖像處理中的一個常用步驟,它對於斑點噪聲和椒鹽噪聲來說尤其有用。保存邊緣的特性使它在不希望出現邊緣模糊的場合也很有用。
為了演示中值濾波器的工作過程,我們給下面的數組加上觀察窗 3 ,重復邊界的數值:
x = [2 80 6 3]
y[1] = Median[2 2 80] = 2
y[2] = Median[2 80 6] = Median[2 6 80] = 6
y[3] = Median[80 6 3] = Median[3 6 80] = 6
y[4] = Median[6 3 3] = Median[3 3 6] = 3
於是
y = [2 6 6 3]
其中 y 是 x 的中值濾波輸出。
普通中值濾波算法偽代碼:
Input: image X of size m*n, kernel radius r.
output: image Y as X.
for i = r to m - r do
for j = r to n - r do
initialize list A[]
for a = i-r to i+r
for b = j-r to j+r
add X(a, b) to A[]
end
end
sort A[] then Y(i ,j) = A[A.size/2]
end
end
處理前:
處理后:
但是,上述算法在像素處理處的復雜度為O(r2).
OpenCV實現代碼:

#include "cv.h" #include "highgui.h" #include <iostream> using namespace std; using namespace cv; int main(int argc, char* argv[]) { Mat src = imread("beauty.jpg"); Mat dst; //參數是按順序寫的 //高斯濾波 //src:輸入圖像 //dst:輸出圖像 //Size(5,5)模板大小,為奇數 //x方向方差 //Y方向方差 GaussianBlur(src,dst,Size(5,5),0,0); imwrite("gauss.jpg",dst); //中值濾波 //src:輸入圖像 //dst::輸出圖像 //模板寬度,為奇數 medianBlur(src,dst,3); imwrite("med.jpg",dst); //均值濾波 //src:輸入圖像 //dst:輸出圖像 //模板大小 //Point(-1,-1):被平滑點位置,為負值取核中心 blur(src,dst,Size(3,3),Point(-1,-1)); imwrite("mean.jpg",dst); //雙邊濾波 //src:輸入圖像 //dst:輸入圖像 //濾波模板半徑 //顏色空間標准差 //坐標空間標准差 bilateralFilter(src,dst,5,10.0,2.0);//這里濾波沒什么效果,不明白 imwrite("bil.jpg",dst); waitKey(); return 0; }
快速中值濾波算法:
O(r)復雜度的Huang算法:<A Fast Two-Dimensional Median Filtering Algorithm>
這個代碼的核心在於維護一個kernel直方圖,可以實現快速的讀取和刪除掃描區域的像素值。
int StopAmount = (2 * Radius + 1) * (2*Radius +1) * Percentile; int Sum = 0; for (int I = 0; I <= 255; I++) { Sum += HistBlue(I); if (Sum >= StopAmount) // 滿足停止條件 { Value = I; // 得到中值 break; } }
在MFC中實現的huang算法:

/****************************************************************** * 功能: 彩色圖像的快速中值濾波平滑處理 * 參數: image0為原圖形,image1平滑結果, * w、h為圖象的寬和高 * size為進行平滑的鄰域邊長 ******************************************************************/ void FastSmoothMedianCl(BYTE* image0, BYTE* image1, unsigned int w, unsigned int h, unsigned int size) { //將圖像轉化為矩陣形式 BYTE** imageBuf0 = CreatImage(image0, w, h); BYTE** imageBuf1 = CreatImage(image1, w, h); //設定模板 int x,y,c; int a; //int scale; int ** templt; //初始化 x = size/2 為中心的點的直方圖, //根據鄰域大小設定模板 templt = new int*[5]; for(c=0; c<3; c++) { templt[c] = new int [256]; } for(y=size/2; y<h-size/2; y++) { for(c=0; c<3; c++) { for (int i= 0; i< 256; i ++){ templt[c][i] = 0; } for(int i = y-size/2; i < y+size/2; i++){ for (int j = 0; j < size; j++){ int k = imageBuf0[i][j*4+c]; templt[c][k] ++; } } } for(x=size/2+1; x<w-size/2; x++) { for(c=0; c<3; c++) { //取采樣窗口中像素灰度的中值 a=FastMedianValueCl(imageBuf0,w,h,templt,size,x,y,c); //a/= scale; //過限處理 a = a>255?255:a; a = a<0?0:a; imageBuf1[y][x*4+c]=a; } } } //清理內存 for(int i = 0; i < 3; i ++){ delete templt[i]; } free(imageBuf0); free(imageBuf1); } /************************************************** * 功能: 使用直方圖對彩色圖鄰域獲取中值 * 參數: imageBuf為目標圖像 w、h為圖像大小 * templt為模板 tw為鄰域大小 * x,y為當前采樣窗口中心像素的坐標 * cn為顏色分量編號 0為藍色 1為綠色 2為紅色 **************************************************/ int FastMedianValueCl(BYTE** imageBuf0, int w, int h, int**templt, int tw, int x, int y, int cn) { int i,j,k; int px,py, mid; int count = 0; //用來保存采樣窗口的像素數量 int count_temp = 0; k=0; //從采樣窗口中取得像素灰度 for(i=0; i<tw; i++) { py=y-tw/2+i; px=x+tw/2+1; //如果該像素位於采樣窗口 //保存像素灰度 k = imageBuf0[py][px*4+cn]; templt[cn][k]++; px=x-tw/2; //保存像素灰度 k = imageBuf0[py][px*4+cn]; templt[cn][k]--; } for(int a = 0; a < 256; a++){ mid = a; count_temp += templt[cn][a]; if(count_temp > (tw*tw)/2) break; } return mid; }
與普通算法的比較:
O(1)復雜度的CTMF算法:<Median Filter in Constant Time.pdf>
首先,對於每一列圖像,我們都為其維護一個直方圖(對於8位圖像,該直方圖有256個元素),在整個的處理過程中,這些直方圖數據都必須得到維護。每列直方圖累積了2r+1個垂直方向上相鄰像素的信息,初始的時候,這2r+1個像素是分別以第一行的每個像素為中心的。核的直方圖通過累積2r+1個相鄰的列直方圖數據獲取。其實,我們所做的就是將核直方圖分解成他對應的列直方圖的集合,在整個濾波的過程中,這些直方圖數據在兩個步驟內用恆定的時間保持最新。
考慮從某個像素向右移動一個像素的情況。對於當前行,核最右側的列直方圖首先需要更新,而此時該列的列直方圖中的數據還是以上一行對應位置那個像素為中心計算的。因此需要減去最上一個像素對應的直方圖然后加上其下面一像素的直方圖信息。這樣做的效果就是將列直方圖數據降低一行。這一步很明顯是個0(1)操作,只有一次加法和一次減法,而於半徑r無關。
第二步更新核直方圖,其是2r+1個列直方圖之和。這是通過減去最左側的列直方圖數據,然后再加上第一步所處理的那一列的列直方圖數據獲得的。這一步也是個O(1)操作,如圖2所示。如前所述,加法、減法以及計算直方圖的中值的耗時都是一些依賴於圖像位深的計算,而於濾波半徑無關。
這個算法較之前的Huang算法的差別在於,充分利用了之前的數據,這有點類似於動態規划,也是用空間換取時間的策略。
參考博客:http://www.cnblogs.com/Imageshop/archive/2013/04/26/3045672.html