Image Processing Filters#

Filters are mathematical operations that produce a new image out of one or more images. Pixel values between input and output images may differ.

import numpy as np

import matplotlib.pyplot as plt
from skimage.io import imread
from skimage import data
from skimage import filters
from skimage import morphology
from scipy.ndimage import convolve, gaussian_laplace
import stackview

To demonstrate what specific filters do, we start with a very simple image. It contains a lot of zeros and a single pixel with value 1 in the middle.

image1 = np.zeros((5, 5))
image1[2, 2] = 1
image1
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])
plt.imshow(image1, cmap='gray')
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7f1301b62a30>
../_images/97aa4ddc8a85334dd952d03a663bc289af6dc3e709384d5042f2198e39c69d66.png

Gaussian kernel#

To apply a Gaussian blur to an image, we convolve it using a Gaussian kernel. The function gaussian in scikit-image can do this for us.

blurred = filters.gaussian(image1, sigma=1)
blurred
array([[0.00291504, 0.01306431, 0.02153941, 0.01306431, 0.00291504],
       [0.01306431, 0.05855018, 0.09653293, 0.05855018, 0.01306431],
       [0.02153941, 0.09653293, 0.15915589, 0.09653293, 0.02153941],
       [0.01306431, 0.05855018, 0.09653293, 0.05855018, 0.01306431],
       [0.00291504, 0.01306431, 0.02153941, 0.01306431, 0.00291504]])
plt.imshow(blurred, cmap='gray')
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7f1301a91790>
../_images/7b455ad9d60cee442e5aca1f309ae740378f31350312d03926749fd28b71c91c.png

Laplacian#

Whenever you wonder what a filter might be doing, just create a simple test image and apply the filter to it.

image2 = np.zeros((9, 9))
image2[4, 4] = 1

plt.imshow(image2, cmap='gray')
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7f13019d6460>
../_images/ac84bb70c8b7e3a7b7c2d720adf9380a3602f16babb7f54c38a9e61a6035ee0f.png
mexican_hat = filters.laplace(image2)

plt.imshow(mexican_hat, cmap='gray')
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7f130178df10>
../_images/f4c3c50637f774f2f45e33e4e0336fad7dc5ca7695b78acbee1f2b25d0dcf33a.png

Laplacian of Gaussian#

We can also combine filters, e.g. using functions. If we apply a Gaussian filter to an image and a Laplacian afterwards, we have a filter doing the Laplacian of Gaussian (LoG) per definition.

def laplacian_of_gaussian(image, sigma):
    """
    Applies a Gaussian kernel to an image and the Laplacian afterwards.
    """
    
    # blur the image using a Gaussian kernel
    intermediate_result = filters.gaussian(image, sigma)
    
    # apply the mexican hat filter (Laplacian)
    result = filters.laplace(intermediate_result)
    
    return result
log_image1 = laplacian_of_gaussian(image2, sigma=1)

plt.imshow(log_image1, cmap='gray')
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7f13016dcd30>
../_images/972b8c07baa5d4e0a4f1e20439b08fff0559f9d35914b00eca0baca7a5887804.png

Interactive filter parameter tuning#

To understand better what filters are doing, it shall be recommended to apply them interactively. The following code will not render on github.com. You need to execute the notebook locally use this interactive user-interface.

image3 = imread('data/mitosis_mod.tif').astype(float)
plt.figure(figsize=(3,3))
plt.imshow(image3, cmap = 'gray')
<matplotlib.image.AxesImage at 0x7f1301608610>
../_images/c247852a36194eaf5488985b4a8636753fb163f1f7bd455b822d61367e0249ca.png
stackview.interact(laplacian_of_gaussian, image3, zoom_factor=4)

More filter examples#

We demonstrate some more typical filters using this nuclei example image.

Denoising#

Common filters for denoising images are the mean filter, the median filter and the Gaussian filter. For the non linear filters mean and median, we have to define the neighborhood for calculation.

denoised_mean = filters.rank.mean(image3.astype(np.uint8), morphology.disk(1))

plt.imshow(denoised_mean, cmap='gray')
<matplotlib.image.AxesImage at 0x7f130113dcd0>
../_images/49ec37ddeaedbcf59741d9c4dbd1ca27ead9a4a5591ea4b176600f63b44803e4.png
morphology.disk(1)
array([[0, 1, 0],
       [1, 1, 1],
       [0, 1, 0]], dtype=uint8)
denoised_median = filters.median(image3, morphology.disk(1))

plt.imshow(denoised_median, cmap='gray')
<matplotlib.image.AxesImage at 0x7f1300f5d9a0>
../_images/91f917f59f09e9c7c4b5409fe148b1589496cf0abf9e519bf150a28476c0076f.png
denoised_median2 = filters.median(image3, morphology.disk(5))

plt.imshow(denoised_median2, cmap='gray')
<matplotlib.image.AxesImage at 0x7f1300edcf10>
../_images/49608828f31d0a9ab9c68428c0e09c400d3b18fa6d7d59f3b6fc80af1b78d4b6.png
denoised_gaussian = filters.gaussian(image3, sigma=1)

plt.imshow(denoised_gaussian, cmap='gray')
<matplotlib.image.AxesImage at 0x7f1300e5c970>
../_images/6a0d5ff42a636f64e724bfd66ee0fa10fc0b35bfd20e80a8cfeb27917cae2050.png

We can also show these images side-by-side using matplotlib.

fig, axes = plt.subplots(1,3, figsize=(15,15))

axes[0].imshow(denoised_mean, cmap='gray')
axes[1].imshow(denoised_median, cmap='gray')
axes[2].imshow(denoised_gaussian, cmap='gray')
<matplotlib.image.AxesImage at 0x7f1300ddef40>
../_images/12981ee94f92a9f21e0f7c810da1d5724b2beb650430cdeca1ffc43b8acdf923.png

Top-hat filtering / background removal#

top_hat = morphology.white_tophat(image3, morphology.disk(15))

plt.imshow(top_hat, cmap='gray')
<matplotlib.image.AxesImage at 0x7f1300434820>
../_images/ea8aef136b032c70c346c1f383994f49951670ba234c69017f4bd8d1fa4a6a77.png

Edge detection#

sobel = filters.sobel(image3)

plt.imshow(sobel, cmap='gray')
<matplotlib.image.AxesImage at 0x7f1300d022e0>
../_images/572e1d5995f860a01435483c2e74183d079607d0ba4481c2583c2be31ae1d99d.png

Custom kernel#

When applying linear filters such as Gaussian and Laplacian, we technically convole the image. We can also convolve it using a custom kernel.

kernel1 = [[1, 2, 1],
           [0, 0, 0],
           [-1, -2, -1]]
output1 = convolve(image3, kernel1)

plt.imshow(output1, cmap='gray')
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7f1301927be0>
../_images/cbfc2c7e71392921f0dd0c7abe605398a0aefd394e36bc9dd1a0d68c6029a5f4.png

Exercise 1#

The above filter hightlights horizontal edges in the image. Write code that highlights vertical edges.

Hint: read more about the Sobel operator.

Exercise 2#

Write a function that computes the Difference of Gaussian.

def difference_of_gaussian(image, sigma1, sigma2):
    # enter code here

Use a simple function call to try out the function.

dog_image = difference_of_gaussian(image3, 1, 5)

plt.imshow(dog_image, cmap='gray')

Use the stackview library to play with it interactively.

stackview.interact(difference_of_gaussian, image3, zoom_factor = 4)