高斯滤波
高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。
实现图像的高斯滤波:
- 通过调整高斯函数的标准差(sigma)来控制平滑程度;
- 滤波窗口大小取为[6*sigma-1],[.]表示取整;
- 利用二维高斯函数的行列可分离性进行加速;
先对每行进行一维高斯滤波,再对结果的每列进行同样的一维高斯滤波;
实现过程:
使用高斯滤波器来进行图像的滤波操作,高斯滤波=以高斯函数为卷积核的图像卷积,高斯滤波器的函数及图像如下:
但是我们不能直接使用高斯滤波器进行滤波,而是要利用二维高斯函数的行列可分离性进行加速,通过调整高斯函数的标准差(sigma)来控制平滑程度,实现不同滤波程度的目的。
分别对行和列做卷积运算:
先对每一行进行一维高斯滤波,再对每一列进行一维高斯滤波。
不过需要注意的是,在进行高斯滤波之前,要进行边界扩展:
此外,我还添加了滑动条选项,来让用户自己选择平滑度(sigma值),最终结果如下:
高斯滤波和均值滤波应该是图像处理中使用的较为频繁的滤波器,而且两种滤波器虽然相似却又不太一样,高斯滤波器是一种线性滤波器,能够有效的抑制噪声,平滑图像。其作用原理和均值滤波器类似,都是取滤波器窗口内的像素的均值作为输出。其窗口模板的系数和均值滤波器不同,均值滤波器的模板系数都是相同的为1;而高斯滤波器的模板系数,则随着距离模板中心的增大而系数减小。所以,高斯滤波器相比于均值滤波器对图像的模糊程度较小。
代码自取:
// CVE4.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include<cxcore.h>
#include<cmath>
#include<cv.h>
#include<highgui.h>
using namespace std;
using namespace cv;
void listPixel_Operate(int, void*);
void Gaussian(const Mat &input, Mat &output, double sigma)
{
int row = input.rows, col = input.cols;
int window = (int)((6 * sigma - 1) / 2) * 2 + 1;//滤波窗口
double *temp = new double[window];
//扩充边界
Mat INPUT;
copyMakeBorder(input, INPUT, window / 2, window / 2, window / 2, window / 2, BORDER_REFLECT_101);
double sum = 0;
for (int w = 0; w < window; w++)
{
int mid = w - window / 2;
temp[w] = exp(-(mid*mid) / (2 * sigma*sigma));
sum += temp[w];
}
//归一化滤波核,和为1
for (int w = 0; w < window; w++)
{
temp[w] = temp[w] / sum;
}
//扩充边界之后的长宽
int rows = row + window - 1;
int cols = col + window - 1;
//先对每行进行一维高斯滤波
for (int y = window / 2; y < row + window / 2; y++)//行
{
for (int x = window / 2; x < col + window / 2; x++) //列
{
int num = 0;
double pix[3] = { 0 };
for (int k = x - window / 2; k < x + window / 2; k++)
{
for (int c = 0; c < INPUT.channels(); c++)
{
pix[c] += (INPUT.at<Vec3b>(y, k)[c])*temp[num]; //列坐标<矩阵列数
}
num++;
}
for (int c = 0; c < INPUT.channels(); c++)
{
INPUT.at<Vec3b>(y, x)[c] = pix[c];
}
}
}
//再对每列进行一维高斯滤波
for (int x = window / 2; x < col + window / 2; x++) //列
{
for (int y = window / 2; y < row + window / 2; y++) //行
{
int num = 0;
double pix[3] = { 0 };
for (int k = y - window / 2; k < y + window / 2; k++)
{
for (int c = 0; c < INPUT.channels(); c++)
{
pix[c] += (INPUT.at<Vec3b>(k, x)[c])*temp[num];
}
num++;
}
for (int c = 0; c < INPUT.channels(); c++)
{
INPUT.at<Vec3b>(y, x)[c] = pix[c];
}
}
}
for (int y = 0; y < row; y++)
{
for (int x = 0; x < col; x++)
{
output.at<Vec3b>(y, x) = INPUT.at<Vec3b>(y + window / 2, x + window / 2);
}
}
}
int sig;
Mat image;
int main()
{
//cout << "请输入sigma的值:" << endl;
//cin >> sig;
sig = 1;
image = imread("../res/img.jpg");
namedWindow("【效果图窗口】", 1);
//创建滑动条
createTrackbar("sigma", "【效果图窗口】", &sig, 10, listPixel_Operate);
//调用回调函数
listPixel_Operate(sig, 0);
//system("pause");
waitKey(0);
return 0;
}
void listPixel_Operate(int, void*)
{
Mat dst = Mat::zeros(image.rows, image.cols, image.type());
imshow("原图窗口", image);
Gaussian(image, dst, sig);
imshow("【效果图窗口】", dst);
}