Draw Contours on an Image using OpenCV

Maximinusjoshus
featurepreneur
Published in
4 min readApr 24, 2021

Have you noticed lines drawn around mountain areas and areas with an elevation in topographical maps? These lines are known as topographical contours. They give you the elevation profile of a terrain. These lines are either drawn manually or are computer-generated. In this article, we will see how to use OpenCV to draw contour lines on a simple image.

Background vector created by freepik — www.freepik.com

The findContours function:

OpenCV provides us with the findContours function which finds the contours in an image and stores it as a numpy array of coordinate points. The function definition is as follows:

cv.findContours(image,
mode,
method[,
contours[,
hierarchy[,
offset]]]) ->contours, hierarchy

image- Source, an 8-bit single-channel image. If it is a grayscale image, non-zero pixels are treated as 1’s and zero pixels remain 0’s, so the image is treated as binary. You can also convert your image to binary before feeding it to this function. Use binary images for better accuracy.
mode- Contour retrieval mode.
method- Contour approximation method.
and three other optional parameters.

The function returns the contours and their hierarchy. The contours are returned in the form of a python list. The list contains a numpy array of (x,y) coordinates, which form the contour as a whole.

Contour Retrieval Mode:

The second return value that the findContours function returns is the hierarchy of the contours in the image.

What is hierarchy?

The contours in an image can be arranged according to the relationships they share with each other. There may be contours which lie one within the other. Then the outer contour can be called the parent and the inner contour the child. This relationship can now be used to arrange the contours according to the hierarchy. Relationships other than the parent-child relationship are also used to define the hierarchy of contours in an image.

This feature comes in handy when you have to retrieve specific contours using their index values or when you have to retrieve contours which belong to a specific group (like only the extreme outer contours in the image, only the first five of the outer contours in an image etc.).

If you are just interested in retrieving or drawing all the contours in an image, you don’t need to get into the depths of all this creepy stuff. You can keep it simple just by using RETR_LIST as your contour retrieval mode.

To get a clear insight of all the retrieval modes and how they work, it is highly recommended to refer to OpenCV’s official tutorial on the hierarchy of contours.

Contour approximation method:

There are two contour approximation methods in OpenCv. They are,

  • cv.CHAIN_APPROX_NONE
  • cv.CHAIN_APPROX_SIMPLE.

If you pass cv.CHAIN_APPROX_NONE, all the boundary points of the contour are stored. But actually, do we need all the points? For eg, you found the contour of a straight line. Do you need all the points on the line to represent that line? No, we need just two endpoints of that line. This is what cv.CHAIN_APPROX_SIMPLE does. It removes all redundant points and compresses the contour, thereby saving memory.

The drawContours function:

After finding the contours and storing the coordinate points (x, y)of the contour line in an array, we can use these points to draw the contour lines on the image. We use the drawContours function of OpenCV to do the same.

cv.drawContours(image,
contours,
contourIdx,
color[,
thickness[,
lineType[,
hierarchy[,
maxLevel[,
offset]]]]]) ->image

image- Destination image.
contours- All the input contours. Each contour is stored as a point vector.
contourIdx- Parameter indicating a contour to draw. If it is negative, all the contours are drawn.
color- Color of the contours.
thickness- Thickness of lines the contours are drawn with. If it is negative, the interiors of the contour are filled with the colour specified.

Now as we have learned about the functions, findContours, and drawContours let us run a simple code to apply these functions on an image:

This is the original image:

Image by Author
import cv2 as cv#read the image
img = cv.imread("D://medium_blogs//pattern1.jpg")
#convert the image to grayscale
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
#blur image to reduce the noise in the image while thresholding. #This smoothens the sharp edges in the image.
blur = cv.blur(gray, (10,10))
#Apply thresholding to the image
ret, thresh = cv.threshold(blur, 1, 255, cv.THRESH_OTSU)
#find the contours in the image
contours, heirarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
#draw the obtained contour lines(or the set of coordinates forming a line) on the original image
cv.drawContours(img, contours, -1, (0,255,0), 20)
#show the image
cv.namedWindow('Contours',cv.WINDOW_NORMAL)
cv.namedWindow('Thresh',cv.WINDOW_NORMAL)
cv.imshow('Contours', img)
cv.imshow('Thresh', thresh)
if cv.waitKey(0):
cv.destroyAllWindows()

The thresholded image and the original image with the contours drawn on it are as follows:

Thesholded image (left) and original image with contours drawn on it (right)

That’s it. This is how you find and draw contour lines on an image. Psst! You may as well try this on maps.

Thank You.

--

--