中值濾波(median filter)在數字圖像處理中屬於空域平滑濾波的內容(spatial filtering)。對消除椒鹽噪聲具備很好的效果。html
爲了講述的便捷,咱們以灰度圖爲例。RGB三通道的彩色圖能夠經過每個通道各自的中值濾波聯合獲得。函數
數字圖像是以矩陣的方式存儲的,具體存儲方式能夠參見OpenCV手冊。中值濾波是經過所謂的mask operation操做進行的。以3x3的mask爲例。設圖像的矩陣形式以下:spa
0,0 | 0,1 | 0,2 | 0,3 | 0,4 | 0,5 |
1,0 | 1,1 | 1,2 | 1,3 | 1,4 | 1,5 |
2,0 | 2,1 | 2,2 | 2,3 | 2,4 | 2,5 |
3,0 | 3,1 | 3,2 | 3,3 | 3,4 | 3,5 |
4,0 | 4,1 | 4,2 | 4,3 | 4,4 | 4,5 |
5,0 | 5,1 | 5,2 | 5,3 | 5,4 | 5,5 |
圖中每一個方框表明一個像素,每一個方框裏的數字對錶明該像素在圖中的位置。中值濾波從位置(1,1)開始,創建一個3x3的mask指針
i-1,j-1 | i-1,j | i-1,j+1 |
i,j-1 | i,j | i,j+1 |
i+1,j-1 | i+1,j | i+1,j+1 |
讓(1,1)與(i,j)對其,取出模板所覆蓋的範圍內像素值,取這九個值得中值而後賦給(1,1),做爲(1,1)位置的新像素值。而後移動模板的中心(i,j)至(1,2),重複上面的操做,直至遍歷整幅圖片。這裏面應該注意的是,咱們在作中值濾波時,模板裏的中值是賦給一個新建的全新圖像,被濾波的圖像像素值不會改變。這樣就保證了每一次模板覆蓋的區域都是原圖像的像素。code
注:orm
OpenCV中也用現成的中值濾波函數medianblur,具體用法爲htm
medianBlur(InputArray src,OutputArray dst,int ksize);
其中InputArray src爲Mat類的被濾波圖片,OutputArray是Mat類的濾波後輸出結果,ksize是mask的大小,如,若是用3x3的模板,ksize就傳值3;blog
基於OpenCV的中指濾波代碼段以下,排序
1 //load the Original Image and get some informations 2 Mat src = imread("010.jpg",1); 3 namedWindow("OriginalImage"); 4 imshow("OriginalImage",src); 5 CV_Assert(src.depth() == CV_8U); 6 const int nr = src.rows; 7 const int nc = src.cols; 8 const int nchannels = src.channels(); 9 10 //OpenCV Solution 11 Mat result_opencv; 12 medianBlur(src,result_opencv,3); 13 namedWindow("median filter_opencv"); 14 imshow("median filter_opencv",result_opencv);
仿真結果:圖片
原圖:
用medianBlur中值濾波的結果:
此次咱們進行的再也不是灰度圖的仿真,因此有必要簡單介紹一下彩色圖在Mat類裏保存的方式,見下圖(來源:opencv.org)。
從圖中咱們能夠看到,彩色圖片中像素的三通道是保存在同一行中的,順序是BGR。假如指針p[i]定位到的是(0,1)的藍色通道,那麼p[i+Mat.channels]定位到的就是下一列的藍色通道。
基於中值濾波原理編寫的中值濾波函數代碼段以下
1 //own median filter algorithm 2 uchar* previous = NULL; 3 uchar* current = NULL; 4 uchar* next = NULL; 5 uchar* current_result_own = NULL; 6 int arr[9]; //use 3*3 mask 7 for(int i=1;i<nr-1;i++) 8 { 9 previous = src.ptr<uchar>(i-1); 10 current = src.ptr<uchar>(i); 11 next = src.ptr<uchar>(i+1); 12 current_result_own = result_own.ptr<uchar>(i); 13 for(int j=nchannels;j<nchannels*(nc-1);j++) 14 { 15 for(int k=0;k<3;k++) 16 { 17 arr[k] = previous[j+(k-1)*nchannels]; 18 arr[k+3] = current[j+(k-1)*nchannels]; 19 arr[k+6] = next[j+(k-1)*nchannels]; 20 } 21 bubble_sort(arr,9); 22 current_result_own[j] = arr[4]; 23 } 24 } 25 26 //set the pixels on the borders to zeros 27 result_own.row(0).setTo(Scalar(0)); 28 result_own.row(nr-1).setTo(Scalar(0)); 29 result_own.col(0).setTo(Scalar(0)); 30 result_own.col(nc-1).setTo(Scalar(0)); 31 32 //show the result 33 namedWindow("median filter_own"); 34 imshow("median filter_own",result_own);
其中bubble_sort是我用冒泡排序法寫的排序函數,代碼段以下,
1 //************************// 2 //bubble sort 3 //************************// 4 void bubble_sort(int* arr,int num) 5 { 6 int temp; 7 for(int i=1;i<num-1;i++) 8 { 9 for(int j=0;j<num-i;j++) 10 { 11 if(arr[j]>arr[j+1]) 12 { 13 temp = arr[j]; 14 arr[j] = arr[j+1]; 15 arr[j+1] = temp; 16 } 17 } 18 } 19 }
仿真結果: