Demo for spectral analysis functions

Tom Wallis, August 2016

Warning: these results will depend on the bandwidths and step sizes of the sliding window averaging, and this will interact with image sizes.


In [1]:
import os
import numpy as np
import matplotlib.pyplot as plt
from skimage import io, transform
from psyutils.image import show_im
import psyutils as pu

%load_ext autoreload
%autoreload 2

%matplotlib inline

Demos with an artificial edge image


In [2]:
# load a test image:
im = pu.im_data.orientation_test()
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (512, 512)
image has range from 0.0 to max 1.0
the mean of the image is 0.502
the SD of the image is 0.225
the rms contrast (SD / mean) is 0.449

In [3]:
# show the spectrum:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (512, 512)
image has range from -5.823 to max 11.787
the mean of the image is 1.156
the SD of the image is 1.504
the rms contrast (SD / mean) is 1.301

In [4]:
# take spectral power:
d = pu.image.spectral_analysis(im)
# plot:
pu.image.spectral_analysis_plot(d)


Test orientation mapping


In [5]:
x, y = pu.image.axes_cart(128)
im = np.sin(x * 8 * np.pi)
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (128, 128)
image has range from -1.0 to max 1.0
the mean of the image is 0.0
the SD of the image is 0.704
the rms contrast (SD / mean) is 1.76532140012e+16

In [6]:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(A)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (128, 128)
image has range from 0.0 to max 8105.88
the mean of the image is 1.525
the SD of the image is 90.143
the rms contrast (SD / mean) is 59.091

In [7]:
d = pu.image.spectral_analysis(im)
# plot:
pu.image.spectral_analysis_plot(d)


/Users/tomwallis/miniconda3/envs/py35/lib/python3.5/site-packages/numpy/core/_methods.py:59: RuntimeWarning: Mean of empty slice.
  warnings.warn("Mean of empty slice.", RuntimeWarning)

In [8]:
x, y = pu.image.axes_cart(128)
im = np.sin(y * 8 * np.pi)
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (128, 128)
image has range from -1.0 to max 1.0
the mean of the image is -0.0
the SD of the image is 0.704
the rms contrast (SD / mean) is -2.03011961014e+16

In [9]:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(A)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (128, 128)
image has range from 0.0 to max 8105.88
the mean of the image is 1.525
the SD of the image is 90.143
the rms contrast (SD / mean) is 59.091

In [10]:
d = pu.image.spectral_analysis(im)
# plot:
pu.image.spectral_analysis_plot(d)


/Users/tomwallis/miniconda3/envs/py35/lib/python3.5/site-packages/numpy/core/_methods.py:59: RuntimeWarning: Mean of empty slice.
  warnings.warn("Mean of empty slice.", RuntimeWarning)

In [11]:
x, y = pu.image.axes_cart(128, angle = 45)
im = np.sin(y * 8 * np.pi)
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (128, 128)
image has range from -1.0 to max 1.0
the mean of the image is 0.0
the SD of the image is 0.707
the rms contrast (SD / mean) is 8.58439208135e+16

In [12]:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(A)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (128, 128)
image has range from 0.0 to max 7230.491
the mean of the image is 6.388
the SD of the image is 90.315
the rms contrast (SD / mean) is 14.138

In [13]:
d = pu.image.spectral_analysis(im, sf_band=1, ori_band=5)
# plot:
pu.image.spectral_analysis_plot(d)



In [14]:
im = pu.im_data.single_bar()
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from 0.0 to max 1.0
the mean of the image is 0.502
the SD of the image is 0.277
the rms contrast (SD / mean) is 0.553

In [15]:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from -7.36 to max 9.291
the mean of the image is -0.763
the SD of the image is 1.884
the rms contrast (SD / mean) is -2.47

In [16]:
d = pu.image.spectral_analysis(im)
# plot:
pu.image.spectral_analysis_plot(d)



In [17]:
# horizontal
im = transform.rotate(pu.im_data.single_bar(), 90, cval = 0.5)
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from 0.0 to max 1.0
the mean of the image is 0.502
the SD of the image is 0.277
the rms contrast (SD / mean) is 0.553

In [18]:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from -7.36 to max 9.291
the mean of the image is -0.763
the SD of the image is 1.884
the rms contrast (SD / mean) is -2.47

