forked from PeterMcGor/LogGabor
/
LogGabor.py
executable file
·103 lines (83 loc) · 3.14 KB
/
LogGabor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# -*- coding: utf8 -*-
"""
LogGabor
See http://pythonhosted.org/LogGabor
"""
__author__ = "(c) Laurent Perrinet INT - CNRS"
import numpy as np
from numpy.fft import fft2, fftshift, ifft2, ifftshift
class LogGabor:
"""
defines a LogGabor transform.
Its envelope is equivalent to a log-normal probability distribution on the frequency axis, and von-mises on the radial axis.
"""
def __init__(self, im):
"""
initializes the LogGabor structure
"""
self.pe = im.pe
self.im = im
self.N_X = im.N_X
self.N_Y = im.N_Y
self.f_x, self.f_y = self.im.f_x, self.im.f_y
self.f = self.im.f
## LOW LEVEL OPERATIONS
def enveloppe_color(self, alpha):
# 0.0, 1.0, 2.0 are resp. white, pink, red/brownian envelope
# (see http://en.wikipedia.org/wiki/1/f_noise )
if alpha == 0:
return 1.
else:
f_radius = np.zeros(self.f.shape)
f_radius = self.f**alpha
f_radius[(self.N_X-1)//2 + 1 , (self.N_Y-1)//2 + 1 ] = np.inf
return 1. / f_radius
def band(self, sf_0, B_sf):
# selecting a donut (the ring around a prefered frequency)
if sf_0 == 0.: return 1.
# see http://en.wikipedia.org/wiki/Log-normal_distribution
env = 1./self.f*np.exp(-.5*(np.log(self.f/sf_0)**2)/B_sf**2)
return env
def orientation(self, theta, B_theta):
# selecting one direction, theta is the mean direction, B_theta the spread
# we use a von-mises distribution on the orientation
# see http://en.wikipedia.org/wiki/Von_Mises_distribution
angle = np.arctan2(self.f_y, self.f_x)
cos_angle = np.cos(angle-theta)
enveloppe_orientation = np.exp(cos_angle/B_theta**2)
# As shown in:
# http://www.csse.uwa.edu.au/~pk/research/matlabfns/PhaseCongruency/Docs/convexpl.html
# this simple bump allows (without the symmetric) to code both symmetric and anti-symmetric parts
return enveloppe_orientation
def loggabor(self, u, v, sf_0, B_sf, theta, B_theta):
env = self.band(sf_0, B_sf) * \
self.orientation(theta, B_theta) * \
self.im.trans(u*1., v*1.)
# normalizing energy:
env /= np.sqrt((np.abs(env)**2).mean())
# in the case a a single bump (see radius()), we should compensate the fact that the distribution gets complex:
env *= np.sqrt(2.)
return env
def show_loggabor(self, u, v, sf_0, B_sf, theta, B_theta, title='', phase=0.):
FT_lg = self.loggabor(u, v, sf_0, B_sf, theta, B_theta)
fig, a1, a2 = self.im.show_FT(FT_lg * np.exp(-1j*phase))
return fig, a1, a2
def _test():
import doctest
doctest.testmod()
#####################################
#
if __name__ == '__main__':
_test()
#### Main
"""
Some examples of use for the class
"""
from pylab import imread
image = imread('database/lena512.png')[:,:,0]
from NeuroTools.parameters import ParameterSet
pe = ParameterSet('default_param.py')
pe.N_X, pe.N_Y = image.shape
from SLIP import Image
im = Image(pe)
lg = LogGabor(im)