In the previous blog, we discussed Hit-or-Miss transformation, that is used for finding desired patterns in an image. In this blog, we will discuss various applications of Hit-or-miss transform such as thinning, thickening, etc. So, let’s get started.
Thinning
This is somewhat similar to erosion or opening operation that we discussed earlier. As clear from the name, this is used to thin the foreground region such that its extent and connectivity is preserved. Preserving extent means preserving the endpoints of a structure whereas connectivity can refer to either 4-connected or 8-connected. Thinning is mostly used for producing skeletons which serve as image descriptors, and for reducing the output of the edge detectors to a one-pixel thickness, etc.
There are various algorithms to implement the thinning operation such as
- Zhang Suen fast parallel thinning algorithm
- Non-max Suppression in Canny Edge Detector
- Guo and Hall’s two sub-iteration parallel Thinning algorithm
- Iterative algorithms using morphological operations such as hit-or-miss, opening and erosion, etc
In this blog, we will only discuss the last algorithm, rest we will discuss in the following blogs. So, let’s get started.
In this, we can implement thinning either using erosion and opening operations or by using hit-or-miss operation. Let’s first discuss thinning using erosion and opening. This can be expressed as the union of skeleton subsets where each subset is given by the following expression (A-Binary image and B-structuring element)
Here, n indicates the number of iterations of erosion. N is the last iterative step before A erodes to the empty set (stopping condition). Now, let’s discuss how to implement this using OpenCV-Python.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import cv2 import numpy as np # Create an image with text on it img = np.zeros((100,400),dtype='uint8') font = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(img,'TheAILearner',(5,70), font, 2,(255),5,cv2.LINE_AA) img1 = img.copy() # Structuring Element kernel = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3)) # Create an empty output image to hold values thin = np.zeros(img.shape,dtype='uint8') # Loop until erosion leads to an empty set while (cv2.countNonZero(img1)!=0): # Erosion erode = cv2.erode(img1,kernel) # Opening on eroded image opening = cv2.morphologyEx(erode,cv2.MORPH_OPEN,kernel) # Subtract these two subset = erode - opening # Union of all previous sets thin = cv2.bitwise_or(subset,thin) # Set the eroded image for next iteration img1 = erode.copy() cv2.imshow('original',img) cv2.imshow('thinned',thin) cv2.waitKey(0) |
Now, let’s discuss thinning using hit-or-miss transform. Thinning of set A by SE B can be expressed in terms of hit-or-miss transform as
This means we remove all those pixels whose neighborhood exactly matches the pixels in the SE. Instead of applying this with a single structuring element, it is a common practice to implement it using a sequence of SE so as to produce symmetric results. This operation is mostly applied iteratively until no further changes occur.
Thickening
Thickening is the dual of thinning and thus is equivalent to applying the thinning operation on the background or on the complement of the set A.
In the next blog, we will discuss the remaining thinning algorithms in detail. Hope you enjoy reading.
If you have any doubt/suggestion please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.
Hey, are you ever going to do a Guo Hall implementation in python with opencv?