谈谈中值滤波无效性:
不谈线性滤波,实用性不大,基本没用。
中值滤波的简单在于选择灰度值的中值来替代该像素点的灰度值,该方法去除椒盐噪声,还勉强可以。但对绝大部分图像来说,不合适。但是比起线性滤波来说,优势还是蛮大的。单单从消除噪声来说和保边来说,更胜一筹。
但是对于细节图像来说,就显得捉襟见肘了。这也是在处理细节图像上,不建议使用中值滤波的原因。
下面就验证一下,先生成高斯噪声,用中值滤波看看效果:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <cstdlib>
#include <cmath>
#include <limits>
#include <iostream>
using namespace cv;
using namespace std;
double generateGaussianNoise(double mu, double sigma)
{
//定义一个特别小的值
const double epsilon = numeric_limits<double>::min();//返回目标数据类型能表示的最逼近1的正数和1的差的绝对值
static double z0, z1;
static bool flag = false;
flag = !flag;
//flag为假,构造高斯随机变量
if (!flag)
return z1*sigma + mu;
double u1, u2;
//构造随机变量
do
{
u1 = rand()*(1.0 / RAND_MAX);
u2 = rand()*(1.0 / RAND_MAX);
} while (u1 <= epsilon);
//flag为真构造高斯随机变量X
z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI * u2);
z1 = sqrt(-2.0*log(u1))*sin(2 * CV_PI * u2);
return z0*sigma + mu;
}
Mat addGaussianNoise(Mat& srcImage)
{
Mat resultImage = srcImage.clone(); //深拷贝,克隆
int channels = resultImage.channels(); //获取图像的通道
int nRows = resultImage.rows; //图像的行数
int nCols = resultImage.cols*channels; //图像的总列数
//判断图像的连续性
if (resultImage.isContinuous()) //判断矩阵是否连续,若连续,我们相当于只需要遍历一个一维数组
{
nCols *= nRows;
nRows = 1;
}
for (int i = 0; i < nRows; i++)
{
for (int j = 0; j < nCols; j++)
{ //添加高斯噪声
int val = resultImage.ptr<uchar>(i)[j] + generateGaussianNoise(2, 0.8) * 32;
if (val < 0)
val = 0;
if (val > 255)
val = 255;
resultImage.ptr<uchar>(i)[j] = (uchar)val;
}
}
return resultImage;
}
int main()
{
Mat srcImage = imread("D:\\1.jpg");
imshow("srcImage", srcImage);
Mat resultImage1 = addGaussianNoise(srcImage);
Mat resultImage2;
medianBlur(resultImage1, resultImage2, 7);
imshow("resultImage1", resultImage1);
imshow("resultImage2", resultImage2);
waitKey(0);
return 0;
}
看到了吧,常用的中值滤波,也叫做模糊。