基於閾值分解的多級中值濾波
基於閾值分解的多級中值濾波的結構如下所示:
首先對整個圖像統計,得到均值m,和標準差δ,並進行閾值的分解,閾值分解函數Ti()爲:
從圖1中,噪灰度圖像首先在(m-kδ)和(m+kδ),兩個閾值上分解爲2個二值圖像。k爲參數,適當選擇k可以使這2個二值圖像反映大部分脈衝噪聲所處位置的信息。2幅二值圖像經過中值濾波後再分別於濾波之前的二值圖像作“異或Xor”運算,其目的是得到已被濾除的脈衝噪聲位置。然後再對2幅圖做“或or”運算,就可以得到總體脈衝噪聲位置分佈矩陣。最後在噪聲位置處濾波,這樣可以在去除噪聲的同時儘可能地保留細節。
代碼如下:
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
void YZmedian(Mat& I, Mat& Iout, int n=3, double k=1.6)
{
cvtColor(I,I,COLOR_BGR2GRAY);//灰度圖轉換
Mat temp_m,temp_std; //定義均值方差矩陣
meanStdDev(I,temp_m,temp_std);//求均值方差矩陣
double Im_m=temp_m.at<double>(0,0);//均值
double Im_std=temp_std.at<double>(0,0);//方差
double t1=Im_m-k*Im_std;//閾值1
double t2=Im_m+k*Im_std;//閾值2
Mat I1=I.clone();
Mat I2=I.clone();
int width=I.cols;
int height=I.rows;
for (int i = 0; i < height; i++)
{
uchar* data1 =I1.ptr<uchar>(i);
uchar* data2=I2.ptr<uchar>(i);
for (int j = 0; j < width; j++)
{
if (data1[j]>=t1)
{
data1[j]=1;
}
else
{
data1[j]=0;
}
if (data2[j]>=t2)
{
data2[j]=1;
}
else
{
data2[j]=0;
}
}
}
Mat I11,I22;
medianBlur(I1,I11,n);//中值濾波
medianBlur(I2,I22,n);//中值濾波
Mat I111,I222;
bitwise_xor(I1,I11,I111);
bitwise_xor(I2,I22,I222);
Mat I3;
bitwise_or(I111,I222,I3);
/*擴展邊界方便濾波*/
Mat I4(Size(I3.rows+(n-1),I3.cols+(n-1)),CV_8U,Scalar(0));
Mat I5(Size(I3.rows+(n-1),I3.cols+(n-1)),CV_8U,Scalar(0));
I.copyTo(I4(Range((n-1)/2,I4.rows-(n-1)/2),Range((n-1)/2,I4.cols-(n-1)/2)));
I3.copyTo(I5(Range((n-1)/2,I4.rows-(n-1)/2),Range((n-1)/2,I4.cols-(n-1)/2)));
//在噪聲處濾波
for (int i = 0; i < I4.rows; i++)
{
uchar* data1=I4.ptr<uchar>(i);
uchar* data2=I5.ptr<uchar>(i);
for (int j = 0; j < I4.cols; j++)
{
if(data2[j]==1)
{
Mat roi=I4(Range(i-(n-1)/2,i+(n-1)/2),Range(j-(n-1)/2,j+(n-1)/2));
resize(roi,roi,Size(1,n*n));
Mat index;
sortIdx(roi,index,SORT_EVERY_COLUMN+SORT_ASCENDING);
int x=index.at<int>((n*n-1)/2);
data1[j]=roi.at<uchar>(x);
}
}
}
Iout=I4(Range((n-1)/2,I4.rows-(n-1)/2),Range((n-1)/2,I4.cols-(n-1)/2)).clone();
}
int main()
{
Mat I=imread("Nimg.png");//讀取原始圖片
Mat Iout;
Mat Imdian;
medianBlur(I,Imdian,7);
YZmedian(I,Iout,7,1.6);
imshow("原始圖像",I);
imshow("基於閾值分解的多級中值濾波後的圖像",Iout);
imshow("傳統中值濾波",Imdian);
waitKey(0);
return 0;
}
結果如下圖所示: