What is the LogGabor package?

Meanwhile biorthogonal wavelets got a very popular image processing tool, alternative multiresolution transforms have been proposed for solving some of their drawbacks, namely the poor selectivity in orientation and the lack of translation invariance due to the aliasing between subbands. These transforms are generally overcomplete and consequently offer huge degrees of freedom in their design. At the same time their optimization get a challenging task. We proposed here a log-Gabor wavelet transform gathering the excellent mathematical properties of the Gabor functions with a carefully construction to maintain the properties of the filters and to permit exact reconstruction. Two major improvements are proposed: first the highest frequency bands are covered by narrowly localized oriented filters. And second, all the frequency bands including the highest and lowest frequencies are uniformly covered so as exact reconstruction is achieved using the same filters in both the direct and the inverse transforms (which means that the transform is self-invertible). The transform is optimized not only mathematically but it also follows as much as possible the knowledge on the receptive field of the simple cells of the Primary Visual Cortex (V1) of primates and on the statistics of natural images. Compared to the state of the art, the log-Gabor wavelets show excellent behavior in their ability to segregate the image information (e.g. the contrast edges) from incoherent Gaussian noise by hard thresholding and to code the image features through a reduced set of coefficients with large magnitude. Such characteristics make the transform a promising tool for general image processing tasks.

Code: https://github.com/bicv/LogGabor

Reference (BibTex Format):

