note
原理:从空间维度和灰度维度生成两个高斯滤波器,再合成一个高斯滤波器
空间域高斯滤波器:GaussSpace(x,y) = exp(-1 * (x*x + y*y) / 2 / sigma / sigma) / 2 / PI / sigma / sigma;
灰度域(颜色域)高斯滤波器:GaussColor(x,y) = exp(-1 * (f(x,y) - g(x,y)^2) / 2 / PI / sigma / sigma) / sigma / sqrt(2*PI);
空间域高斯滤波器和颜色域高斯滤波器的合成,相乘,注意归一化
code
static void GetSapceGaussKernel2D(Mat& gaussFilter, double sigma) {
	if (gaussFilter.rows != gaussFilter.cols || gaussFilter.channels() != 1) {
		return;
	}
	if (gaussFilter.rows / 2 == 0) {
		return;
	}
	if (gaussFilter.type() != CV_64FC1) {
		gaussFilter.convertTo(gaussFilter, CV_64FC1);
	}
	
	int mid = gaussFilter.rows / 2;
	for (int x = 0; x < gaussFilter.cols; ++x) {
		for (int y = 0; y < gaussFilter.rows; ++y) {
			double l2 = (double)(mid-x)*(mid-x) + (double)(mid-y)*(mid-y);
			double val = exp((-0.5) * (l2) / sigma / sigma) / 2 / PI / sigma / sigma;
			gaussFilter.at<double>(y,x) = val;
		}
	}
}
static void GetColorGaussKernel(double color, Mat& mat, Mat& gaussFilter, double sigma = 1) {
	if (mat.type() != CV_64FC1) {
		return;
	}
	if (mat.channels() > 1) {
		return;
	}
	if (gaussFilter.rows != gaussFilter.cols || gaussFilter.channels() != 1) {
		return;
	}
	if (gaussFilter.rows / 2 == 0) {
		return;
	}
	if (gaussFilter.type() != CV_64FC1) {
		gaussFilter.convertTo(gaussFilter, CV_64FC1);
	}
	for (int r = 0; r < gaussFilter.rows; ++r) {
		for (int c = 0; c < gaussFilter.cols; ++c) {
			double val = (mat.at<double>(r,c));
			double deta = (color - val) * (color - val);
			gaussFilter.at<double>(r,c) = exp(-0.5 * deta / PI / sigma / sigma) / sigma / sqrt(2 * PI);
		}
	}
}
/*
 \brief 高斯双边滤波;
 \brief 原理:从空间维度和灰度维度生成两个高斯滤波器,再合成一个高斯滤波器;
 \brief 空间域高斯滤波器:GaussSpace(x,y) = exp(-1 * (x*x + y*y) / 2 / sigma / sigma) / 2 / PI / sigma / sigma;
 \brief 灰度域(颜色域)高斯滤波器:GaussColor(x,y) = exp(-1 * (f(x,y) - g(x,y)^2) / 2 / PI / sigma / sigma) / sigma / sqrt(2*PI);
 \brief 空间域高斯滤波器和颜色域高斯滤波器的合成,相乘,注意归一化
 \param src:原图像矩阵
 \param res:输出图像矩阵
 \param sigmaSpace:空间域sigma
 \param sigmaColor:颜色域sigma
*/
void MyGaussBilateralFilter(Mat& src, Mat& res, Size& size, double sigmaSpace = 1, double sigmaColor = 1) {
	if ((src.channels() > 1) || (res.channels() > 1)) {
		return;
	}
	if (size.width != size.height) {
		return;
	}
	if ((size.width / 2 == 0) || (size.height / 2 == 0)) {
		return;
	}
	int srcType = src.type();
	if (srcType != CV_64FC1) {
		src.convertTo(src, CV_64FC1);
	}
	Mat kernel(size, CV_64FC1);	// 总滤波器,高斯双边滤波器
	Mat spaceGauss(size, CV_64FC1);	// 空间域高斯滤波器
	int anchor = size.height / 2;	// 锚点位置
	double sumVal = 0.0;	// 归一化时求和使用
	Mat colorGauss(size, CV_64FC1);	// 颜色域高斯滤波器
	Mat mat;	// 原图根据roi矩形截取的矩阵
	Rect rec;	// roi矩形框
	Mat tmp(size, CV_64FC1);
	rec.width = size.width;
	rec.height = size.height;
	GetSapceGaussKernel2D(spaceGauss, sigmaSpace);
	sumVal = (sum(spaceGauss))[0];
	spaceGauss = spaceGauss / sumVal;	// 空间域高斯滤波器归一化
	for (int r = 0; r+size.height <= src.rows; r++) {
		for (int c = 0; c+size.width <= src.cols; c++) {
			rec.x = c;
			rec.y = r;
			
			src(rec).copyTo(mat);	// 从原图截取矩阵
			src(rec).copyTo(res(rec));
			double color = mat.at<double>(anchor,anchor);	// 锚点位置灰度值\颜色值
			GetColorGaussKernel(color, mat, colorGauss, sigmaColor);
			sumVal = (sum(colorGauss))[0];
			colorGauss = colorGauss / sumVal;	// 颜色域高斯滤波器归一化
			
			multiply(spaceGauss, colorGauss, kernel);	// 由空间域高斯滤波器和颜色域高斯滤波器获取总滤波器
			
			sumVal = (sum(kernel))[0];
			kernel = kernel / sumVal;	// 总滤波器归一化
			
			multiply(mat, kernel, tmp);
			double tmpSum = (sum(tmp))[0];
			(res(rec)).at<double>(anchor,anchor) = tmpSum;	// 锚点位置像素修改
		}
	}
	src.convertTo(src, srcType);
	res.convertTo(res, srcType);
} 
test




















