您的位置:首页 > 运维架构

图像模糊--高斯滤波

2014-11-15 00:59 447 查看
首先,了解什么是模糊,可以看一下这篇,图像模糊--快速均值滤波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 <<endl;
}
//归一化
for(int i = ksize*ksize-1; i >=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()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息