如何在python中获得高斯滤波器
Posted
技术标签:
【中文标题】如何在python中获得高斯滤波器【英文标题】:How to obtain a gaussian filter in python 【发布时间】:2013-06-15 22:51:58 【问题描述】:我正在使用 python 创建一个大小为 5x5 的高斯滤波器。
我看到了这篇文章here,他们在其中谈论了类似的事情,但我没有找到获得与 matlab 函数 fspecial('gaussian', f_wid, sigma)
等效的 python 代码的确切方法
还有其他方法吗?
我尝试使用以下代码:
size = 2
sizey = None
size = int(size)
if not sizey:
sizey = size
else:
sizey = int(sizey)
x, y = scipy.mgrid[-size: size + 1, -sizey: sizey + 1]
g = scipy.exp(- (x ** 2/float(size) + y ** 2 / float(sizey)))
print g / np.sqrt(2 * np.pi)
得到的输出是
[[ 0.00730688 0.03274718 0.05399097 0.03274718 0.00730688]
[ 0.03274718 0.14676266 0.24197072 0.14676266 0.03274718]
[ 0.05399097 0.24197072 0.39894228 0.24197072 0.05399097]
[ 0.03274718 0.14676266 0.24197072 0.14676266 0.03274718]
[ 0.00730688 0.03274718 0.05399097 0.03274718 0.00730688]]
我想要的是这样的:
0.0029690 0.0133062 0.0219382 0.0133062 0.0029690
0.0133062 0.0596343 0.0983203 0.0596343 0.0133062
0.0219382 0.0983203 0.1621028 0.0983203 0.0219382
0.0133062 0.0596343 0.0983203 0.0596343 0.0133062
0.0029690 0.0133062 0.0219382 0.0133062 0.0029690
【问题讨论】:
Creating Gaussian filter of required length in python 和 astrolitterbox.blogspot.co.uk/2012/04/… 的可能重复 我正在使用博客中提到的代码。我设置了N = 2 and sigma = 1
并使用以下代码:size = 2 sizey = None size = int(size) if not sizey: sizey = size else: sizey = int(sizey) x, y = scipy.mgrid[-size: size + 1, -sizey: sizey + 1] g = scipy.exp( - (x ** 2/float(size) + y ** 2 / float(sizey)) / 2) print g / np.sqrt(2 * np.pi)
但是这里得到的结果与在matlab中使用 fspecial 得到的结果不同
有什么不同?你期望什么,你会得到什么?
我已将其包含在问题中。请再次检查。
【参考方案1】:
使用高斯 PDF 并假设空间不变模糊
def gaussian_kernel(sigma, size):
mu = np.floor([size / 2, size / 2])
size = int(size)
kernel = np.zeros((size, size))
for i in range(size):
for j in range(size):
kernel[i, j] = np.exp(-(0.5/(sigma*sigma)) * (np.square(i-mu[0]) +
np.square(j-mu[0]))) / np.sqrt(2*math.pi*sigma*sigma)```
kernel = kernel/np.sum(kernel)
return kernel
【讨论】:
【参考方案2】:这里是提供一个nd-gaussian窗口生成器:
def gen_gaussian_kernel(shape, mean, var):
coors = [range(shape[d]) for d in range(len(shape))]
k = np.zeros(shape=shape)
cartesian_product = [[]]
for coor in coors:
cartesian_product = [x + [y] for x in cartesian_product for y in coor]
for c in cartesian_product:
s = 0
for cc, m in zip(c,mean):
s += (cc - m)**2
k[tuple(c)] = np.exp(-s/(2*var))
return k
此函数将为您提供具有给定形状、中心和方差的非归一化高斯窗口。 例如: gen_gaussian_kernel(shape=(3,3,3),mean=(1,1,1),var=1.0) 输出->
[[[ 0.22313016 0.36787944 0.22313016]
[ 0.36787944 0.60653066 0.36787944]
[ 0.22313016 0.36787944 0.22313016]]
[[ 0.36787944 0.60653066 0.36787944]
[ 0.60653066 1. 0.60653066]
[ 0.36787944 0.60653066 0.36787944]]
[[ 0.22313016 0.36787944 0.22313016]
[ 0.36787944 0.60653066 0.36787944]
[ 0.22313016 0.36787944 0.22313016]]]
【讨论】:
如果形状只是 2D,这似乎不起作用......也就是在我想生成单个高斯内核的情况下。 @Will.Evo 它也适用于 2d 吗?我不明白为什么它不适用于 2d 案例。尝试运行 gen_gaussian_kernel((5, 5), (1.0, 1.0), 1.0)【参考方案3】:嘿,我想这可能对你有帮助
import numpy as np
import cv2
def gaussian_kernel(dimension_x, dimension_y, sigma_x, sigma_y):
x = cv2.getGaussianKernel(dimension_x, sigma_x)
y = cv2.getGaussianKernel(dimension_y, sigma_y)
kernel = x.dot(y.T)
return kernel
g_kernel = gaussian_kernel(5, 5, 1, 1)
print(g_kernel)
[[0.00296902 0.01330621 0.02193823 0.01330621 0.00296902]
[0.01330621 0.0596343 0.09832033 0.0596343 0.01330621]
[0.02193823 0.09832033 0.16210282 0.09832033 0.02193823]
[0.01330621 0.0596343 0.09832033 0.0596343 0.01330621]
[0.00296902 0.01330621 0.02193823 0.01330621 0.00296902]]
【讨论】:
【参考方案4】:您也可以尝试这个(作为 2 个独立的 1D 高斯随机变量的乘积)来获得 2D 高斯核:
from numpy import pi, exp, sqrt
s, k = 1, 2 # generate a (2k+1)x(2k+1) gaussian kernel with mean=0 and sigma = s
probs = [exp(-z*z/(2*s*s))/sqrt(2*pi*s*s) for z in range(-k,k+1)]
kernel = np.outer(probs, probs)
print kernel
#[[ 0.00291502 0.00792386 0.02153928 0.00792386 0.00291502]
#[ 0.00792386 0.02153928 0.05854983 0.02153928 0.00792386]
#[ 0.02153928 0.05854983 0.15915494 0.05854983 0.02153928]
#[ 0.00792386 0.02153928 0.05854983 0.02153928 0.00792386]
#[ 0.00291502 0.00792386 0.02153928 0.00792386 0.00291502]]
import matplotlib.pylab as plt
plt.imshow(kernel)
plt.colorbar()
plt.show()
【讨论】:
【参考方案5】:您好,我认为问题在于,对于高斯滤波器,归一化因子取决于您使用了多少维。 所以过滤器看起来像这样 你错过的是归一化因子的平方!并且由于计算精度需要重新归一化整个矩阵! 代码附在这里:
def gaussian_filter(shape =(5,5), sigma=1):
x, y = [edge /2 for edge in shape]
grid = np.array([[((i**2+j**2)/(2.0*sigma**2)) for i in xrange(-x, x+1)] for j in xrange(-y, y+1)])
g_filter = np.exp(-grid)/(2*np.pi*sigma**2)
g_filter /= np.sum(g_filter)
return g_filter
print gaussian_filter()
未归一化为 1 的输出:
[[ 0.00291502 0.01306423 0.02153928 0.01306423 0.00291502]
[ 0.01306423 0.05854983 0.09653235 0.05854983 0.01306423]
[ 0.02153928 0.09653235 0.15915494 0.09653235 0.02153928]
[ 0.01306423 0.05854983 0.09653235 0.05854983 0.01306423]
[ 0.00291502 0.01306423 0.02153928 0.01306423 0.00291502]]
输出除以 np.sum(g_filter):
[[ 0.00296902 0.01330621 0.02193823 0.01330621 0.00296902]
[ 0.01330621 0.0596343 0.09832033 0.0596343 0.01330621]
[ 0.02193823 0.09832033 0.16210282 0.09832033 0.02193823]
[ 0.01330621 0.0596343 0.09832033 0.0596343 0.01330621]
[ 0.00296902 0.01330621 0.02193823 0.01330621 0.00296902]]
【讨论】:
【参考方案6】:我为这个问题找到了类似的解决方案:
def fspecial_gauss(size, sigma):
"""Function to mimic the 'fspecial' gaussian MATLAB function
"""
x, y = numpy.mgrid[-size//2 + 1:size//2 + 1, -size//2 + 1:size//2 + 1]
g = numpy.exp(-((x**2 + y**2)/(2.0*sigma**2)))
return g/g.sum()
【讨论】:
这是被否决的原因吗?它似乎是正确的(而且更简洁) 我使用这个函数,它有最接近 Matlab 输出的值。谢谢。【参考方案7】:该函数实现的功能类似于matlab中的fspecial功能
http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.get_window.html 从 scipy 导入信号
>>>signal.get_window(('gaussian',2),3)
>>>array([ 0.8824969, 1. , 0.8824969])
这个函数似乎只生成一维内核
我猜你可以自己实现代码来生成高斯掩码,就像其他人指出的那样。
【讨论】:
【参考方案8】:一般而言,如果您真的很想获得与 MATLAB 完全相同的结果,实现这一目标的最简单方法通常是直接查看 MATLAB 函数的源代码。
在这种情况下,edit fspecial
:
...
case 'gaussian' % Gaussian filter
siz = (p2-1)/2;
std = p3;
[x,y] = meshgrid(-siz(2):siz(2),-siz(1):siz(1));
arg = -(x.*x + y.*y)/(2*std*std);
h = exp(arg);
h(h<eps*max(h(:))) = 0;
sumh = sum(h(:));
if sumh ~= 0,
h = h/sumh;
end;
...
很简单,嗯?将其移植到 Python 只需
import numpy as np
def matlab_style_gauss2D(shape=(3,3),sigma=0.5):
"""
2D gaussian mask - should give the same result as MATLAB's
fspecial('gaussian',[shape],[sigma])
"""
m,n = [(ss-1.)/2. for ss in shape]
y,x = np.ogrid[-m:m+1,-n:n+1]
h = np.exp( -(x*x + y*y) / (2.*sigma*sigma) )
h[ h < np.finfo(h.dtype).eps*h.max() ] = 0
sumh = h.sum()
if sumh != 0:
h /= sumh
return h
这给了我与 fspecial
相同的答案,在舍入误差内:
>> fspecial('gaussian',5,1)
0.002969 0.013306 0.021938 0.013306 0.002969
0.013306 0.059634 0.09832 0.059634 0.013306
0.021938 0.09832 0.1621 0.09832 0.021938
0.013306 0.059634 0.09832 0.059634 0.013306
0.002969 0.013306 0.021938 0.013306 0.002969
: matlab_style_gauss2D((5,5),1)
array([[ 0.002969, 0.013306, 0.021938, 0.013306, 0.002969],
[ 0.013306, 0.059634, 0.09832 , 0.059634, 0.013306],
[ 0.021938, 0.09832 , 0.162103, 0.09832 , 0.021938],
[ 0.013306, 0.059634, 0.09832 , 0.059634, 0.013306],
[ 0.002969, 0.013306, 0.021938, 0.013306, 0.002969]])
【讨论】:
这正是我想要的。你真的让它变得简单了。谢谢:) @ali_m 我不太明白这一行h[ h < np.finfo(h.dtype).eps*h.max() ] = 0
我看了看文档,它似乎可以防止机器限制错误(?)。 d.type 参数是否必要?还有你为什么用.eps
和h.max
相乘。很抱歉提出这么旧的帖子。
也可以使用 cv2 和以下 2 个衬里:u = c.getGaussianKernel(5, 1); kernel = np.outer(u, u)
。我得到了和上面一样的结果。以上是关于如何在python中获得高斯滤波器的主要内容,如果未能解决你的问题,请参考以下文章