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.
import numpy as np
from skimage.io import imread
from stackview import imshow
from skimage.filters import gaussian
from skimage.restoration import rolling_ball
from skimage.morphology import disk
import matplotlib.pyplot as plt
from skimage.filters import difference_of_gaussians
from skimage.morphology import white_tophat
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.
# load zfish image and extract a channel
zfish_image = imread('data/zebrafish_eye.tif')
imshow(zfish_image)
To subtract the background, we need to determine it first. We can use the rolling-ball algorithm for that. The radius parameter configures how distant pixels should be taken into account for determining the background intensity.
background_rolling = rolling_ball(zfish_image, radius=25)
imshow(background_rolling)
Afterwards, we subtract the background from the original and display all three images:
zfish_rolling = zfish_image - background_rolling
imshow(zfish_rolling)
For visualization purposes, we show all the three images side-by-side.
fig, axs = plt.subplots(1, 3, figsize=(15,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")
Text(0.5, 1.0, 'Background subtracted')
We could do the same using a Gaussian blur filter.
background_gaussian = gaussian(zfish_image, sigma=20, preserve_range=True)
zfish_gaussian = zfish_image - background_gaussian
fig, axs = plt.subplots(1, 3, figsize=(15,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")
Text(0.5, 1.0, 'Background subtracted')
In some scenarios it also makes sense to divide the image by the background. This helps for example to make all nuclei in this image have similar intensities. This could be advantageous for nuclei segmentation.
background_gaussian = gaussian(zfish_image, sigma=50, preserve_range=True)
zfish_gaussian = zfish_image / background_gaussian
fig, axs = plt.subplots(1, 3, figsize=(15,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 divided")
Text(0.5, 1.0, 'Background divided')
Other background subtraction techniques#
There are other techniques for background subtraction such as the top-hat. Furthermore, the Difference of Gaussians (DoG) is a technique for combined denoising and background removal.
# DoG
zfish_dog = difference_of_gaussians(zfish_image, 0, 15)
# Top-Hat
zfish_top_hat = white_tophat(zfish_image, disk(15))
fig, axs = plt.subplots(1, 3, figsize=(15,10))
imshow(zfish_dog, plot=axs[0], min_display_intensity=0)
axs[0].set_title("Difference of Gaussian")
imshow(zfish_top_hat, plot=axs[1])
axs[1].set_title("Top hat")
imshow(zfish_rolling, plot=axs[2])
axs[2].set_title("Rolling ball algorithm")
Text(0.5, 1.0, 'Rolling ball algorithm')
Exercise#
Implement the following algorithm:
Apply a minimum filter to an image (
filters.rank.minimum), e.g. with a radius of 15.Apply a maximum filter to the result of the minimum filter with the same radius.
Subtract the result of the maximum filter from the original image.
Which of the above shown algorithms has a similar result?