Morphological Filtering in scikit-image for Image Cleaning and Preprocessing

Learning about the most popular morphological operations in Image Processing

Rafael Madrigal
4 min readSep 14, 2022

Spatial and Morphological Filters work the same way. They use a structuring element or a kernel to manipulate the pixel neighborhood. This process is called convolution.

Morphological Filters unlike spatial filters use the kernels to “clean” an image prior to a segmentation task. They usually allow us to remove noise generated from image binarization or patch small holes and open some space. Meanwhile, spatial filters serve the purpose of enhancing the image as a form of data augmentation for a different machine learning task or enhancement for enhancement’s sake.

Different morphological operations in an image

In the example above we showcase 7 morphological operations (there are more but these are commonly used). We used a circular structural element and applied each operation to the Original image. We discuss below what happens at each box.

Erosion. Erosion as the name suggests refers to the deletion or the “erosion” of pixel values. In the output above, we can notice that the white border surrounding the phantom was deleted/ removed by the structural element. What happens is that the structural element is passed through every pixel in the original image, superimposing the center/ origin of the structural element with the pixel. If the entire structural element is not contained in the image i.e. some 1s in the element overlaps with 0s in the original image, then the pixel is deleted; otherwise, it is retained. The opposite of Erosion is dilation

Dilation. In dilation, is the opposite of erosion. In dilation, the structural element is passed through every pixel, superimposing the origin with the pixel, but as long as part of the structural element is included in the original image i.e. some of the 1s match, then the pixel in question will be “dilated” or added to the original image. If there is no element from the image that matches those of the structural element, then the pixel will remain deleted.

Closing and Opening are just combinations of Erosion and Dilation done simultaneously. Closing is the erosion of a dilation while Opening is the dilation of an erosion. That’s why in the example above, we managed to bridge the gap by performing a dilation; however not fully given that we used an erosion afterward.

Skeletonize. Skeletonization is the process of reducing foreground regions in a binary image to a skeleton that preserves the connectivity of original regions. So in our example, we removed almost all of the foreground regions and only retained “lines” or skeletons that keep the original regions connected (i.e. tangential curves to the edges of the phantom).

Remove small holes. Is simply a compound operation of closing and/or opening in an attempt to remove small holes in the image to provide a certain area threshold.

Let’s look at some applications of Morphological operations

selem = np.array([[0, 1, 1, 1, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[0, 1, 1, 1, 0]])
art1_k = erosion(art1, selem)
art1_k = dilation(art1_k, selem)

In the example below, we used a circular structural element to “open” the path and remove the lines connecting the spheres/ dots. Using a disk element as a kernel is useful here since we wanted to preserve the dots and not the lines.

Below, we eliminated all the vertical lines through two consecutive erosions using a vertical structural element. Intuitively, we can eliminate the horizontal lines if we use the horizontal element and perform erosion twice.

selem_hor = np.array([[0, 0, 0],
[1, 1, 1],
[0, 0, 0]])
selem_ver = np.array([[0, 1, 0],
[0, 1, 0],
[0, 1, 0]])
art2_k = erosion(erosion(art2, selem_ver), selem_ver)

In the next example, we were able to bridge the gaps between the lines by dilating using a square structuring element and then eroding twice using vertical and horizontal elements.

selem_hor = np.array([[0, 0, 0],
[1, 1, 1],
[0, 0, 0]])
selem_sq = np.array([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]])
selem_ver = np.array([[0, 1, 0],
[0, 1, 0],
[0, 1, 0]])
art3_k = erosion(erosion(dilation(art3, selem_sq[:3, :3]),
selem_ver),
selem_hor)

Wrapping Up

We learned the intuition behind some of the common morphological operations for image processing and showcased how we can execute them using scikit-image. Next, we will look at blob detection and how we can identify and count items using this algorithm.

--

--

Rafael Madrigal

Data Scientist and Corporate Strategist. Can’t function without Coffee