{.bibtex}
    @article{Fischer07cv,
        Author = {Fischer, Sylvain and Sroubek, Filip and Perrinet, Laurent U. and Redondo, Rafael and Crist{\'o}bal, Gabriel},
        Journal = {Int. Journal of Computional Vision},
        Keywords = {wavelet transforms, log-Gabor filters, oriented high-pass filters, image denoising, visual system},
        Title = {Self-invertible 2{D} log-{G}abor wavelets},
        Url = {https://laurentperrinet.github.io/publication/fischer-07-cv},
        Year = {2007}}

The log-Gabor transform compared to other multiresolution schemes. a. Schematic contours of the log-Gabor filters implented in Fischer (2007) in the Fourier domain with 5 scales and 8 orientations (only the contours at 78% of the filter maximum are drawn). b. The real part of the corresponding filters is drawn in the spatial domain. The two first scales are drawn at the bottom magnified by a factor of 4 for a better visualization. The different scales are arranged in lines and the orientations in columns. The low-pass filter is drawn in the upper-left part. c. The corresponding imaginary parts of the filters are shown in the same arrangement. Note that the low-pass filter does not have imaginary part. Insets (b) and (c) show the final filters built through all the processes described in Section II. d. In the proposed scheme the elongation of log-Gabor wavelets increases with the number of orientations nt . Here the real parts (left column) and imaginary parts (right column) are drawn for the 3, 4, 6, 8, 10, 12 and 16 orientation schemes. e. As a comparison orthogonal wavelet filters ’Db4’ are shown. Horizontal, vertical and diagonal wavelets are arranged on columns (low-pass on top). f. As a second comparison, steerable pyramid filters [30] are shown. The arrangement over scales and orientations is the same as for the log-Gabor scheme.

The Golden Laplacian Pyramid with log-Gabor filters. To represent the edges of the image at different levels and orientations, we use a multi-scale approach constructing a set of filters of different scales and according to oriented log-Gabor filters. This is represented here by stacking images on a Golden Rectangle Perrinet (2008), that is where the aspect ratio is the golden section $\phi = \frac{1+\sqrt{5}}{2}$. The level represents coefficients' amplitude, hue corresponds to orientation. We present here the base image on the left and the successive levels of the pyramid in a clockwise fashion (for clarity, we stopped at level $8$). Note that here we also use $\phi^2$ (that is $\phi+1$) as the down-scaling factor so that the pixelwise resolution of the pyramid images correspond across scales.

Install

To install them, use pip:

pip3 install LogGabor

This will install the necessary requirements :

  • numpy
  • NeuroTools
  • SLIP
  • matplotlib

More info and the whole source code may be found @ https://github.com/bicv/LogGabor.

Installing notebook dependencies

To run this notebook, you obviously need jupyter (aka ipython), but also https://github.com/ioam/holoviews for the nice visualization. In short, you need to

pip3 install -r requirements.txt

Importing the library


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)

In [2]:
help(LogGabor)


Help on class LogGabor in module LogGabor.LogGabor:

class LogGabor(SLIP.SLIP.Image)
 |  Defines a LogGabor framework by defining a ``loggabor`` function which return the envelope of a log-Gabor filter.
 |  
 |  Its envelope is equivalent to a log-normal probability distribution on the frequency axis, and von-mises on the radial axis.
 |  
 |  Method resolution order:
 |      LogGabor
 |      SLIP.SLIP.Image
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __init__(self, pe)
 |      Initializes the Image class
 |      
 |      May take as input:
 |      
 |      - a dictionary containing parameters
 |      - a ``ndarray`` (dimensions ``N_X`` and ``N_Y`` are guessed from this array)
 |      - a string representing a file or URL pointing to an image file
 |      - a string pointing to  a file or URL containing a dictionary of parameters (or simply the name of the file)
 |      - a ``NeuroTools.parameters.ParameterSet`` object containing parameters
 |      
 |      Parameters are
 |      
 |      - N_X and N_Y which are respectively the number of pixels in the vertical and horizontal dimensions respectively (MANDATORY)
 |      - optional parameters which are used in the various functions such as N_image when handling a database or the whitening parameters.
 |  
 |  argmax(self, C)
 |      Returns the ArgMax from C by returning the
 |      (x_pos, y_pos, theta, scale)  tuple
 |      
 |      >>> C = np.random.randn(10, 10, 5, 4)
 |      >>> x_pos, y_pos, theta, scale = mp.argmax(C)
 |      >>> C[x_pos][y_pos][theta][scale] = C.max()
 |  
 |  band(self, sf_0, B_sf, force=False)
 |      Returns the radial frequency envelope:
 |      
 |      Selects a preferred spatial frequency ``sf_0`` and a bandwidth ``B_sf``.
 |  
 |  golden_pyramid(self, z, mask=False, spiral=True, fig_width=13)
 |      The Golden Laplacian Pyramid.
 |      To represent the edges of the image at different levels, we may use a simple recursive approach constructing progressively a set of images of decreasing sizes, from a base to the summit of a pyramid. Using simple down-scaling and up-scaling operators we may approximate well a Laplacian operator. This is represented here by stacking images on a Golden Rectangle, that is where the aspect ratio is the golden section $\phi \eqdef rac{1+\sqrt{5}}{2}$. We present here the base image on the left and the successive levels of the pyramid in a clockwise fashion (for clarity, we stopped at level $8$). Note that here we also use $\phi^2$ (that is $\phi+1$) as the down-scaling factor so that the resolution of the pyramid images correspond across scales. Note at last that coefficient are very kurtotic: most are near zero, the distribution of coefficients has long tails.
 |  
 |  init(self)
 |      Initializes different convenient matrices for image processing.
 |      
 |      To be called when keeping the same Image object but changing the size of the image.
 |  
 |  linear_pyramid(self, image)
 |  
 |  loggabor(self, x_pos, y_pos, sf_0, B_sf, theta, B_theta, preprocess=True)
 |      Returns the envelope of a LogGabor
 |      
 |      Note that the convention for coordinates follows that of matrices: the origin is at the top left of the image, and coordinates are first the rows (vertical axis, going down) then the columns (horizontal axis, going right).
 |  
 |  loggabor_image(self, x_pos, y_pos, theta, sf_0, phase, B_sf, B_theta)
 |  
 |  orientation(self, theta, B_theta, force=False)
 |      Returns the orientation envelope:
 |      We use a von-Mises distribution on the orientation:
 |      - mean orientation is ``theta`` (in radians),
 |      - ``B_theta`` is the bandwidth (in radians). It is equal to the standard deviation of the Gaussian
 |      envelope which approximate the distribution for low bandwidths. The Half-Width at Half Height is
 |      given by approximately np.sqrt(2*B_theta_**2*np.log(2)).
 |      
 |      # 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
 |  
 |  show_loggabor(self, u, v, sf_0, B_sf, theta, B_theta, title='', phase=0.0)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from SLIP.SLIP.Image:
 |  
 |  FTfilter(self, image, FT_filter, full=False)
 |      Using the ``FTfilter`` function, it is easy to filter an image with a filter defined in Fourier space.
 |  
 |  dewhitening(self, white, preprocess=True, center=True, use_max=True)
 |      Returns the dewhitened image
 |  
 |  enveloppe_color(self, alpha)
 |  
 |  extract_patches_2d(self, image, patch_size, N_patches)
 |      Reshape a 2D image into a collection of patches
 |      
 |      redundant with self.patch, but similar call as
 |      https://github.com/scikit-learn/scikit-learn/blob/14031f6/sklearn/feature_extraction/image.py#L300
 |  
 |  fourier(self, image, full=True)
 |      Using the ``fourierr`` function, it is easy to retieve its Fourier transformation.
 |  
 |  fourier_grid(self)
 |      use that function to define a reference frame for envelopes in Fourier space.
 |      In general, it is more efficient to define dimensions as powers of 2.
 |  
 |  frequency_angle(self)
 |  
 |  frequency_radius(self)
 |  
 |  full_url(self, name_database)
 |  
 |  get_imagelist(self, exp, name_database='natural')
 |      returns an imagelist from a pickled database.
 |      
 |      If the stored imagelist does not exist, creates it.
 |      The ``exp`` string allows to tag the list for a particular experiment.
 |  
 |  get_pe(self, pe)
 |      Guesses the parameters from the init variable
 |      
 |      We perform a duck-typing to guess parameters from different possible sources.
 |      outputs a ParameterSet
 |  
 |  get_size(self, im)
 |  
 |  hist_radial_frequency(self, FT, N_f=20)
 |      A simple function to compute a radial histogram in different spatial frequency bands.
 |  
 |  imread(self, URL, resize=True)
 |  
 |  imshow(self, image, fig=None, ax=None, cmap=<matplotlib.colors.LinearSegmentedColormap object at 0x10538aeb8>, axis=False, norm=True, center=True, xlabel='Y axis', ylabel='X axis', figsize=None, mask=False, vmin=-1, vmax=1)
 |      Plotting routine to show an image
 |      
 |      Place the [0,0] index of the array in the upper left  corner of the axes.
 |      Data limits for the axes. The default assigns zero-based row, column
 |      indices to the x, y centers of the pixels.
 |      Note that the convention for coordinates follows that of matrices: the
 |      origin is at the top left of the image, and coordinates are first the
 |      rows (vertical axis, going down) then the columns (horizontal axis,
 |      going right).
 |  
 |  init_logging(self, filename='debug.log', name='SLIP')
 |  
 |  invert(self, FT_image, full=False)
 |      # Fourier number crunching
 |  
 |  list_database(self, name_database)
 |      Returns a list of the files in a folder
 |  
 |  load_in_database(self, name_database, i_image=None, filename=None, verbose=True)
 |      Loads a random image from the database ``name_database``.
 |      
 |      The strategy is to pick one image in the folder using the list provided by the ``list_database``function.
 |      
 |      TODO: it would be useful to be able to load from standard databases such as http://www.cps.utexas.edu/natural_scenes/db.shtml
 |  
 |  low_pass(self, f_0, steepness)
 |      Returns the low_pass filter used by (Olshausen, 98)
 |      
 |      parameters from Atick (p.240)
 |      f_0 = 22 c/deg in primates: the full image is approx 45 deg
 |      alpha makes the aspect change (1=diamond on the vert and hor, 2 = anisotropic)
 |      
 |      from Olshausen 98 (p.11):
 |      f_0  = 200 cycles / image (512 x 512 images)
 |      in absolute coordinates : f_0 = 200 / 512 / 2
 |      
 |      steepness is to produce a "fairly sharp cutoff"
 |  
 |  make_imagelist(self, name_database, verbose=False)
 |      Makes a list of images with no repetition.
 |      
 |      Takes as an input the name of a database (the name of a folder in the ``datapath``),
 |      returns a list of the filenames along with the crop area.
 |  
 |  mkdir(self)
 |      Initializes two folders for storing intermediate matrices and images.
 |      
 |      To be called before any operation to store or retrieve a result or figure.
 |  
 |  normalize(self, image, center=True, use_max=True)
 |  
 |  olshausen_whitening_filt(self)
 |      Returns the whitening filter used by (Olshausen, 98)
 |  
 |  patch(self, name_database, i_image=None, filename=None, croparea=None, threshold=0.2, verbose=True, preprocess=True, center=True, use_max=True, do_whitening=False)
 |      takes a subimage of size s (a tuple)
 |      
 |      does not accept if energy is relatively below a threshold (flat image)
 |  
 |  pipeline(self, image, preprocess=True, center=True, use_max=True, do_whitening=False)
 |      pre-processing pipeline
 |  
 |  power_spectrum(self, image)
 |  
 |  preprocess(self, image)
 |      Returns the pre-processed image
 |      
 |      From raw pixelized images, we want to keep information that is relevent to the content of
 |      the objects in the image. In particular, we want to avoid:
 |      
 |          - information that would not be uniformly distributed when rotating the image. In
 |          particular, we discard information outside the unit disk in Fourier space, in particular
 |          above the Nyquist frequency,
 |          - information that relates to information of the order the size of the image. This
 |          involves discarding information at low-level frequencies.
 |      
 |      See https://laurentperrinet.github.io/sciblog/posts/2015-05-21-a-simple-pre-processing-filter-for-image-processing.htmll
 |      for more information.
 |  
 |  retina(self, df=0.07, sigma=0.5)
 |      A parametric description of the envelope of retinal processsing.
 |      See https://laurentperrinet.github.io/sciblog/posts/2015-05-21-a-simple-pre-processing-filter-for-image-processing.htmll
 |      for more information.
 |      
 |      In digital images, some of the energy in Fourier space is concentrated outside the
 |      disk corresponding to the Nyquist frequency. Let's design a filter with:
 |      
 |          - a sharp cut-off for radial frequencies higher than the Nyquist frequency,
 |          - times a smooth but sharp transition (implemented with a decaying exponential),
 |          - times a high-pass filter designed by one minus a gaussian blur.
 |      
 |      This filter is rotation invariant.
 |      
 |      Note that this filter is defined by two parameters:
 |          - one for scaling the smoothness of the transition in the high-frequency range,
 |          - one for the characteristic length of the high-pass filter.
 |      
 |      The first is defined relative to the Nyquist frequency (in absolute values) while the second
 |      is relative to the size of the image in pixels and is given in number of pixels.
 |  
 |  savefig(self, fig, fname, figpath='', formats=None, display=True)
 |  
 |  set_size(self, im)
 |      Re-initializes the Image class with  the size given in ``im``
 |      
 |      May take as input:
 |      
 |      - a numpy array,
 |      - a string representing a file or URL pointing to an image file
 |      - a tuple
 |      
 |      Updated parameters are
 |      
 |      - N_X and N_Y which are respectively the number of pixels in the vertical and horizontal dimensions respectively (MANDATORY)
 |  
 |  show_FT(self, FT_image, fig=None, figsize=None, a1=None, a2=None, axis=False, title=True, FT_title='Spectrum', im_title='Image', norm=True, vmin=-1.0, vmax=1.0)
 |  
 |  show_image_FT(self, image, FT_image, fig=None, figsize=None, a1=None, a2=None, axis=False, title=True, FT_title='Spectrum', im_title='Image', norm=True, vmin=-1.0, vmax=1.0)
 |  
 |  show_spectrum(self, image, fig=None, figsize=None, a1=None, a2=None, axis=False, title=True, FT_title='Spectrum', im_title='Image', norm=True, vmin=-1.0, vmax=1.0)
 |  
 |  trans(self, u, v)
 |  
 |  translate(self, image, vec, preshift=True)
 |      Translate image by vec (in pixels)
 |      
 |      Note that the convention for coordinates follows that of matrices: the origin is at the top left of the image, and coordinates are first the rows (vertical axis, going down) then the columns (horizontal axis, going right).
 |  
 |  whitening(self, image)
 |      Returns the whitened image
 |  
 |  whitening_filt(self, recompute=False)
 |      Returns the envelope of the whitening filter.
 |      
 |      if we chose one based on structural assumptions (``struct=True``)
 |          then we return a 1/f spectrum based on the assumption that the structure of images
 |          is self-similar and thus that the Fourier spectrum scales a priori in 1/f.
 |      
 |      elif we chose to learn,
 |          returns theaverage correlation filter in FT space.
 |      
 |          Computes the average power spectrum = FT of cross-correlation, the mean decorrelation
 |          is given for instance by (Attick, 92).
 |      
 |      else
 |          we return the parametrization based on Olshausen, 1996
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from SLIP.SLIP.Image:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

To install the dependencies related to running this notebook, see Installing notebook dependencies.

Properties of log-Gabor filters

Gabor filters

An important task in image processing and related areas (such as understanding principles of vision) involves defining a dictionary of templates (or filters) for detecting edges. This representation should give a generic model of edges parameterized by their shape, orientation, and scale. Moreover the range of these parameters should match with what has been reported for simple-cell responses in macaque primary visual cortex (V1). As such, standard Gabors are classically used as they are well fitted to V1 simple cells (Daugman, 1980).

Firstly proposed by Dennis Gabor in 1946, the canonical coherent states of the Gabor filters are different versions of a Gaussian-shaped window shifted in time/space and frequency variables. Subsequently Morlet brought them into the wavelet multi-resolution framework and they are called Gabor wavelets as well. Belonging to the large Cohen's class, Gabor's work synthesizes the studies of Nyquist in Communication Theory in 1924 and Heisenberg in Quantum Mechanics in 1927, by which he proposed the Gaussian shape as an optimal envelope for time-frequency representation because it turns the uncertainly principle from inequality into equality.

Some important characteristics of Gabor wavelets are:

  1. the Gabor transform is obtained through a linear convolution,
  2. it may enable complete image recovery,
  3. the transform domain contains fully the energy of the signal (Parseval's theorem), 1. it is not orthogonal but an unconditional basis, a frame,
  4. the Fourier plane is symmetric and
  5. it is invariant to shifting in time/space, frequency and scale.
  6. Gabor filters are completely symmetric of both sides (isotropy), monomodal and centered (localization) and smooth and infinitely derivable (regularity).
  7. In the case of bidimensional signals (images), the scaled versions even can be rotated. The result is the partition of the Fourier plane into bands modulated in frequency and orientation which discriminate spectral features in multiples directions. In contrast, (bi-)orthogonal wavelets often have well-known difficulties in implementing more than three orientations (horizontal, vertical and diagonal).
  8. In addition, the Gaussian envelop is modulated by a complex exponential with odd and even phases, which is effective for analyzing features with different phases as abrupt impulses or steps, i.e. ridges and edges in 2D respectively. The filter results of a symmetric and an antisymmetric filter can be combined in a single complex number whose squared amplitude is called the Gabor-energy. This activity relates to the response of so-called complex cells in the primary visual cortex (see H. Spitzer and S. Hochstein. A complex-cell receptive-field model. Journal of Neuroscience, 53(5):1266–1286, 1985).

See https://en.wikipedia.org/wiki/Gabor_filter for more information.

log-Gabor filters

Gabor filters are a traditional choice for obtaining localised frequency information. It is worth stressing here other important aspects in that peculiar shape. Despite its Gaussian shape spreads to infinite, it decays rapidly from its center. They offer the best simultaneous localization of spatial and frequency information. However they have two main limitations. The maximum bandwidth of a Gabor filter is limited to approximately one octave and Gabor filters are not optimal if one is seeking broad spectral information with maximal spatial localization.

These limitations are well illustrated by focusing on the DC component. Indeed, one cannot construct Gabor functions of arbitrarily wide bandwidth and still maintain a reasonably small DC component in the even-symmetric filter. This difficulty can be seen if we look at the transfer function of an even-symmetric Gabor filter in the frequency domain. The transfer function is the sum of two Gaussians centred at plus and minus the centre frequency. If the standard deviation of these Gaussians becomes more than about one third of the centre frequency the tails of the two Gaussians will start to overlap excessively at the origin, resulting in a nonzero DC component. Transfer function of a high bandwidth even-symmetric Gabor filter. The two Gaussians that make up the function overlap at the origin, resulting in a significant DC component.

An alternative to the Gabor function is the Log-Gabor function proposed by Field [1987]. Log-Gabor filters can be constructed with arbitrary bandwidth and the bandwidth can be optimised to produce a filter with minimal spatial extent. We use a log-Gabor representation, which is well suited to represent a wide range of natural images~\citep{Fischer07}. Like Gabors, these filters are defined by Gaussians in Fourier space, but their specificity is that log-Gabors have Gaussians envelopes in log-polar frequency space. This is consistent with physiological measurements which indicate that V1 cell responses are symmetric on the log frequency scale. They have multiple advantages over Gaussians: In particular, they have no DC component, and more generally, their envelopes more broadly cover the frequency space~\citep{Fischer07cv}. In this chapter, we set the bandwidth of the Fourier representation of the filters to $1$ and $\pi/8$ respectively in the log-frequency and polar coordinates to get a family of relatively elongated (and thus selective) filters (see~\citet{Fischer07cv} and sigure above for examples of such edges). Prior to the analysis of each image, we used the spectral whitening filter described by~\citet{Olshausen97} to provide a good balance of the energy of output coefficients~\citep{Perrinet03ieee,Fischer07}. Such a representation is implemented in this package.

What do log Gabor functions look like in the spatial domain? Unfortunately due to the singularity in the log function at the origin one cannot construct an analytic expression for the shape of the log Gabor function in the spatial domain. One is reduced to designing the filters in the frequency domain and then performing a numerical inverse Fourier Transform to see what they look like. Their appearance is similar to Gabor functions though their shape becomes much "sharper" as the bandwidth is increased. The shapes of log Gabor and Gabor functions are almost identical for bandwidths less than one octave.

testing coordinates in Fourier space


In [3]:
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)


The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload

Defining input image as Lena:


In [4]:
import numpy as np
np.set_printoptions(precision=2, suppress=True)

In [5]:
from LogGabor import imread
image = imread('https://github.com/bicv/SLIP/raw/master/database/yelmo512.png')
print('Mean intensity: ', image.mean(), ' - standard deviation: ', image.std())


Mean intensity:  0.5346490691900253  - standard deviation:  0.22045908846780704

Defining image processing framework by creating a LogGabor object:


In [6]:
lg = LogGabor(parameterfile)
lg.set_size(image)

Rectifying image:


In [7]:
image = lg.normalize(image, center=True)
print('Mean intensity: ', image.mean(), ' - standard deviation: ', image.std())


Mean intensity:  -0.042770279037368776  - standard deviation:  0.394707489264721

Testing on a sample image


In [8]:
lg = LogGabor(parameterfile)
image = imread('https://github.com/bicv/SLIP/raw/master/database/yelmo512.png')
lg.set_size(image)
lg.pe.datapath = 'database/'
print(lg.pe)


{'N_image': 100, 'seed': None, 'N_X': 512, 'N_Y': 512, 'noise': 0.1, 'do_mask': True, 'mask_exponent': 3.0, 'do_whitening': True, 'white_name_database': 'kodakdb', 'white_n_learning': 0, 'white_N': 0.07, 'white_N_0': 0.0, 'white_f_0': 0.4, 'white_alpha': 1.4, 'white_steepness': 4.0, 'white_recompute': False, 'base_levels': 1.618, 'n_theta': 24, 'B_sf': 0.4, 'B_theta': 0.17453277777777776, 'use_cache': True, 'figpath': 'results', 'edgefigpath': 'results/edges', 'matpath': 'cache_dir', 'edgematpath': 'cache_dir/edges', 'datapath': 'database/', 'ext': '.pdf', 'figsize': 14.0, 'formats': ['pdf', 'svg', 'jpg'], 'dpi': 450, 'verbose': 0}

We will use the filters tested in the notebook and apply them on a sample image:


In [9]:
%%opts Image (cmap='gray') 
hv.Image(image)


Out[9]:

In [10]:
%%opts Image (cmap='gray') 
image = lg.whitening(image)*lg.mask
hv.Image(image)


Out[10]:

In [11]:
%opts Image.Phase_domain (cmap='hsv')
%opts Image.Amplitude_domain (cmap='hot')

In [12]:
# a function to explore these parameters:
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}
def filter_explore(image, param_name, param_range, verb=False, 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(0, 0, **params_)
        im_ = lg.FTfilter(image, FT_lg, full=True)
        
        amp = hv.Image(lg.normalize(np.absolute(im_), center=False), 
                    group='Amplitude domain',
                    key_dimensions=[r'$f_x$', r'$f_y$'],
                    value_dimensions=[hv.Dimension('Amplitude', range=(0,1))])
        phase = hv.Image(np.angle(im_)/np.pi,
                    group='Phase domain',
                    key_dimensions=[r'$x$', r'$y$'],
                    value_dimensions=[hv.Dimension('Phase', range=(-1,1))])
        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(sv).cols(2)

In [13]:
# explore parameters of LogGabors on the filtering:
filter_explore(image, param_name='theta', param_range=lg.theta)


Out[13]:

In [14]:
filter_explore(image, param_name='B_theta', param_range=lg.pe.B_theta*np.logspace(-.3, .2, 6))


Out[14]:

In [15]:
filter_explore(image, param_name='sf_0', param_range=lg.sf_0, verb=True)


Out[15]:

In [16]:
filter_explore(image, param_name='B_sf', param_range=lg.pe.B_sf*np.logspace(-.6, .6, 9))


Out[16]:

more book keeping


In [17]:
%load_ext watermark
%watermark


2018-06-20T14:47:42+02:00

CPython 3.6.5
IPython 6.4.0

compiler   : GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.2)
system     : Darwin
release    : 17.6.0
machine    : x86_64
processor  : i386
CPU cores  : 36
interpreter: 64bit

In [18]:
%load_ext version_information
%version_information numpy, scipy, matplotlib, SLIP, LogGabor


Out[18]:
SoftwareVersion
Python3.6.5 64bit [GCC 4.2.1 Compatible Apple LLVM 9.1.0 (clang-902.0.39.2)]
IPython6.4.0
OSDarwin 17.6.0 x86_64 i386 64bit
numpy1.14.5
scipy1.1.0
matplotlib2.2.2
SLIP20171205
LogGabor2017-12-05.binder
Wed Jun 20 14:47:42 2018 CEST