自适应中值滤波器
传统中值滤波器处理低概率椒盐噪声退化的图像效果令人满意 但是对于 P = 0.2 的脉冲噪声退化过的图片的处理效果就很令人失望,会丢失很多细节,由此,自适应中值滤波器诞生,与传统不同的是,自适应中值滤波器尝试保留细节。
冈萨雷斯中给出的过程是:
进程A:
A1 = Z<sub>med</sub> -Z<sub>min</sub>
A2 = Z<sub>med</sub> -Z<sub>max</sub>
if(A1 > 0 && A2 < 0 )
goto B
else if ( S < S<sub>max</sub>)
goto A
else
return Z<sub>med</sub>
进程B:
B1 = Z<sub>xy</sub> -Z<sub>min</sub>
B2 = Z<sub>xy</sub> -Z<sub>max</sub>
if(B1 > 0 && B2 < 0 )
return Z<sub>xy</sub>
else
return Z<sub>med</sub>
过程的主要思想就是 如果当前像素点灰度值不是脉冲,则保留,当滤波器扩大到指定最大之后则选取中值为结果,可能该处是边缘。
突发奇想 既然要尽可能多的保留图像原本细节 为什么不把B过程和A过程交换一下逻辑 经过试验结果是差不多的0。0
实验图片
#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
string st = "E:\\冈萨雷斯OpenCV重写\\DIP3E_CH05_Original_Images\\DIP3E_CH05_Original_Images\\";
//自己尝试
uchar autoMedianFilter(Mat src,int i,int j, int Smax, int Smin,int Snow = -1)
{
if (Snow == -1){ Snow = Smin; }
double Zmin;
double Zmax;
double Zmed;
double Zxy;
double A1;
double A2;
double B1;
double B2;
Mat dst = src.clone();
Mat tmp;
Mat tmp2(Size(pow(Snow,2),1),CV_8UC1);
tmp = dst(Rect(j-Snow/2, i-Snow/2, Snow, Snow)).clone();
for (int z = 0; z < Snow; z++)
for (int z1 = 0; z1 < Snow;z1++)
{
tmp2.at<uchar>(z*Snow + z1) = tmp.at<uchar>(z, z1);
}
cv::sort(tmp2, tmp2, CV_SORT_ASCENDING);
Zxy = tmp.at<uchar>(Snow / 2, Snow / 2);
Zmin = tmp2.at<uchar>(0);
Zmax = tmp2.at<uchar>(Snow*Snow-1);
Zmed = tmp2.at<uchar>(Snow*Snow / 2 );
A1 = Zmed - Zmin;
A2 = Zmed - Zmax;
B1 = Zxy - Zmin;
B2 = Zxy - Zmax;
if (B1 > 0 && B2 < 0)
{
return Zxy;
}
else
{
if (A1>0 && A2 < 0)
{
return Zmed;
}
else
{
Snow += 2;
if (Snow >= Smax){ return Zmed; }
else{ return autoMedianFilter(src, i, j, Smax, Smin, Snow); }
}
}
}
//书中的方法
uchar autoMedianFilter2(Mat src, int i, int j, int Smax, int Smin, int Snow = -1)
{
if (Snow == -1){ Snow = Smin; }
double Zmin;
double Zmax;
double Zmed;
double Zxy;
double A1;
double A2;
double B1;
double B2;
Mat dst = src.clone();
Mat tmp;
Mat tmp2(Size(pow(Snow, 2), 1), CV_8UC1);
tmp = dst(Rect(j - Snow / 2, i - Snow / 2, Snow, Snow)).clone();
for (int z = 0; z < Snow; z++)
for (int z1 = 0; z1 < Snow; z1++)
{
tmp2.at<uchar>(z*Snow + z1) = tmp.at<uchar>(z, z1);
}
cv::sort(tmp2, tmp2, CV_SORT_ASCENDING);
Zxy = tmp.at<uchar>(Snow / 2, Snow / 2);
Zmin = tmp2.at<uchar>(0);
Zmax = tmp2.at<uchar>(Snow*Snow - 1);
Zmed = tmp2.at<uchar>(Snow*Snow / 2);
A1 = Zmed - Zmin;
A2 = Zmed - Zmax;
B1 = Zxy - Zmin;
B2 = Zxy - Zmax;
if (A1>0 && A2 < 0)
{
if (B1 > 0 && B2 < 0)
{
return Zxy;
}
else
{
return Zmed;
}
}
else
{
Snow += 2;
if (Snow >= Smax){ return Zmed; }
else{ return autoMedianFilter2(src, i, j, Smax, Smin, Snow); }
}
}
void main()
{
Mat srcImage = imread(st + "Fig0514(a)(ckt_saltpep_prob_pt25).tif",0);
imshow("原图像",srcImage);
Mat dstImage = srcImage.clone();
copyMakeBorder(srcImage, dstImage, 7, 7, 7, 7, BORDER_REPLICATE);
for (int i = 4; i < dstImage.rows-4;i++)
for (int j = 4; j < dstImage.cols-4; j++)
{
//这里要用改变后的图像进行计算 逐步优化,使用初始图片效果不会很理想
dstImage.at<uchar>(i, j) = autoMedianFilter(dstImage, i, j, 7, 3);
}
dstImage = dstImage(Rect(7,7,srcImage.cols,srcImage.rows));
imshow("自适应中值滤波后1",dstImage);
copyMakeBorder(srcImage, dstImage, 7, 7, 7, 7, BORDER_REPLICATE);
for (int i = 4; i < dstImage.rows - 4; i++)
for (int j = 4; j < dstImage.cols - 4; j++)
{
dstImage.at<uchar>(i, j) = autoMedianFilter2(dstImage, i, j, 7, 3);
}
dstImage = dstImage(Rect(7, 7, srcImage.cols, srcImage.rows));
imshow("自适应中值滤波后2", dstImage);
Mat medianImage = srcImage.clone();
medianBlur(srcImage, medianImage, 7);
imshow("中值滤波器7*7",medianImage);
waitKey(0);
}
加油 坚持