In the first part of this series, we looked at how to open images and perform some basic manipulations using Scikit Image. This second part will introduce you to digital image filters!
Digital filters for image analysis
Often we need to perform some operation on our images. For example, we may want to reduce noise, find object edges in the image. Digital filters can help with that!
In image analysis, a digital filter is a mathematical operation that is applied to the image to perform specific operation on it. The output image results from the application of said operation in a pixel-wise manner on the input image.
Usually we apply the operation to a region around each pixel of interest, most often square or rectangular; we then slide this region throughout the image to apply the operation to each pixel. This sliding window is called the filter kernel.
Simple filters: min, max, mean, median
These are probably the simplest examples of filters. They consist of a $n \times m $ kernel that “moves” through the image and applies a specific operation (e.g. the minimum) to the neighbourhood of each pixel.
For instance, imagine that our image contains the following values
$$\begin{bmatrix}10 & 15 & 25 & 38\\115 & 22 & 28 & 125\\ 31 & 47 & 34 & 32\\220 & 216 & 83 & 92\end{bmatrix}$$
We want to apply a $3 \times 3$ maximum filter to the image. Let’s consider the value 47 in the original image. The filter will take a $3 \times 3$ neighbourhood centred around it and find the maximum value. So the neighbourhood is
$$\begin{bmatrix}115 & 22 & 28\\ 31 & \mathbf{47} & 34\\220 & 216 & 83\end{bmatrix}$$
We apply our operation, in this case $max(X)$ to this sub-matrix. The maximum value is 220, which will become the value of the pixel at that position in the output image. For the next pixel (original value 34) the same filter will return 216.
Edge pixels
You may be wondering what to do with pixels at the edge. After all, the top left pixel in the example above does not have a 3×3 neighborhood. There are various ways around this.
- You can crop the kernel, simply ignoring any pixel that is not there. So, you will just use smaller neighbourhoods for edge pixels.
- You can extend the image by repeating the border pixels values.
- Alternatively you can wrap the image around. When doing this, the left neighbours of the pixels in the first column will be the pixels in the last column, the top neighbours of the first row of pixels will be those in the last row and so on.
- A different solution is to mirror the image at the edges.
- Finally you can crop the image, and not apply the filter to the edge pixels. This will, however, result in a smaller output image.
The schematic below summarises these options for the top-left pixel of an image
Basic filters in Scikit Image
The Scikit Image filters
submodule contains a lot of different functions to apply filters to images. The simple filters described above are found within the filters.rank
submodule.
Let’s start by loading an image. This shows some cell nuclei, and is quite noisy.
from skimage.io import imread, imshow
nuclei = imread("nuclei_noisy.tif")
imshow(nuclei)
We can now apply the minimum, maximum, mean and median filters to the image
import numpy as np
from skimage.filters.rank import minimum, maximum, mean, median
img_min = minimum(nuclei, selem=np.ones((5, 5)))
img_max = maximum(nuclei, selem=np.ones((5, 5)))
img_med = median(nuclei, selem=np.ones((5, 5)))
img_mean = mean(nuclei, selem=np.ones((5, 5)))
The selem
parameter defines the kernel as a matrix of 0 and 1. We use np.ones
to define a $5 \times 5$ matrix of 1. We can use this to use kernels that are not square for example selem = np.array[[0,1,0], [1,1,1], [0,1,0]]
(or you can use Numpy functions such as np.diamond
, or, np.disk
).
Here is what we get
In general, the minimum filter acts as a “shrinking” filter, while the maximum filter expands object borders. This are useful, for example, when detecting objects in an image.
The mean and median filter are good at removing noise, by eliminating the effect of very bright or very dark pixels; usually the median filter works better, and is often used at the beginning of many image analysis pipelines.
Convolutional filters
Similar to what discussed above, convolutional filters can be used to process images.
Convolution takes each pixel of the image, together with its neighbours, and adds them together, weighting the sum by the value of a kernel of the same size of the neighbourhood. The kernel can be of arbitrary size, and its values should generally sum to 1. So, for instance, having the following image and kernel
The output value for the pixel marked in red will be
$$255 * 0 + 50 * (-1) + 80 * 0 + 80 * (-1) + 80 * 5 + 0 * (-1) +$$
$$255 * 0 + 50 * (-1) + 80 * 0 = \mathbf{220}$$
A very commonly used convolutional filter is the Gaussian filter. Some examples of Gaussian kernels are shown here
The Gaussian filter has the effect of blurring the image. For example
from skimage.filters import gaussian
# 5x5 kernel
imshow(gaussian(nuclei, sigma=5))
Subtracting the blurred version of an image from the original one, and adding back to the original has the effect of actually sharpening it! This filter is called unsharp mask, and is available in skimage.filters
. The radius
parameter is the kernel size for the Gaussian smoothing, and amount is a multiplier. The output of the filter is
$\text{output} = \text{original} + \text{amount} * (\text{original} – \text{blurred})$
from skimage.filters import unsharp_mask
nuclei_sharp = unsharp_mask(nuclei, radius=10, amount=1)
Another commonly used convolutional filter is the Sobel filter, used for edge detection. It uses two kernels, one for determining horizontal edges and one for vertical edges
from skimage.filters import sobel
nuclei_edges = sobel(nuclei)
There are many other filters you can apply, I would suggest having a look at the Explained Visually where you can play with convolutional filters! I hope this post gave you a brief introduction to filters and keep an eye for new parts of this series!