2013-06-19 14 views
12

Sto usando python per creare un filtro gaussiano di dimensione 5x5. Ho visto questo post here dove si parla di una cosa simile ma non ho trovato il modo esatto per ottenere il codice Python equivalente alla funzione MATLAB fspecial('gaussian', f_wid, sigma) C'è qualche altro modo per farlo? Ho provato ad utilizzare il seguente codice:Come ottenere un filtro gaussiano in 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) 

L'output ottenuto è

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

Quello che voglio è qualcosa di simile:

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

possibile duplicato [Creare filtro gaussiano di lunghezza desiderata in pitone] (http://stackoverflow.com/questions/11209115/creating-gaussian-filter-of-required-length-in-python) e http: // astrolitte rbox.blogspot.co.uk/2012/04/creating-discrete-gaussian-kernel-with.html – YXD

+0

Sto usando il codice menzionato nel blog. Ho impostato 'N = 2 e sigma = 1' e utilizzare il seguente codice: ' size = 2 SizeY = Nessuno size = int (size) se non sizeY: SizeY = dimensione altro: SizeY = int (sizey) x, y = scipy.mgrid [-size: size + 1, -sizey: sizey + 1] g = scipy.exp (- (x ** 2/float (dimensione) + y ** 2/float (sizey))/2) print g/np.sqrt (2 * np.pi) ' Ma il risultato ottenuto qui è diverso da quello ottenuto con fspecial in matlab – Khushboo

+0

Come è diverso? Cosa ti aspetti e cosa ottieni? – interjay

risposta

19

In termini generali se realmente vi preoccupate su come ottenere lo stesso identico risultato di MATLAB, il modo più semplice per ottenerlo è spesso guardando direttamente la fonte della funzione MATLAB.

In questo caso, 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; 
... 

Abbastanza semplice, eh? E '< 10 minuti di lavoro in porto questo a 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 

Questo mi dà la stessa risposta fspecial entro arrotondamento errore:

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

Questo è esattamente quello che stavo cercando. E l'hai reso davvero semplice. Grazie :) – Khushboo

-1

ho trovato soluzione simile per questo problema:

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

Salve Credo che il problema è che per un filtro gaussiano il fattore di normalizzazione dipende da quante dimensioni si è utilizzato. Quindi il filtro è simile a questo formula
Quello che ti manca è il quadrato del fattore di normalizzazione! E bisogno di rinormalizzare l'intera matrice a causa dell'accuratezza del calcolo! Il codice è attaccato qui:

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

L'uscita senza normalizzata per riassumere di 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]] 

L'uscita diviso per 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]] 
0

qui è quello di fornire un generatore finestra ND-gaussiana:

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 

questa funzione vi darà una normalizzate finestre gaussiana con data forma, al centro, e la varianza. per esempio: gen_gaussian_kernel (forma = (3,3,3), media = (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

Si potrebbe provare anche questo (come prodotto di 2 1D gaussiani variabili casuali indipendenti) per ottenere un 2D gaussiana kernel:

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

Problemi correlati