OpenCV-跟我學一塊兒學數字圖像處理之中值濾波

中值濾波(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

  1. mask並不必定要用3x3的矩陣來作,模板的大小不是必定的。
  2. 從上面的操做過程能夠看到,在圖像的最後一行和第一行,最後一列和第一列的像素都沒有被遍歷到,咱們通常有兩種方案解決這個問題。
    1. 能夠將該位置的全部像素賦值爲零。
    2. 能夠在原圖像的上下左右都加上相應的全零向量,而後再進行上述的中值濾波操做,這樣全部原圖的像素均可以被遍歷到。
  • 基於OpenCV中值濾波程序

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)。

圖片來源: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 }

仿真結果:

相關文章
相關標籤/搜索