In [19]:
d = pu.image.spectral_analysis(im)
# plot:
pu.image.spectral_analysis_plot(d)



In [20]:
# +45
im = transform.rotate(pu.im_data.single_bar(), 45, cval = 0.5)
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from 0.0 to max 1.0
the mean of the image is 0.501
the SD of the image is 0.275
the rms contrast (SD / mean) is 0.549

In [21]:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from -7.727 to max 9.291
the mean of the image is -0.903
the SD of the image is 1.907
the rms contrast (SD / mean) is -2.112

In [22]:
d = pu.image.spectral_analysis(im)
# plot:
pu.image.spectral_analysis_plot(d)



In [23]:
# opposite phase:
im = transform.rotate(pu.im_data.single_bar(), 225, cval = 0.5)
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from 0.0 to max 1.0
the mean of the image is 0.501
the SD of the image is 0.275
the rms contrast (SD / mean) is 0.549

In [24]:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from -7.727 to max 9.291
the mean of the image is -0.903
the SD of the image is 1.907
the rms contrast (SD / mean) is -2.112

In [25]:
d = pu.image.spectral_analysis(im)
# plot:
pu.image.spectral_analysis_plot(d)



In [26]:
# -45
im = transform.rotate(pu.im_data.single_bar(), -45, cval = 0.5)
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from 0.0 to max 1.0
the mean of the image is 0.501
the SD of the image is 0.275
the rms contrast (SD / mean) is 0.549

In [27]:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (147, 147)
image has range from -7.727 to max 9.291
the mean of the image is -0.903
the SD of the image is 1.907
the rms contrast (SD / mean) is -2.112

In [28]:
d = pu.image.spectral_analysis(im)
# plot:
pu.image.spectral_analysis_plot(d)



In [29]:
im = pu.image.gabor_create(orientation = np.pi/2)
show_im(im.real)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (107, 107)
image has range from -0.0 to max 0.001
the mean of the image is 0.0
the SD of the image is 0.0
the rms contrast (SD / mean) is 35.897

In [30]:
A, P, F = pu.image.spectral_analysis_fft(im.real)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (107, 107)
image has range from -30.63 to max -0.804
the mean of the image is -20.351
the SD of the image is 4.219
the rms contrast (SD / mean) is -0.207

In [31]:
d = pu.image.spectral_analysis(im.real, ori_step = 1, ori_band = 10)
# plot:
pu.image.spectral_analysis_plot(d)



In [32]:
im = pu.image.gabor_create(orientation = 0)
show_im(im.real)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (107, 107)
image has range from -0.0 to max 0.001
the mean of the image is 0.0
the SD of the image is 0.0
the rms contrast (SD / mean) is 35.897

In [33]:
A, P, F = pu.image.spectral_analysis_fft(im.real)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (107, 107)
image has range from -30.63 to max -0.804
the mean of the image is -20.351
the SD of the image is 4.219
the rms contrast (SD / mean) is -0.207

In [34]:
d = pu.image.spectral_analysis(im.real)
# plot:
pu.image.spectral_analysis_plot(d)



In [35]:
im = pu.image.gabor_create(orientation = np.pi/4)
show_im(im.real)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (77, 77)
image has range from -0.0 to max 0.001
the mean of the image is 0.0
the SD of the image is 0.0
the rms contrast (SD / mean) is 26.459

In [36]:
A, P, F = pu.image.spectral_analysis_fft(im.real)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (77, 77)
image has range from -14.327 to max -0.9
the mean of the image is -11.249
the SD of the image is 1.762
the rms contrast (SD / mean) is -0.157

In [37]:
d = pu.image.spectral_analysis(im.real)
# plot:
pu.image.spectral_analysis_plot(d)



In [38]:
# test a more complex image:
im = pu.im_data.tiger_grey()
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (256, 256)
image has range from 0.012 to max 1.0
the mean of the image is 0.515
the SD of the image is 0.194
the rms contrast (SD / mean) is 0.376

In [39]:
A, P, F = pu.image.spectral_analysis_fft(im)
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (256, 256)
image has range from -4.581 to max 10.427
the mean of the image is 2.564
the SD of the image is 1.053
the rms contrast (SD / mean) is 0.411

