开发环境
opencv版本:opencv4.5.1
VS版本:VS2017
Qt版本:Qt5.12.3
C++实现高斯滤波器
一、目的:去除噪声,使图像平滑。
二、原理
1.一维高斯分布:
2.二维高斯分布:
3、高斯滤波一般使用的二维零均值的高斯分布函数,通过高斯分布函数求出模板系数,例如一个3*3的模板:以模板的中心位置为坐标原点进行取样,其中模板各个坐标位置如下图,x轴水平向右,y轴垂直向下,(x,y)表示
4、将各个位置的坐标代入二维零均值高斯分布函数,计算出来的模板有两种形式:
整数模板和小数模板,可以使用二维数组来存放计算出的模板系数
①小数模板:
②整数模板:
伪代码:
输入:目标核,核的大小,sigma值
1.以x,y方向联合实现获取高斯模板
①、取样获得模板
②、将坐标代入高斯公式
③、将对应的值写入高斯核中
④、归一化
输入:原图像,目标图像,核
1.判断原图像是否为空,空则直接返回
2.判断核的是否为奇数
3.原图像边界填充,目标图像清空
4.用高斯核高斯滤波
图像:
原图:
结果图像:
部分核心代码:
/ x,y方向联合实现获取高斯模板
void imageJ::GenerateGaussMask(cv::Mat& Mask, cv::Size wsize, double sigma) {
Mask.create(wsize, CV_64F);
int h = wsize.height;
int w = wsize.width;
int center_h = (h - 1) / 2;
int center_w = (w - 1) / 2;
double sum = 0.0;
double x, y;
for (int i = 0; i < h; ++i) {
y = pow(i - center_h, 2);
for (int j = 0; j < w; ++j) {
x = pow(j - center_w, 2);
//因为最后都要归一化的,常数部分可以不计算,也减少了运算量
double g = exp(-(x + y) / (2 * sigma*sigma));
Mask.ptr<double>(i)[j] = g;
sum += g;
}
}
Mask = Mask / sum;
}
// 按二维高斯函数实现高斯滤波
void imageJ::GaussianFilter(cv::Mat& src, cv::Mat& dst, cv::Mat window) {
int hh = (window.rows - 1) / 2;
int hw = (window.cols - 1) / 2;
dst = cv::Mat::zeros(src.size(), src.type());
//边界填充
cv::Mat Newsrc;
cv::copyMakeBorder(src, Newsrc, hh, hh, hw, hw, cv::BORDER_REPLICATE);//边界复制
dst.zeros(src.size(), src.type());
//高斯滤波
for (int i = hh; i < src.rows + hh; ++i) {
for (int j = hw; j < src.cols + hw; ++j) {
double sum[3] = { 0 };
for (int r = -hh; r <= hh; ++r) {
for (int c = -hw; c <= hw; ++c) {
if (src.channels() == 1) {
sum[0] = sum[0] + Newsrc.ptr<uchar>(i + r)[j + c] * window.ptr<double>(r + hh)[c + hw];
}
else if (src.channels() == 3) {
cv::Vec3b rgb = Newsrc.ptr<cv::Vec3b>(i + r)[j + c];
sum[0] = sum[0] + rgb[0] * window.ptr<double>(r + hh)[c + hw];//B
sum[1] = sum[1] + rgb[1] * window.ptr<double>(r + hh)[c + hw];//G
sum[2] = sum[2] + rgb[2] * window.ptr<double>(r + hh)[c + hw];//R
}
}
}
for (int k = 0; k < src.channels(); ++k) {
if (sum[k] < 0)
sum[k] = 0;
else if (sum[k] > 255)
sum[k] = 255;
}
if (src.channels() == 1)
{
dst.ptr<uchar>(i - hh)[j - hw] = static_cast<uchar>(sum[0]);
}
else if (src.channels() == 3)
{
cv::Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
dst.ptr<cv::Vec3b>(i - hh)[j - hw] = rgb;
}
}
}
}