Image Processing — Identifying Shapes in an image without neural networks.

Vipul Vaibhaw
4 min readFeb 11, 2020

Practical guide for understanding Gaussian Blur, Simple Thresholding and Adaptive Thresholding and Contours.

In this post, we will be demonstrating a pipeline which we can use to identify shapes in an image. It will be useful because using neural networks always is not a viable solution.

source — internet

We will start by importing some essential libraries needed for image processing.

import cv2import imutilsimport numpy as np

Now we will read the image using opencv and will resize it using imutils.

image = cv2.imread("4.jpg")resized = imutils.resize(image, width=500)ratio = image.shape[0] / float(resized.shape[0])

In case you are wondering the usage of imutils.resize() and not cv2.resize(), I used it because I wanted to aspect ratio of the image to be preserved.

I will now be converting the image to gray because it would make the processing easier for me. I would then be dealing only with 1 dimension instead of 3 dimensions(RGB).

gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
grayscale image

Alright, next thing would be to apply a slight Gaussian Blur because I want only prominent shapes here, like the corners of the bricks and not the circles or shapes inside of the brick.

blurred = cv2.GaussianBlur(gray, (5, 5), 0)
Gaussian Blurred Grayscale image

Gaussian Blur ( also known as Gaussian Smoothing) is a low pass filter which allows only signals below a particular frequency to pass. It is commonly used in edge detection because it helps in reduction of noise in an image. For now just assume that it is a good way of doing edge detection, later in the post you will find a section where result will be posted without doing Gaussian Blur.

Now, we will apply thresholding on this image.

For now we will be applying simple thresholding to the image. Simple thresholding can only be applied to a grayscale image. Simple Thresholding means that if pixel value is greater than a threshold value, it is assigned one value (may be white), else it is assigned another value (may be black). The function used is cv2.threshold().

thresh = cv2.threshold(blurred, 70, 255, cv2.THRESH_BINARY)[1]
Image after simple thresholding

The next thing will be to find contours in the image.

Contours can be explained simply as a curve joining all the continuous points (along the boundary), having same color or intensity. The contours are a useful tool for shape analysis and object detection and recognition. Opencv recommends to use binary images. So before finding contours, apply threshold or canny edge detection. We will be using thresholded image.

cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)cnts = imutils.grab_contours(cnts)

We are there, let’s plot all the contours on the image.

for c in cnts:
c = c.astype("float")
c *= ratio
c = c.astype("int")
cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)

The output will look like the following —

Output

Well, can we further improve our pipeline?

Let’s see. What if we remove the Gaussian Blur and run the pipeline again?

Output without Gaussian Blur

I see, it surprisingly works better. Can we improve it more?

It is time to use a better thresholding mechanism. There is something known as Adaptive thresholding.

Adaptive Thresholding allows us to use different thresholding value at different parts of the image. It is quite helpful when we have varying illumination condition across the image.

thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
Output with Gaussian Blur and Adaptive Threshold

The output looks much better.

Just for curiosity, what if we remove gaussian blur with from the adaptive threshold’s pipeline?

The output is somewhat same but lines are very messy.

The output is unclean because we didn’t remove the noise from the pipeline.

We can conclude by saying that for the given problem of identifying the contours in the image, adaptive threshold with gaussian blur worked best.

Can you further improve it? Let me know in comments.

--

--

Vipul Vaibhaw

I am passionate about computer engineering. Building scalable distributed systems| Web3 | Data Engineering | Contact me — vaibhaw[dot]vipul[at]gmail[dot]com