In [3]:
%matplotlib inline
import sys
import numpy as np
from matplotlib import pyplot as plt
In [4]:
def plot_spectrum(F, amplify=1000, ax=None):
"""Normalise, amplify and plot an amplitude spectrum."""
# Note: the problem here is that we have a spectrum whose histogram is
# *very* sharply peaked at small values. To get a meaningful display, a
# simple strategy to improve the display quality consists of simply
# amplifying the values in the array and then clipping.
# Compute the magnitude of the input F (call it mag). Then, rescale mag by
# amplify/maximum_of_mag.
mag = abs(F)
mag *= amplify/mag.max()
# Next, clip all values larger than one to one.
mag[mag > 1] = 1
if ax is None: ax = plt.gca()
ax.imshow(mag, plt.cm.Blues)
Read in original image, convert to floating point for further manipulation; imread returns a MxNx4 RGBA image. Since the image is grayscale, just extract the 1st channel
Hints:
In [7]:
fname = 'images/moonlanding.png'
im = plt.imread(fname).astype(float)
print("Image shape:", im.shape)
Compute the 2d FFT of the input image
Hint: Look for a 2-d FFT in np.fft.
Note: call this variable 'F', which is the name we'll be using below.
In the lines following, we'll make a copy of the original spectrum and
truncate coefficients.
In the lines following, we'll make a copy of the original spectrum and
truncate coefficients.
In [8]:
F = np.fft.fft2(im)
# Define the fraction of coefficients (in each direction) we keep
keep_fraction = 0.1
# Call ff a copy of the original transform. Numpy arrays have a copy
# method for this purpose.
ff = F.copy()
# Set r and c to be the number of rows and columns of the array.
r,c = ff.shape
# Set to zero all rows with indices between r*keep_fraction and
# r*(1-keep_fraction):
ff[r*keep_fraction:r*(1-keep_fraction)] = 0
# Similarly with the columns:
ff[:, c*keep_fraction:c*(1-keep_fraction)] = 0
Reconstruct the denoised image from the filtered spectrum, keep only the real part for display. Hint: There's an inverse 2d fft in the np.fft module as well (don't forget that you only want the real part). Call the result im_new and plot the results
In [9]:
im_new = np.fft.ifft2(ff).real
fig, ax = plt.subplots(2, 2, figsize=(10,7))
ax[0,0].set_title('Original image')
ax[0,0].imshow(im, plt.cm.gray)
ax[0,1].set_title('Fourier transform')
plot_spectrum(F, ax=ax[0,1])
ax[1,1].set_title('Filtered Spectrum')
plot_spectrum(ff, ax=ax[1,1])
ax[1,0].set_title('Reconstructed Image')
ax[1,0].imshow(im_new, plt.cm.gray);