Как получить гауссовский фильтр в python
Я использую python для создания гауссовского фильтра размером 5x5.
Я видел этот пост здесь, где они говорят о подобной вещи, но я не нашел точного способа получить эквивалентный код python для функции matlab fspecial('gaussian', f_wid, sigma)
Есть ли другой способ сделать это?
Я попытался использовать следующий код:
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
Ответы
Ответ 1
В общих чертах, если вы действительно заботитесь о том, чтобы получить тот же результат, что и 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;
...
Довольно просто, а? Он < 10mins работает, чтобы перенести это на 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]])
Ответ 2
Эта функция реализует функциональные возможности, подобные fspecial в matlab
http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.get_window.html
от скудного импортного сигнала
>>>signal.get_window(('gaussian',2),3)
>>>array([ 0.8824969, 1. , 0.8824969])
Эта функция генерирует только 1D ядер
Я предполагаю, что вы могли бы реализовать код для генерации гауссовской маски, как и другие, указали.
Ответ 3
Вы также можете попробовать это (как произведение 2 независимых 1D гауссовских случайных величин) для получения двумерного гауссовского ядра:
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()
![введите описание изображения здесь]()
Ответ 4
Привет. Я думаю, проблема в том, что для гауссовского фильтра коэффициент нормировки зависит от того, сколько измерений вы использовали.
Таким образом, фильтр выглядит следующим образом: ![formula]()
То, что вы пропустили, является квадратом коэффициента нормировки! И нужно перенормировать всю матрицу из-за вычислительной точности!
Код прилагается здесь:
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]]
Ответ 5
здесь должен быть создан nd-гауссовый генератор окна:
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)] = exp(-s/(2*var))
return k
эта функция даст вам ненормализованные гауссовые окна с заданной формой, центром и дисперсией.
например: gen_gaussian_kernel (shape = (3,3,3), mean = (1,1,1), var = 1.0) output →
[[[ 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]]]
Ответ 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()