In [40]:
x = np.linspace(-A.shape[1]//2, A.shape[1]//2, num=A.shape[1])
plt.plot(x, np.log(A[A.shape[0]//2, :]));



In [41]:
d = pu.image.spectral_analysis(im)
# plot:
pu.image.spectral_analysis_plot(d)


Note how the (log) mean amplitude averaged by my analysis function corresponds to the mean of the (log) amplitudes in the fourier spectrum. No weird normalisation going on.

Testing of spectral analysis function internals


In [42]:
im = pu.im_data.tiger_grey()
show_im(im)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (256, 256)
image has range from 0.012 to max 1.0
the mean of the image is 0.515
the SD of the image is 0.194
the rms contrast (SD / mean) is 0.376

In [43]:
A, P, F = pu.image.spectral_analysis_fft(im)

In [44]:
show_im(np.log(A))


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (256, 256)
image has range from -4.581 to max 10.427
the mean of the image is 2.564
the SD of the image is 1.053
the rms contrast (SD / mean) is 0.411

Test radial scan


In [45]:
mask = pu.image.make_filter_gaussian(A.shape, peak=1, width=4, zero_mean=True)
show_im(mask)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (256, 256)
image has range from 0.0 to max 0.997
the mean of the image is 0.002
the SD of the image is 0.034
the rms contrast (SD / mean) is 16.522

In [46]:
plt.plot(mask[mask.shape[0]//2, 100:150]);



In [47]:
sf_band = 1
sf_step = 10
finished = 0
inc = 0
freq = []
freq_amp = []
while finished == 0:
    peak = 1 + inc  # start from 1 cpi
    freq.append(peak)  # this frequency centre

    mask = pu.image.make_filter_gaussian(A.shape, peak=peak,
                                         width=sf_band,
                                         pixel_units=True,
                                         zero_mean=True)
    mask[mask < 0.01] = 0  # cut tails of Gaussian

    # mask = pu.image.make_filter_log_cosine(A.shape, peak=peak,
    #                                        pixel_units=True,
    #                                        zero_mean=True)

    res = A * mask
    # take mean of nonzero region:
    mean = np.mean(res[res > 0])
    freq_amp.append(mean)

    inc += sf_step  # in pixel unit of radial increments (cpi).
    if peak >= A.shape[0]/2:
        # if freq greater than or equal to nyquist:
        finished = 1

    plt.figure()
    plt.title("Inc = {} \n peak = {} \n mean = {}".format(inc, peak,
                                                          mean))
    plt.imshow(mask * np.log(A)); plt.grid("off")


Test angular scan


In [48]:
filt = pu.image.make_filter_orientation_gaussian(A.shape,
                                                 peak=360,
                                                 width=10,
                                                 symmetric=False,
                                                 pixel_units=True,
                                                 zero_mean=True)
show_im(filt)


image is of type <class 'numpy.ndarray'>
image has data type float64
image has dimensions (256, 256)
image has range from 0.0 to max 1.0
the mean of the image is 0.056
the SD of the image is 0.19
the rms contrast (SD / mean) is 3.364

In [49]:
ori_band = 12
ori_step = 36
symmetric = False
finished = 0
inc = 0
ang = []
ang_amp = []
if symmetric is True:
    # bowtie, running 0-180
    end_angle = 180
elif symmetric is False:
    end_angle = 360

while finished == 0:
    peak = 0 + inc
    ang.append(peak)

    mask = pu.image.make_filter_orientation_gaussian(A.shape,
                                                     peak=peak,
                                                     width=ori_band,
                                                     symmetric=symmetric,
                                                     pixel_units=True,
                                                     zero_mean=True)

    # this average amplitude:
    ang_amp.append(np.mean(A * mask))
    inc += ori_step
    if peak >= end_angle:
        finished = 1

    plt.figure()
    plt.title("Inc = {} \n peak = {} \n mean = {}".format(inc, peak,
                                                          np.mean(A * mask)))
    plt.imshow(mask * np.log(A)); plt.grid("off")



In [50]:
# convert degrees to radians:
ang = np.array(ang, dtype=np.float)
ang /= (180 / np.pi)
ang


Out[50]:
array([ 0.        ,  0.62831853,  1.25663706,  1.88495559,  2.51327412,
        3.14159265,  3.76991118,  4.39822972,  5.02654825,  5.65486678,
        6.28318531])

In [51]:
ax = plt.axes(projection = "polar")
ax.plot(ang, ang_amp);