现在的位置: 首页 > 综合 > 正文

图像模糊–高斯滤波

2017年03月08日 ⁄ 综合 ⁄ 共 3382字 ⁄ 字号 评论关闭

首先,了解什么是模糊,可以看一下这篇,图像模糊--快速均值滤波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()

抱歉!评论已关闭.