2013-06-19 18 views
12

Używam python do utworzenia filtru gaussowskiego o rozmiarze 5x5. Widziałem ten post here, gdzie mówią o podobnej rzeczy, ale nie znalazłem dokładny sposób, aby uzyskać równoważny kod Pythona do funkcji Matlab fspecial('gaussian', f_wid, sigma) Czy jest jakiś inny sposób to zrobić? Próbowałem za pomocą następującego kodu:Jak uzyskać filtr Gaussa w pythonie

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) 

Otrzymany wyjście jest

[[ 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]] 

Co chcę jest coś takiego:

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 
+0

możliwe duplikat [Tworzenie Gaussa filtra wymaganej długości, pyton] (http://stackoverflow.com/questions/11209115/tworzenie-gaussowskich filtrów o wymaganej długości w pythonie) i http: // astrolitte rbox.blogspot.co.uk/2012/04/creating-discrete-gaussian-kernel-with.html – YXD

+0

Używam kodu wspomnianego na blogu. Ustawić 'n = 2, a = 1 ' sigma i użyć tego kodu: ' rozmiar = 2 sizey = nie wielkość = int (rozmiar) jeśli nie sizey: sizey = rozmiar innego: sizey = Int (sizey) x, y = scipy.mgrid [-size: size + 1, -sizey: sizey + 1] g = scipy.exp (- (x ** 2/float (rozmiar) + y ** 2/float (sizey))/2) print g/np.sqrt (2 * np.pi) ' Ale uzyskany tutaj wynik jest inny niż uzyskany przy użyciu fspecial w matlab – Khushboo

+0

Jak to jest inne? Czego oczekujesz i co otrzymujesz? – interjay

Odpowiedz

19

Ogólnie jeśli troszczą się o uzyskanie Dokładnie taki sam wynik jak MATLAB, najłatwiejszym sposobem osiągnięcia tego jest często patrząc bezpośrednio na źródło funkcji MATLAB.

W tym przypadku 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; 
... 

Całkiem proste, prawda? To < 10min pracować do portu to 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 

To daje mi taką samą odpowiedź jak fspecial do wewnątrz zaokrąglania błędu:

>> 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]]) 
+0

To dokładnie to, czego szukałem. Naprawdę było to proste. Dzięki :) – Khushboo

-1

znalazłem podobnego rozwiązania dla tego problemu:

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() 
0

Cześć Myślę, że problemem jest to, że za filtrem Gaussa współczynnik normalizacji zależy ile wymiary użyłeś. Filtr wygląda tak: formula
Tęskni się za kwadratem współczynnika normalizacji! I trzeba renormalizować całą macierz ze względu na dokładność obliczeń! kod dołączony poniżej:

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() 

Wyjście bez znormalizowane do sumy 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]] 

Wyjście podzielona przez NP.suma (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]] 
0

tutaj jest zapewnienie ND-Gaussa okno generator:

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 

ta funkcja daje nieznormalizowanych Gaussa okna z danego kształtu, centrum i wariancji. na przykład: gen_gaussian_kernel (shape = (3,3,3), średnia = (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]]] 
1

można spróbować to też (jako iloczyn 2 niezależnych zmiennych losowych Gaussa 1D), w celu uzyskania jądra 2D Gaussa:

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() 

enter image description here

Powiązane problemy