Image Contours with OpenCV

Finding and Drawing Contours in OpenCV: A Comprehensive Tutorial

Updated March 21, 2023


Hey! If you love Computer Vision and AI, let's connect on Twitter or LinkedIn. I talk about this stuff all the time!

Hello, computer vision enthusiasts! In this captivating tutorial, we’ll explore the intriguing process of finding and drawing contours in OpenCV. We’ll delve into the underlying theory, share multiple code examples, and ensure that even beginners can grasp the concepts. So, buckle up and get ready for an exciting journey into the world of contours!

What are contours, and why do we need them?

Contours are continuous curves that form the boundaries of objects in an image. They help us represent and understand the shapes of objects, enabling us to perform tasks like object detection, shape analysis, and object recognition.

Finding contours is a critical step in many computer vision applications, such as counting objects in an image, extracting regions of interest, or estimating the orientation of an object. By the end of this tutorial, you’ll be equipped with the knowledge and tools to tackle these tasks with ease.

Contour detection: the fundamentals

Before we dive into contour detection, let’s discuss a few key concepts:

Binary image: Contour detection typically requires a binary image as input, where the objects are represented by white pixels (foreground) and the background by black pixels. This simplification makes the contour detection process more robust and efficient.

Edge detection: Contour detection is closely related to edge detection, as both techniques aim to identify boundaries between objects and the background. However, contour detection focuses on capturing closed boundaries, while edge detection highlights all edges, including those within objects.

Now that we have a basic understanding of contours and their importance, let’s explore how OpenCV handles contour detection.

Contour detection in OpenCV

OpenCV provides the findContours() function to detect contours in a binary image. The function identifies contours by analyzing the image’s pixel intensity, connecting adjacent white pixels to form a continuous boundary.

The findContours() function accepts three arguments:

  1. Input image: A binary image, typically obtained by applying a threshold or edge detection algorithm to the original image.

  2. Contour retrieval mode: Specifies the hierarchy relationship between contours (e.g., nested or connected contours). Common modes include cv2.RETR_EXTERNAL (retrieves only the extreme outer contours) and cv2.RETR_TREE (retrieves all contours and reconstructs the full hierarchy).

  3. Contour approximation method: Determines how the contours are approximated. The most common methods are cv2.CHAIN_APPROX_SIMPLE (compresses horizontal, diagonal, and vertical segments and leaves only their end points) and cv2.CHAIN_APPROX_NONE (stores all the contour points).

The function returns two values:

  1. Contours: A list of contours, where each contour is represented as a set of points.

  2. Hierarchy: A list containing information about the hierarchy of the contours, if the retrieval mode specified a hierarchical relationship. Drawing contours

Once we have detected the contours, we can draw them on the original image using OpenCV’s drawContours() function. This function accepts four arguments:

  1. Input image: The image on which to draw the contours.

  2. Contours: A list of contours obtained from the findContours() function.

  3. Contour index: The index of the contour to draw. To draw all contours, set this to -1.

  4. Color: The color of the contours, specified as a tuple in BGR format.

A complete example: finding and drawing contours

Now, let’s put everything together with a complete example that demonstrates how to find and draw contours in an image:

import cv2

# Load the image
image = cv2.imread('example_image.jpg', cv2.IMREAD_GRAYSCALE)
Apply a binary threshold to the image
_, threshold = cv2.threshold(image, 128, 255, cv2.THRESH_BINARY)

#Find contours in the binary image
contours, hierarchy = cv2.findContours(threshold, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

#Create a copy of the original image for drawing contours
result = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)

#Draw the contours on the result image
cv2.drawContours(result, contours, -1, (0, 255, 0), 2)

#Display the original, thresholded, and result images
cv2.imshow('Original Image', image)
cv2.imshow('Threshold Image', threshold)
cv2.imshow('Contours', result)

cv2.waitKey(0)
cv2.destroyAllWindows()

In this example, we first load a grayscale image and apply a binary threshold to create a binary image. We then find the contours in the binary image using the findContours() function and draw them on a copy of the original image using the drawContours() function. Finally, we display the original, thresholded, and result images to visualize the contour detection process.

Advanced contour operations

Now that you’ve learned the basics of contour detection and drawing, let’s explore some advanced contour operations that can help you extract more information from the contours:

  1. Contour area: You can calculate the area of a contour using OpenCV’s contourArea() function. This is useful for filtering contours based on their size or estimating the size of objects in an image.
area = cv2.contourArea(contour)
  1. Contour perimeter: You can calculate the perimeter (or length) of a contour using OpenCV’s arcLength() function. This can help you differentiate between objects with similar shapes but different sizes.
perimeter = cv2.arcLength(contour, closed=True)
  1. Bounding rectangle: You can compute the bounding rectangle of a contour using OpenCV’s boundingRect() function. This is helpful for cropping regions of interest, calculating aspect ratios, or estimating object orientations.
x, y, w, h = cv2.boundingRect(contour)
  1. Minimum enclosing circle: You can compute the minimum enclosing circle of a contour using OpenCV’s minEnclosingCircle() function. This can be useful for detecting circular objects or estimating the size of irregularly shaped objects.
(x, y), radius = cv2.minEnclosingCircle(contour)

Wrapping up

Congratulations! You’ve successfully ventured through the fascinating world of finding and drawing contours in OpenCV. We’ve covered the fundamentals of contour detection, explored how to find and draw contours using OpenCV, and even touched on some advanced contour operations.

Remember, practice is the key to mastering any skill. So, keep experimenting with different images, contour operations, and computer vision applications. Before you know it, you’ll be a contour wizard, ready to tackle any challenge that comes your way. Happy coding!