基於Opencv的自適應中值濾波函數selfAdaptiveMedianBlur()


 7.3.3 自適應濾波器

自適應中值濾波器

對於7.3.2節所討論的中值濾波器,只要脈沖噪聲的空間密度不大,性能還是可以的(根據經驗需Pa和Pb小於0.2)。本節將證明,自適應中值濾波器可以處理更大概率的脈沖噪聲。自適應中值濾波器的另一個優點是平滑非脈沖噪聲時,試圖保留細節,這是傳統中值濾波器所做不到的。正如前面幾節中所討論的所有濾波器一樣,自適應中值濾波器也工作於矩形窗口區域Sxy然而與這些濾波器不同的是自適應中值濾波器在進行濾波處理時會根據本節列舉的某些條件而改變增大或縮小)Sxy的尺寸記住濾波器的輸出是一個單值該值用於替代點(x,y)處的像素值,位於(x,y)處的是Sxy的中心也是它的錨點

 

考慮如下符號:

Zmin=Sxy中的最小灰度值

Zmax=Sxy中的最大灰度值

Zmed=Sxy中的中值;

Zxy=坐標(x,y)處的灰度值

Smax=Sxy允許的最大尺寸(在程序中,用kernal_size表示)

自適應中值濾波算法以兩個進程工作,分別為進程AB,如下所示:

進程A:

     如果Zmin<Zmed<Zmax,則轉到進程B
     否則增大窗口尺寸;
     增大后的窗口尺寸(程序中用ks表示),
     如果ks<Smax,則重復A。(在程序中,kernal_size即Smax)
     否則輸出Zmed

進程B:

     如果Zmin<Zxy<Zmax,則輸出Zxy
     否則,輸出Zmed.

 

    該算法的設計意圖是要實現3個目的:①去除椒鹽噪聲;②平滑其它非脈沖噪聲;③減少物體邊界細化或粗化的失真。Zmin和Zmax在算法統計上認為是類脈沖噪聲分量,既使它們不是圖像中的最大值或最小值。

    進程A的目的是確定中值濾波器的輸出Zmed,是否是一個脈沖黑或白)。如果條件Zmin<Zmed<Zmax有效則根據前節提到的原因,Zmed不可能是脈沖這種情況下轉到進程B,檢驗窗口Sxy的中心點Zxy(即錨點)是否是一個脈沖如果滿足條件就不是脈沖原因與前同這時算法輸出一個未修改的像素值Zxy通過不修改這些中間灰度級的點減少圖像中的失真。如果Zmin<Zxy<Zmax為假則Zxy=Zmin或Zxy=Zmax在任何一種情況下像素值都是一個極端值且算法輸出中值Zmed,從進程A可知Zmed不是脈沖噪聲最后一步是執行標准的中值濾波問題是標准中值濾波器使用圖像中相應鄰域的中值代替圖像中的每一點這會引起不必要的細節損失

    繼續上面的說明,假設進程A確實找到了一個脈沖(若不是,則轉到進程B),算法會增大窗口尺寸,並重復進程A。該循環會一直繼續,直到算法找到一個非脈沖的中值,並轉到進程B。如果循環中窗口達到了最大尺寸,則算法會返回值Zmed。注意,這並不能保證該值不是脈沖。噪聲的概率Pa或Pb越小,或者在Sxy允許的范圍內越大,退出條件也就越難滿足。這是合理的,隨着脈沖密度的增大,我們會需要更大的窗口來消除尖峰噪聲。

算法沒輸出一個值,窗口Sxy就被移動到圖像中的下一個位置。然后,算法重新初始化並應用到新位置的像素。僅使用新像素就可以反復更新中值,因而減少了計算開銷。

 

 

 

#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
#include <algorithm>
using namespace cv;
using namespace std;
//下面的宏,定義了在矩陣src的第m行、n列,ks*ks覆蓋的矩形區域內的像素,並將像素壓到矢量v中
//該覆蓋區域的左上角坐標為(m,n),寬為ks,高為ks,要求src必須是單通道,數據類型為CV_8UC1
#define CV_ROI_ELEM(src,vector,m,n,ks)  \
{                                      \
    uchar* kn;                         \
    int st0=src.step[0];\
    int st1=src.step[1];\
    for(int k=0;k<(ks);k++)            \
    {                                  \
        for(int s=0;s<(ks);s++)        \
        {                              \
            kn =src.data+(k+m)*st0+(s+n)*st1;   \
            vector.push_back(*kn);              \
        }                                       \
    }                                           \
}

#define CV_MAT_ELEM2(src,dtype,y,x) \
    (dtype*)(src.data+src.step[0]*(y)+src.step[1]*(x))
/*********************自適應中值濾波********************************/
void selfAdaptiveMedianBlur(Mat&src,Mat&dst,int kernal_size)
{
    CV_Assert(src.type()==CV_8UC1||src.type()==CV_8U);
    if(dst.empty())
    {
        dst.create(src.rows,src.cols,CV_8UC1);
    }
    uchar* pdst=dst.data;
    uchar Zmin,Zmax,Zmed,Zxy;
    int step0=src.step[0];
    int step1=src.step[1];
    for(int i=kernal_size/2;i<src.rows-kernal_size/2;i++)
    {
        for(int j=kernal_size/2;j<src.cols-kernal_size/2;j++)
        {
            int ks=3;//kernal_size;
            int count=0;
            Zxy=*CV_MAT_ELEM2(src,uchar,i,j);//Sxy覆蓋區域的中心點像素值,即錨點像素值
            vector<uchar> v;//將模板覆蓋區域的像素,壓入矢量v中
            do{
                if(cout==0)
                {//獲取模板ks*ks覆蓋區域的像素,壓入矢量v中
                    CV_ROI_ELEM(src,v,i-ks/2,j-ks/2,ks);
                }
               else
                {
               /****************下面的for循環,將外擴的四個邊的像素添加到v中**************/
                    uchar* p=src.data+(i-ks/2)*step0+(j-ks/2)*step1;
                    for(int u=0;u<ks;u++)
                    {
                        v.push_back(*(p+u*step1));//向外擴展的四個邊的上邊
                        v.push_back(*(p+(ks-1)*step0+u*step1));//向外擴展的四個邊的下邊
                        if(u!=0&&u!=ks-1)
                        {
                          v.push_back( *(p+u*step0));//向外擴展的四個邊的左邊
                          v.push_back(*(p+u*step0+(ks-1)*step1));//向外擴展的四個邊的右邊
                        }
                    }
                }

                //對v的元素排序
                //排序后,Sxy覆蓋區域內,最大值為Zmax=v[v.size-1],最小值為Zmin=v[0]
                std::sort(v.begin(),v.end());
                Zmin=v[0],Zmax=v[v.size()-1],Zmed=v[ks*ks/2];
                pdst =CV_MAT_ELEM2(dst,uchar,i,j);
                if(Zmin<Zmed&&Zmed<Zmax)
                {
                    if(Zmin<Zxy&&Zxy<Zmax)
                        {*pdst=Zxy;break;}
                    else
                        {*pdst=Zmed;break;}
                }
                else
                {
                    ks +=2;
                }
                count++;
            }while(ks<=kernal_size);

            *pdst=Zmed;
        }
    }
}


int main()
{
    Mat src=imread("D:\\Qt\\MyImage\\3.bmp",0);
    imshow("src image",src);

    Mat dst;
    selfAdaptiveMedianBlur(src,dst,7);

    imshow("adaptive median filter",dst);

    waitKey();

    return 0;
}

 

 

原圖像:

自適應中值濾波后的圖像:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM