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