图像导向滤波:
导向滤波不仅仅能实现双边滤波的边缘平滑,而且在检测到边缘附近有很好的表现,可以应用在图像增强,HDR压缩,图像抠图及图像去雾等场景中。
直接看实现吧:
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
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;
}
Mat guidedfilter(Mat &srcImage, Mat &srcClone, int r, double eps)
{
srcImage.convertTo(srcImage, CV_64FC1);
srcImage.convertTo(srcClone, CV_64FC1);
int nRows = srcImage.rows;
int nCols = srcImage.cols;
Mat boxResult;
//计算均值
boxFilter(Mat::ones(nRows, nCols, srcImage.type()), boxResult, -1, 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));
//步骤五:生成输出矩阵
Mat resultMat = mean_a.mul(srcImage) + mean_b;
return resultMat;
}
int main()
{
Mat srcImage = imread("D:\\1.jpg");
if (srcImage.empty())
return -1;
Mat dstImage = addGaussianNoise(srcImage);
vector<Mat> vDstImage, vResultImage;
split(dstImage, vDstImage);
Mat resultMat;
for (int i = 0; i < 3; i++)
{
Mat tempImage;
vDstImage[i].convertTo(tempImage, CV_64FC1, 1.0 / 255.0);
Mat p = tempImage.clone();
//分别进行导向滤波
Mat resultImage = guidedfilter(tempImage, p, 4, 0.01);
vResultImage.push_back(resultImage);
}
merge(vResultImage, resultMat);
imshow("srcImage", srcImage);
imshow("dstImage", dstImage);
imshow("resultMat", resultMat);
waitKey(0);
return 0;
}
源图像:
高斯噪声图像:
导向滤波: