高斯滤波及其实现
1.创建高斯滤波核
高斯滤波模板是通过二维高斯函数计算出来的:
G(x,y)=12πσ2e−x2+y22σ2
高斯模板需要知道模板大小及σ值,再通过上述高斯函数来确定模板系数。例现有3x3高斯模板如下,以模板中心为坐标原点,其高斯函数中的
x2+y2
就是指模板在坐标系中离原点的距离。
模板的分类:有小数模板和整数模板
小数模板计算方法:利用高斯分布函数求得后,对其中每个元素的值除以模板系数和.
整数模板计算方法:利用高斯分布函数求得后,先归一化(左上角的元素为1),取整,再乘以模板取整后的系数和。
Note:高斯模板的大小与σ的选择:高斯核的宽度应该为方差σ的3倍,原理是因为高斯正态分布中的3σ原则。
2.用滑动窗体进行卷积滤波
Note:注意3通道的卷积运算,是分别选取该通道的进行运算。
效果
代码:
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
using namespace std;
using namespace cv;
/*
*生成高斯滤波的模板
*function return 整型模板
@param: windowsize 模板的大小 奇数
@param: sigma 方差的大小
*/
vector<vector<int>> createGussInt(int windowsize,double sigma)
{
/*计算小数模板
*此时计算出来的小数模板不能直接用于高斯滤波,还需要进一步处理
*/
vector<vector<double> > GussinDouble(windowsize, vector<double>(windowsize));
int std = windowsize / 2;
for (int i = 0; i < windowsize; i++)
{
for (int j = 0; j < windowsize; j++)
{
int tem = (i - std)*(i - std) + (j - std)*(j - std);
//GussinDouble[i][j] = (1 / 2.0*pi*sigma)*exp(-tem / (2.0*sigma*sigma));
GussinDouble[i][j] =exp(-tem / (2.0*sigma*sigma));
cout << GussinDouble[i][j] << " ";
if (j == windowsize - 1)cout << "\n";
}
}
//变为整数模板:归一化,向下取整
double k = 1 / GussinDouble[0][0];
vector<vector<int>>GussinInt(windowsize, vector<int>(windowsize));
for (int i = 0; i < windowsize; i++)
{
for (int j = 0; j < windowsize; j++)
{
GussinDouble[i][j] = GussinDouble[i][j] * k;
GussinInt[i][j] = floor(GussinDouble[i][j]);
cout << GussinInt[i][j] << " ";
if (j == windowsize - 1)cout << "\n";
}
}
return GussinInt;
}
/*
*高斯滤波
**采用滑动模板窗口的方法滤波处理图片,图片最外层因为滤波窗口的大小会出现没有计算的情况,这里选用opencv自带的边界扩展函数
@param: img 支持单通道和3通道的输入图像
@param: kernel 整型滤波核
*/
void Guss(Mat src,Mat &dst,vector<vector<int>>kernel)
{
cout << "src.rows" << src.rows << endl;
cout << "src.cols" << src.cols << endl;
int std = kernel.size()/2;
Mat tem;
copyMakeBorder(src,tem,std,std,std,std, BORDER_REPLICATE);
cout << "tem col:" << tem.cols << endl;
cout << "tem.rows:" << tem.rows << endl;
cout << "tem channels:" << tem.channels() << endl;
uchar *p = tem.data;
int step = tem.step[0];
int channels = tem.channels();
for (int i = std; i < tem.rows-std; i++)
{
for (int j = std*channels; j < (tem.rows - std)*channels; j = j + channels)//保证一列的遍历
{
double sum[3] = { 0 };
for (int m = -std; m <= std; m++)
{
for (int n = -std; n <= std; n++)
{
if(channels==1)sum[0]+= p[(i + m)*step + j + n] * kernel[std + m][std + n];
if (channels == 3) {
sum[0] += p[(i + m)*step + j + n*channels] * kernel[std + m][std + n];
sum[1] += p[(i + m)*step + j+1 + n*channels] * kernel[std + m][std + n];
sum[2] += p[(i + m)*step + j+2 + n*channels] * kernel[std + m][std + n];
}
}
}
//饱和处理
/* for (int i = 0; i < 3; i++)
{
if (sum[i] > 255)sum[i] = 255;
else if (sum[i] < 0)sum[0] = 0;
}*/
//赋值
if (channels == 1)p[i*step + j] = sum[0];
if (channels == 3) {
p[i*step + j] = sum[0];
p[i*step + j + 1] = sum[1];
p[i*step + j + 2] = sum[2];
}
}
}
//range左包含右不包含
dst = tem(Range(std, tem.rows - std),Range(std, tem.cols - std));
}
/*主函数*/
int main()
{
Mat img = imread("test.jpg",1);
vector<vector<int>>kernel;
kernel=createGussDouble(3,0.8);
Mat dst;
imshow("img",img);
Guss(img, dst,kernel);
imshow("dst",dst);
waitKey(0);
}