均值滤波
下引用 https://blog.csdn.net/baimafujinji/article/details/74750283 的一段话来说明导向滤波的作用:
无论是简单平滑,还是高斯平滑,它们都有一个共同的弱点,即它们都属于各向同性滤波。我们都知道,一幅自然的图像可以被看成是有(过渡平缓的,也就是梯度较小)区域和(过渡尖锐的,也就是梯度较大)边缘(也包括图像的纹理、细节等)共同组成的。噪声是影响图像质量的不利因素,我们希望将其滤除。噪声的特点通常是以其为中心的各个方向上梯度都较大而且相差不多。边缘则不同,边缘相比于区域也会出现梯度的越变,但是边缘只有在其法向方向上才会出现较大的梯度,而在切向方向上梯度较小。
因此,对于各向同性滤波(例如简单平滑或高斯平滑)而言,它们对待噪声和边缘信息都采取一直的态度。结果,噪声被磨平的同时,图像中具有重要地位的边缘、纹理和细节也同时被抹平了。这是我们所不希望看到的。研究人员已经提出了很多Edge-perserving的图像降噪(平滑)算法,例如双边滤波、自适应(维纳)平滑滤波(请参见文献【1】)、基于PM方程的各向异性滤波以及基于TV-norm的降噪算法等。本文将考虑在文献【2】中提出的另外一种Edge-perserving的图像滤波(平滑)算法——导向滤波(Guided Filter)。当然,通过阅读文献【2】,我们也知道导向滤波的应用不止有Edge-perserving的图像平滑,还包括图像去雾、图像Matting等等。
下给出处理流程图:
从图中也可以看出,导向滤波的输入为两个,一个是真实的输入p,另一个是引导输入I。输出为q,是p和I共同作用的产物。
实现代码:
#include
#include
#include
#include
using namespace std;
using namespace cv;
//导向滤波器
Mat guidedfilter(Mat &srcImage, Mat &srcClone, int r, double eps)
{
//转换源图像信息
srcImage.convertTo(srcImage, CV_64FC1);
srcClone.convertTo(srcClone, CV_64FC1);
int nRows = srcImage.rows;
int nCols = srcImage.cols;
Mat boxResult;
//步骤一:计算均值
boxFilter(Mat::ones(nRows, nCols, srcImage.type()),
boxResult, CV_64FC1, Size(r, r));
//生成导向均值mean_I
Mat mean_I;
boxFilter(srcImage, mean_I, CV_64FC1, Size(r, r));
//生成原始均值mean_p
Mat mean_p;
boxFilter(srcClone, mean_p, CV_64FC1, Size(r, r));
//生成互相关均值mean_Ip
Mat mean_Ip;
boxFilter(srcImage.mul(srcClone), mean_Ip,
CV_64FC1, Size(r, r));
Mat cov_Ip = mean_Ip - mean_I.mul(mean_p);
//生成自相关均值mean_II
Mat mean_II;
//应用盒滤波器计算相关的值
boxFilter(srcImage.mul(srcImage), mean_II,
CV_64FC1, Size(r, r));
//步骤二:计算相关系数
Mat var_I = mean_II - mean_I.mul(mean_I);
Mat var_Ip = mean_Ip - mean_I.mul(mean_p);
//步骤三:计算参数系数a,b
Mat a = cov_Ip / (var_I + eps);
Mat b = mean_p - a.mul(mean_I);
//步骤四:计算系数a\b的均值
Mat mean_a;
boxFilter(a, mean_a, CV_64FC1, Size(r, r));
mean_a = mean_a / boxResult;
Mat mean_b;
boxFilter(b, mean_b, CV_64FC1, Size(r, r));
mean_b = mean_b / boxResult;
//步骤五:生成输出矩阵
Mat resultMat = mean_a.mul(srcImage) + mean_b;
return resultMat;
}
void main()
{
Mat srcImage = imread("F:\\opencv_re_learn\\2.jpg");
if (!srcImage.data){
cout << "falied to read" << endl;
system("pause");
return;
}
imshow("srcImage", srcImage);
//通道分离
vector vSrcImage, vResultImage;
split(srcImage, vSrcImage);
Mat resultMat;
for (int i = 0; i < 3; i++){
//分通道转换成浮点型
Mat tempImage;
vSrcImage[i].convertTo(tempImage, CV_64FC1, 1.0 / 255.0);
Mat p = tempImage.clone();
//分别进行导向滤波
Mat resultImage = guidedfilter(tempImage, p, 10, 0.01);
vResultImage.push_back(resultImage);
}
//通道结果合并
merge(vResultImage, resultMat);
imshow("resultMat", resultMat);
waitKey(0);
}
实现效果: