In [1]:
%load_ext autoreload
%autoreload 2
%matplotlib inline
from numpy import *
from IPython.html.widgets import *
import matplotlib.pyplot as plt
from IPython.core.display import clear_output
Gabor filters were originally introduced as an acoustic (1D) filter to explain audition.
A Gabor filter is a product of the Gaussian envelope and the (complex) sinusoidal carrier:
$$g(x; \sigma, f, \phi) = \underbrace{\exp\left( -\frac{x^2}{2 \sigma^2} \right)}_{\textrm{Gaussian}} \underbrace{ \exp\left( i \left(\frac{2 \pi x}{f} + \phi \right) \right)}_{\textrm{Sinusoid}}$$Remember, $e^{i x} = \cos x + i \sin x$; so the filter has both real and imaginary parts.
In [2]:
xs=linspace(-3, 3, 1000)
gaussian=exp(-xs**2/2)
sinusoid=exp(1j*2*pi*xs/0.5) # 1j is "i"
plt.plot(xs, gaussian, '--')
plt.plot(xs, real(sinusoid), '--')
plt.plot(xs, gaussian*real(sinusoid))
Out[2]:
Similarly, we can characterize 2D Gabor filters using:
Exercise 1. Let's create some 2D Gabor filters and visualize them.
In [3]:
#from skimage.filters import gabor_kernel
# ^--- if you have latest version of scikit-image installed.
from filters import gabor_kernel
g=gabor_kernel(frequency=0.1, theta=pi/4,
sigma_x=3.0, sigma_y=5.0, offset=pi/5, n_stds=5)
plt.imshow(real(g), cmap='RdBu', interpolation='none',
vmin=-abs(g).max(), vmax=abs(g).max())
plt.axis('off')
Out[3]:
For the purposes of cognitive modeling, however, the most important is that the filter responses achieve translation invariance: that is, the magnitude of the (complex) filter response doesn't change very much when the image is shifted slightly.
Exercise 2. Let's apply different Gabor filters to an image and visualize the filter responses.
(This can be done very easily using skimage.filters.gabor_filter
function.)
Try changing the values in the sliders. Note how the magnitude of the complex response (response = abs
) provides some shift invariance - that is, the response changes less even when the image is shifted slightly (image_shift_x
and image_shift_y
.)
In [4]:
# The code to create interactive plots
def plot_gabor_filtering(dataset, image_id, frequency, theta, response_fn=real, image_shift_x=0, image_shift_y=0):
"""Plots the results of the real part of the Gabor filter."""
image = dataset.images[image_id]
H, W = image.shape
original=pad(dataset.images[image_id], ((image_shift_y,0), (image_shift_x,0)), mode='reflect')[:H,:W]
fig, axs = plt.subplots(1, 4, figsize=(15,5))
axs[0].imshow(original,cmap='gray',interpolation='none')
axs[0].set_title('Original Image')
axs[0].axis('off')
delta_image=zeros(original.shape, dtype=float)
delta_image[tuple(array(delta_image.shape)/2)]=1.0 # 1.0 at the center
kernel_real, kernel_imag=gabor_filter(delta_image, frequency=frequency, theta=theta)
kernel=kernel_real + 1j*kernel_imag
axs[1].imshow(response_fn(kernel),cmap='gray',interpolation='none')
axs[1].set_title('Filter (%s)' % response_fn.__name__)
axs[1].axis('off')
response_real,response_imag=gabor_filter(original, frequency=frequency, theta=theta)
response=response_real + 1j*response_imag
axs[2].imshow(response_fn(response),cmap='gray',interpolation='none')
axs[2].set_title('Filter Response')
axs[2].axis('off')
unshifted_real,unshifted_imag=gabor_filter(image, frequency=frequency, theta=theta)
unshifted_response=unshifted_real + 1j*unshifted_imag
difference=(response_fn(response)-response_fn(unshifted_response)) / response_fn(unshifted_response).std()
axs[3].imshow(difference,cmap='gray',interpolation='none', vmin=-2, vmax=2)
axs[3].set_title('Difference from unshifted (NRMSE=%f)' % sqrt((difference**2).mean()))
axs[3].axis('off')
In [5]:
#from skimage.filters import gabor_filter
from filters import gabor_filter
import pickle
dataset=pickle.load(open('data/cafe.pkl','r'))
interactive(plot_gabor_filtering,
dataset=fixed(dataset),
image_id=(0,dataset.images.shape[0]-1),
frequency=FloatSlider(min=0.001, max=0.5, value=0.1),
theta=FloatSlider(min=0, max=pi, value=pi / 2.0),
response_fn={'Real': real, 'Imag': imag, 'Abs': abs},
image_shift_x=IntSlider(min=0, max=10, value=0),
image_shift_y=IntSlider(min=0, max=10, value=0))