高斯滤波
高斯滤波
一、目的与原理
(1)目的:用于消除高斯噪声;
(2)原理:高斯噪声的特点是噪声分布服从正态分布,要消除这样分布的噪声那么处理的方法也需要有正态分布的思想,即对于图像而言,着重于处理图像中心,其次再稍微处理边缘,因为正态分布的特点是中间部分多,外侧比较少。所以卷积核的设计思路是中间点的权值最大,越靠近中间点的权值越大。
公式①:
是一个常数,由于我们最终需要对高斯模板归一化,而常数不影响数值比例,所以可以忽略掉。我们实际要计算的部分是:
高斯滤波的步骤:
假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:
y轴水平向上,x轴水平向右。
根据二维高斯函数:,设定 的值,假设其=1.5可得权重矩阵:
归一化:
假设有九个点,灰度值如下图:
每个点乘以权重后的结果:
可得:
这九个点的累加就是中心点的高斯模糊值。
二、算法步骤
(1)建立坐标系关系
(2)根据高斯函数计算出坐标矩阵的值
(3)对矩阵的值归一化
(4)卷积求和获得输出图像的灰度值
(5)将结果赋值到输出图像
(6)显示图像
三、伪代码
输入:卷积核大小wsize,高斯函数的sigma
输出:高斯模板Mask
void generateGaussMask(cv::Mat& Mask, cv::Size wsize, double sigma)
{
for(循环处理点,生成各个坐标点){
根据高斯函数算出坐标点对应的值
对上一步的值归一化
生成高斯模板Mask
}
}
输入:原图src,高斯模板Mask
输出:结果图dst
void GaussianFilter(cv::Mat& src, cv::Mat& dst, cv::Mat Mask)
{
for(循环处理原图src像素点){
if(图片为单通道){
根据高斯模板Mask卷积求核获得输出图像的灰度值
将灰度值赋值到输出图像中
}
if(图片为多通道){
根据通道数,用高斯模板Mask卷积求核获得输出图像的各个通道的值
将各个通道值赋值到输出图像中
}
}
}
四、源码:
// 按二维高斯函数实现高斯滤波
void GaussianFilter(cv::Mat& src, cv::Mat& dst, cv::Mat kernel) {
int hh = (kernel.rows - 1) / 2;
int hw = (kernel.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);//边界复制
//高斯滤波
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.at<uchar>(i + r, j + c) * kernel.at<double>(r + hh, c + hw);
}
else if (src.channels() == 3) {
cv::Vec3b rgb = Newsrc.at<cv::Vec3b>(i + r, j + c);
sum[0] = sum[0] + rgb[0] * kernel.at<double>(r + hh, c + hw);//B
sum[1] = sum[1] + rgb[1] * kernel.at<double>(r + hh, c + hw);//G
sum[2] = sum[2] + rgb[2] * kernel.at<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.at<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.at<cv::Vec3b>(i - hh, j - hw) = rgb;
}
}
}
}
// x,y方向联合实现获取高斯模板
void 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.at<double>(i, j) = g;
sum += g;
}
}
Mask = Mask / sum;
}
六、结果图
高斯模板:
原图、Opencv高斯函数处理结果、自定义高斯函数处理结果、原图+噪声、做差求算法区别: