Noise reduction#

The simplest way to reduce noise is to slightly blur the image, for example using a gaussian or median filter.

import numpy as np
from skimage.io import imread
from pyclesperanto_prototype import imshow
import matplotlib.pyplot as plt
# load zfish image and extract a channel
zfish_image = imread('../../data/zfish_eye.tif')[:,:,0]

cropped_zfish = zfish_image[630:730, 500:600]
from skimage.filters import median, gaussian
from skimage.morphology import disk

zfish_gaussian = gaussian(cropped_zfish, sigma=2, preserve_range=True)
zfish_median = median(cropped_zfish, footprint=disk(4))

fig, axs = plt.subplots(1, 3, figsize=(10,10))

imshow(cropped_zfish, plot=axs[0])
axs[0].set_title("Original")
imshow(zfish_gaussian, plot=axs[1])
axs[1].set_title("Gaussian")
imshow(zfish_median, plot=axs[2])
axs[2].set_title("Median")
for ax in axs:
    ax.axis('off')
plt.tight_layout()
../_images/09_Filters_3_0.png

Background removal filters#

There are also background removal filters. If there is a more or less homogeneous intensity spread over the whole image, potentially increasing in a direction, it is recommended to remove this background before segmenting the image.

As example image, we will work with a zebrafish eye data set (Courtesy of Mauricio Rocha Martins, Norden lab, MPI CBG). As you can see, there is some intensity spread around the nuclei we want to segment later on. The source of this background signal is out-of-focus light.

imshow(zfish_image)
../_images/09_Filters_6_0.png

To subtract the background, we need to determine it first. There are several algorithms that are useful for removing inhomogeneous background.

Rolling ball algorithm#

Well known to FIJI users, the rolling-ball algorithm is still widely used to remove background. The radius parameter determines the largest object that should not be considered background.

from skimage.restoration import rolling_ball

background_rolling = rolling_ball(zfish_image, radius=50)

zfish_rolling = zfish_image - background_rolling

fig, axs = plt.subplots(1, 3, figsize=(10,10))

imshow(zfish_image, plot=axs[0])
axs[0].set_title("Original")
imshow(background_rolling, plot=axs[1])
axs[1].set_title("Background (rolling ball)")
imshow(zfish_rolling, plot=axs[2])
axs[2].set_title("Background subtracted")
for ax in axs:
    ax.axis('off')
plt.tight_layout()
../_images/09_Filters_8_0.png

Tophat filter#

The white_tophat filter gives very similar results to the rolling ball algorithm, but is algorithmically much simpler. The footprint parameter determines the largest object that should not be considered background:

from skimage.morphology import disk, white_tophat

zfish_tophat = white_tophat(zfish_image, footprint=disk(50))

background_tophat = zfish_image - zfish_tophat

fig, axs = plt.subplots(1, 3, figsize=(10,10))

imshow(zfish_image, plot=axs[0])
axs[0].set_title("Original")
imshow(background_tophat, plot=axs[1])
axs[1].set_title("Background (tophat)")
imshow(zfish_tophat, plot=axs[2])
axs[2].set_title("Background subtracted")
for ax in axs:
    ax.axis('off')
plt.tight_layout()
../_images/09_Filters_10_0.png

Gaussian blur#

A simple gaussian blur can also be used to estimate the background:

from skimage.filters import gaussian

background_gaussian = gaussian(zfish_image, sigma=50, preserve_range=True)

zfish_gaussian = zfish_image - background_gaussian

fig, axs = plt.subplots(1, 3, figsize=(10,10))

imshow(zfish_image, plot=axs[0])
axs[0].set_title("Original")
imshow(background_gaussian, plot=axs[1])
axs[1].set_title("Background (Gaussian)")
imshow(zfish_gaussian, plot=axs[2])
axs[2].set_title("Background subtracted")
for ax in axs:
    ax.axis('off')
plt.tight_layout()
../_images/09_Filters_13_0.png

Comparing different algorithms#

Which one is your favorite algorithm?

fig, axs = plt.subplots(2, 2, figsize=(6.67,8))

imshow(zfish_image, plot=axs[0,0])
axs[0,0].set_title("Original")
imshow(zfish_rolling, plot=axs[0,1])
axs[0,1].set_title("Rolling ball")
imshow(zfish_tophat, plot=axs[1,0])
axs[1,0].set_title("Tophat")
imshow(zfish_gaussian, plot=axs[1,1])
axs[1,1].set_title("Gaussian")
for ax in axs.ravel():
    ax.axis('off')
plt.tight_layout()
../_images/09_Filters_15_0.png

Difference of Gaussians#

In many cases, background subtraction is combined with denoising. The Difference of Gaussians (DoG) performs both operations in one function.

from skimage.filters import difference_of_gaussians

zfish_difference_of_gaussians = difference_of_gaussians(zfish_image, 3, 50)

fig, axs = plt.subplots(1, 3, figsize=(10,10))

imshow(zfish_image, plot=axs[0])
axs[0].set_title("Original")
imshow(background_gaussian, plot=axs[1])
axs[1].set_title("Background (Gaussian)")
imshow(zfish_difference_of_gaussians, plot=axs[2])
axs[2].set_title("Difference of Gaussian")
for ax in axs:
    ax.axis('off')
plt.tight_layout()
../_images/09_Filters_17_0.png

Edge detection#

Edge detection highlights parts of the image where the signal intensity changes strongly.

A common filter for edge detection is the laplace filter

from skimage.filters import laplace

zfish_laplace = laplace(zfish_image, ksize=5)

fig, axs = plt.subplots(1, 2, figsize=(6.67,10))

imshow(zfish_image, plot=axs[0])
axs[0].set_title("Original")
imshow(zfish_laplace, plot=axs[1])
axs[1].set_title("Laplace")
for ax in axs:
    ax.axis('off')
plt.tight_layout()
../_images/09_Filters_19_0.png

Oops, I guess the image was too noisy. Let’s use what we have learned above and apply the laplacian to an image where we reduced the noise

zfish_gaussian = gaussian(zfish_image, sigma=3)
zfish_laplacian_of_gaussian = laplace(zfish_gaussian)

fig, axs = plt.subplots(1, 3, figsize=(10,10))

imshow(zfish_image, plot=axs[0])
axs[0].set_title("Original")
imshow(zfish_gaussian, plot=axs[1])
axs[1].set_title("Gaussian")
imshow(zfish_laplacian_of_gaussian, plot=axs[2])
axs[2].set_title("Laplacian of Gaussian (LoG)")
for ax in axs:
    ax.axis('off')
plt.tight_layout()
../_images/09_Filters_21_0.png

Exercises#

Exercise 1#

compare the different algorithms again but now add min_display_intensity=0 to the parameters of imshow.

Does that change your assessment of the algorithms? What are the implications for further processing of your image?

Exercise 2#

Apply different algorithms and radii to remove the background in the zebrafish eye dataset. Zoom into the dataset using cropping and figure out how to make the background go away optimally.