首先,了解什么是模糊,可以看一下这篇,图像模糊--快速均值滤波http://blog.csdn.net/zhonghuan1992/article/details/41131183
看完上面的那篇blog,应该就知道什么是模糊了,那么什么是高斯滤波,或者说是高斯模糊呢?
简单地替换一下就好了,均值滤波,就是取平均值,那么高斯滤波,取得是什么?
高斯滤波,会比均值滤波复杂一点,它不是简单地平均而已,而是加权平均,加权平均的意思,可以看下嘛。
注意,上面的图显示的是一个5*5的区域,不过,里面的数值,不再是图像的像素点了,而是这个区域的每一个点得权重,权重是什么意思呢?就是重要的程度,怎么体现呢?当我们用上面的卷积核(这里给这个区域的权重表取了一个响亮的名字,卷积核),卷积核上面的值和对应位置的点的像素相乘,再相加,便是更新的值。
O(u,v) = a(1,1)*I(1,1)+a(1,2)*I(1,2)+....+a(5,5)*I(5,5)
很好理解吧。
注意一下,上面的卷积核是归一化了,所以上面计算的时候我们才直接相加。
好了,现在我们该考虑,这个卷积核是怎么来的了。这个是这里的关键点。看下面图
上面的图片,可以看到,高斯函数就是一个二维的正态分布,什么,忘了正态分布神马了?看这里
也可以从上面的图中,看到,图像以中点开始,向四周散开,非常好的形态。而高斯卷积核就是通过这个高斯函数计算出来的。好了,这样的话,高斯滤波就解决了。
就这样简单嘛,是滴,你木有听错,就是这样简单,不用想复杂啦。那么,在代码中我们,如何实现它呢?看下面的实现吧,代码来自网络上c++版的(因为本人直接写得优化版的,懒呐): 来自(http://blog.csdn.net/zddblog/article/details/7450033)
void GaussianSmooth2D(const Mat &src, Mat &dst, double sigma)
{
if(src.channels() != 1)
return;
//确保sigma为正数
sigma = sigma > 0 ? sigma : 0;
//高斯核矩阵的大小为(6*sigma+1)*(6*sigma+1)
//ksize为奇数
int ksize = cvRound(sigma * 3) * 2 + 1;
// dst.create(src.size(), src.type());
if(ksize == 1)
{
src.copyTo(dst);
return;
}
dst.create(src.size(), src.type());
//计算高斯核矩阵
double *kernel = new double[ksize*ksize];
double scale = -0.5/(sigma*sigma);
const double PI = 3.141592653;
double cons = -scale/PI;
double sum = 0;
for(int i = 0; i < ksize; i++)
{
for(int j = 0; j < ksize; j++)
{
int x = i-(ksize-1)/2;
int y = j-(ksize-1)/2;
kernel[i*ksize + j] = cons * exp(scale * (x*x + y*y));
sum += kernel[i*ksize+j];
// cout << " " << kernel[i*ksize + j];
}
// cout <=0; i--)
{
*(kernel+i) /= sum;
}
//图像卷积运算,无边缘处理
for(int j = 0; j < src.cols-ksize; j++)
{
for(int i = 0; i < src.rows-ksize; i++)
{
double acc = 0;
for(int m = 0; m < ksize; m++)
{
for(int n = 0; n < ksize; n++)
{
acc += *(srcData + src.step * (i+n) + src.channels() * (j+m)) * kernel[m*ksize+n];
}
}
*(dstData + dst.step * (i + (ksize - 1)/2) + (j + (ksize -1)/2)) = (int)acc;
}
}
delete []kernel;
}
下面,我们考虑一下,高斯函数,其实这个函数有一些不错的性质值得探讨,这里,说一个,它的行列可分离性,这个有什么用呢?简单的说,他可以化简我们计算时候的复杂度。看下面的图:
有什么用呐,当然是优化了复杂度啊,原先,我们都是计算一个区域的x和y,这样很耗时间,现在,先计算x,再计算y,就能够简化了,具体看代码吧,仔细看,就能理解了,因为不太好表述,语言是python
# -*- coding: utf-8 -*-
__author__ = 'zhonghuan'
import numpy as np
import cv2
import math
class MyGaussianBlur():
#初始化
def __init__(self, sigma):
self.length=int(math.floor(6*sigma-1)/2*2+1)
self.sigma=sigma
#高斯的计算公式,根据高斯函数计算的。
def calcTemplate(self):
a=np.zeros(self.length);
k=(self.length)/2;
sum = 0.0;
cons = 1/(math.sqrt(2*math.pi)*self.sigma);
cons2 = -1/(2*self.sigma*self.sigma);
for i in range(0,self.length):
x = i-k; #和中间节点的距离,就是x
a[i]= cons * math.exp((x*x)*cons2);
sum=sum+a[i];
a/=sum;
return a;
#滤波函数
def filter(self, src, template):
dstSize = [np.size(src,0),np.size(src,1)];
if src.ndim==3:
dstSize.append(3)
len = self.length;
center = len/2;
print len;
dst=np.array(np.zeros(dstSize),src.dtype)
temp=np.array(np.zeros(dstSize),src.dtype)
# print np.size(src,0),np.size(src,1);
#这里就是利用行列可分离性,先计算x
for x in range(0,np.size(src,0)):
for y in range(0,np.size(src,1)):
ary = 0;
sum = 0;
for i in range(-center,center):
if(y+i>=0 and y+i < np.size(src,1)):
ary =ary + template[i+center]*src[x,y+i];
sum =sum + template[i+center];
temp[x,y]=ary/sum;
return temp;
#再计算y
for y in range(0,np.size(src,1)):
for x in range(0,np.size(src,0)):
ary = 0;
sum = 0;
for i in range(-center,center):
if(x+i>=0 and x+i < np.size(src,0)):
ary =ary + template[i+center]*temp[x+i];
sum =sum + template[i+center];
dst[x,y]=ary/sum;
return dst;
s=10 #sigma数值,自己自由调整
GBlur=MyGaussianBlur(sigma=s)#声明高斯模糊类
img=cv2.imread('author.jpg')#打开图片
# img = cv2.imread('m.png')
template = GBlur.calcTemplate()
print template
GBimg = GBlur.filter(img,template);
cv2.imshow("src",img);
cv2.imshow("dst",GBimg);
cv2.waitKey(20000);
cv2.destroyAllWindows()