本文主要借鉴参考了这篇已总结得很好的博文:zddhub 高斯模糊实现小结 ,感谢博主zddhub的精彩总结,记录此文仅供自己学习总结。
以下是VS2013 下C++实现简要代码,借助OpenCV为了更方便读取、显示图像。只是个一维高斯的简单Demo,用以测试效果。
#include <highgui.h>
#include <cv.h>
using namespace cv;
void main()
{
Mat src = imread("demo.bmp",2);
int dd = src.channels();
Mat dst,middle;// middle存放中间数据
dst.create(src.size(), src.type());
middle.create(src.size(), src.type());
int width = src.cols;
int height = src.rows;
//
// 一维高斯模糊
double sigma = 6;
const double PI = 3.141592653;
int ksize = ceil(sigma * 3) * 2 + 1; // 使边长为奇数
int kcenter = ksize / 2;
if (ksize == 1)
{
src.copyTo(dst);
return;
}
double *kernel = new double[ksize];
double temp = -1 / (2 * sigma*sigma); // 高斯公式中间步骤
double cons = 1 / (sqrt(2 * PI)*sigma);
double sum = 0;
for (int i = 0; i < ksize;i++)
{
kernel[i] = cons*exp(temp*(i - kcenter)*(i - kcenter)); // 半径即当前元素到模板中心的距离
sum += kernel[i];
}
// 归一化
for (int i = 0; i < ksize;i++)
{
kernel[i] /= sum;
}
// x方向卷积
for (int j = 0; j < height;j++)
{
for (int i = 0; i < width;i++)
{
double result = 0;
sum = 0;
for (int index = -kcenter; index <= kcenter;index ++)
{
if ((index + i) >= 0 && (index + i) < width)
{
result += src.data[j*width + index + i] * kernel[index + kcenter]; // kernel[index+kcenter] 可理解为以kcenter为中心向左右的偏移量(index)
sum += kernel[index + kcenter];
}
}
middle.data[j*width + i] = result / sum;
}
}
// y方向卷积
for (int j = 0; j < height;j++)
{
for (int i = 0; i < width;i++)
{
double result = 0;
sum = 0;
for (int index = -kcenter; index <= kcenter; index++)
{
if ((j+index)>=0 && (j+index)<height)
{
result += middle.data[(j + index)*width + i] * kernel[index + kcenter];
sum += kernel[index + kcenter];
}
}
dst.data[j*width + i] = result / sum;
}
}
delete[] kernel;
kernel = NULL;
//
imshow("原始图片", src);
imshow("高斯模糊结果图", dst);
Mat cvGauss;
GaussianBlur(src, cvGauss, Size(0, 0), 6); // OpenCV自带高斯函数,可做效果对比
imshow("OpenCV高斯结果", cvGauss);
waitKey();
}
运行结果如下: