In [1]:
%load_ext autoreload
%autoreload 2
from LogGabor import LogGabor
parameterfile = 'https://raw.githubusercontent.com/bicv/LogGabor/master/default_param.py'
lg = LogGabor(parameterfile)
To install the dependencies related to running this notebook, see Installing notebook dependencies.
In [2]:
import holoviews as hv
#hv.notebook_extension('bokeh')
%load_ext holoviews.ipython
%output size=150 dpi=120
%load_ext autoreload
%autoreload 2
import os
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
fig_width = 12
figsize=(fig_width, .618*fig_width)
Defining a reference log-gabor (look in the corners!)
In [3]:
sf_0 = .02 # TODO .1 cycle / pixel (Geisler)
params= {'sf_0':sf_0, 'B_sf': lg.pe.B_sf, 'theta':0., 'B_theta': lg.pe.B_theta}
In [4]:
%opts Image (cmap='gray')
%opts Image.Fourier_domain (cmap='hot')
In [5]:
def fourier_domain(arr):
return hv.Image(arr, group='Fourier domain',
key_dimensions=[r'$f_Y$', r'$f_X$'],
value_dimensions=[hv.Dimension('Fourier', range=(0,0.01))])
def image_domain(arr):
return hv.Image(arr,group='Image domain',
key_dimensions=[r'$Y$', r'$X$'],
value_dimensions=[hv.Dimension('Image', range=(-1,1))])
In [6]:
FT_lg = lg.loggabor(0, 0, **params)
(fourier_domain(lg.normalize(np.absolute(FT_lg), center=False))
+ image_domain(lg.normalize(lg.invert(FT_lg), center=False)))
Out[6]:
Translating in the middle:
In [7]:
N_X, N_Y = 256, 256 #image.shape
help(lg.translate)
same params, larger frequency with sf_0
In [8]:
params2 = {'sf_0':sf_0*4, 'B_sf':lg.pe.B_sf, 'theta':0., 'B_theta':lg.pe.B_theta}
FT_lg = lg.loggabor(N_X/2, N_Y/2, **params2)
(fourier_domain(lg.normalize(np.absolute(FT_lg), center=False))
+ image_domain(lg.normalize(lg.invert(FT_lg), center=False)))
Out[8]:
Same params, but larger frequency with sf_0
In [9]:
params2 = {'sf_0':sf_0*4, 'B_sf':lg.pe.B_sf, 'theta':0., 'B_theta':lg.pe.B_theta}
In [10]:
FT_lg = lg.loggabor(N_X/4, N_Y/2, **params2)
(fourier_domain(lg.normalize(np.absolute(FT_lg), center=False))
+ image_domain(lg.normalize(lg.invert(FT_lg), center=False)))
Out[10]:
Narrower with a smaller B_theta:
In [11]:
params3 = {'sf_0':sf_0, 'B_sf':lg.pe.B_sf, 'theta':0., 'B_theta':lg.pe.B_theta/2}
FT_lg = lg.loggabor(N_X/4, 3*N_Y/4, **params3)
(fourier_domain(lg.normalize(np.absolute(FT_lg), center=False))
+ image_domain(lg.normalize(lg.invert(FT_lg), center=False)))
Out[11]:
Broader spectrum with B_sf
In [12]:
params4 = {'sf_0':sf_0, 'B_sf':lg.pe.B_sf*2., 'theta':0., 'B_theta':lg.pe.B_theta}
FT_lg = lg.loggabor(N_X/4, N_Y/4, **params4)
(fourier_domain(lg.normalize(np.absolute(FT_lg), center=False))
+ image_domain(lg.normalize(lg.invert(FT_lg), center=False)))
Out[12]:
Using a function to explore these parameters:
In [13]:
def lg_explore(param_name, param_range, angle=False, movie=True):
if movie:
amp_map, phase_map = hv.HoloMap(), hv.HoloMap()
else:
ims = []
for param_ in param_range:
if angle:
title = np.str(param_*180/np.pi) + r'$^0$'
else:
title = np.str(param_)
if param_name=='phase':
FT_phase = np.exp(-1j*param_)
params_=params.copy()
else:
FT_phase = 1
params_=params.copy()
params_.update({param_name:param_})
FT_lg = lg.loggabor(N_X/2, N_Y/2, **params_) * FT_phase
amp = fourier_domain(lg.normalize(np.absolute(FT_lg), center=False))
phase = image_domain(lg.normalize(lg.invert(FT_lg), center=False))
if movie:
amp_map[param_] = amp
phase_map[param_] = phase
else:
ims.append((amp + phase))
if movie:
return amp_map + phase_map
else:
return np.sum(ims).cols(2)
Now exploring these parameters individually:
In [14]:
lg_explore(param_name='phase',
param_range=np.linspace(0, np.pi, 24, endpoint=False), angle=True)
Out[14]:
In [15]:
lg_explore(param_name='theta',
param_range=lg.theta,
angle=True)
Out[15]:
In [16]:
lg_explore(param_name='B_theta',
param_range=lg.pe.B_theta*np.logspace(-.3, .2, 6), angle=True)
Out[16]:
Here, we define a pyramid by defining a vector of sf_0
values that we use later in Matching Pursuit (see https://github.com/bicv/SparseEdges):
In [17]:
#n_levels = int(np.log(np.max((lg.pe.N_X, lg.pe.N_Y)))/np.log(lg.pe.base_levels))
print('for an image of size', np.max((lg.pe.N_X, lg.pe.N_Y)), ', at base lg.pe.base_levels=', lg.pe.base_levels, ', we have n_levels=', lg.n_levels)
#v_sf_0 = .5 * (1 - 1/n_levels) / np.logspace(0, n_levels, n_levels, base=lg.pe.base_levels)[::-1]
print('Range of spatial frequencies (in cycles per image pixel) =', lg.sf_0)
print('Range of spatial frequencies (in pixels per cycle) =', 1./lg.sf_0)
print('Range of spatial frequencies (in cycles per image size) =', lg.pe.N_X * lg.sf_0)
lg_explore(param_name='sf_0', param_range=lg.sf_0)
Out[17]:
geometric mean distances across frequencies :
In [18]:
scaling = np.sqrt(lg.sf_0[:, np.newaxis]*lg.sf_0[np.newaxis, :])
print('mean scaling=', scaling.mean())
In [19]:
lg_explore(param_name='B_sf', param_range=lg.pe.B_sf*np.logspace(-.6, .6, 9))
Out[19]:
In [20]:
%load_ext watermark
%watermark
In [21]:
%load_ext version_information
%version_information numpy, scipy, matplotlib, SLIP, LogGabor
Out[21]: