How to Find Contours in Python OpenCV
This tutorial will discuss finding contours present in an image using the findContours()
function of OpenCV in Python.
Use the findContours()
Function of OpenCV to Find Contours in an Image in Python
Contours are curves formed by joining the points along with the boundary of an object. In images, there are multiple objects present, and finding the contours of the image, we can get information about the shape of the objects as contours will highlight the boundaries of objects present in the image.
If we know the shapes of objects, we can easily guess which objects are present in the image. Contours are widely used to analyze shapes and detect and recognize objects.
We can use the findContours()
function of OpenCV to find the contours present in an image. We must use a binary image to find the contours for better accuracy.
If the given image is not binary, we can convert it to binary. For example, in the case of the colored image, we must convert the image to grayscale using the cvtColor()
function of OpenCV.
We can use the grayscale image inside the threshold() function of OpenCV to find the binary image. After that, we can use the findContours()
function and the binary image to find the contours.
If we want to show the contours, we must create a drawing and draw contours using the drawContours()
function. The drawing should be the same size as the given image to better visualize contours.
We can create a black color drawing of the same size as the given image using the zeros() function of the numpy
library.
For example, let’s read an image using the imread()
function, convert it into the binary scale, and then find the contours and show them. See the code below.
import cv2
import numpy as np
image = cv2.imread("cat.jpg")
cv2.imshow("Original Image", image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("Gray Image", gray)
_, binary = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
cv2.imshow("Binary image", binary)
contours, hierarchy = cv2.findContours(
binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
drawing = np.zeros((gray.shape[0], gray.shape[1], 3), dtype=np.uint8)
CountersImg = cv2.drawContours(drawing, contours, -1, (255, 255, 0), 3)
cv2.imshow("Contours", CountersImg)
cv2.waitKey(0)
Output:
The findContours()
function returns two output arguments. The first output argument contains the contour’s location points and coordinates in a list. The second output argument contains the hierarchy of the contours.
The first input of the findContours()
function is a binary or grayscale image. The second input argument is the retrieval mode used to define the hierarchy of contours.
We can pass different values inside the retrieval mode like cv2.RETR_LIST
to retrieve all contours, cv2.RETR_EXTERNAL
to retrieve external counters only, cv2.RETR_COMP
to retrieve contours in the 2-level hierarchy, and cv2.RETR_TREE
to retrieve contours in the full hierarchy. The third input argument of the findContours()
function is the approximate method used to store the boundary points.
The cv2.CHAIN_APPROX_NONE
method stores all the boundary points, but sometimes we don’t need all the boundary points. We can use the cv2.CHAIN_APPROX_SIMPLE
method to store the start and end points contours.
We can also define an offset that will shift each contour according to the offset in the findContours()
function. We can also show the contours on top of the given image using the drawContours()
function of OpenCV.
The first argument of the drawContours()
function is the image we want to draw the contours. The second argument is the contours, and the third is the contour index.
The third argument is the color of the contours, and it can be defined as an RGB triplet. The fourth argument is the thickness of contours which can be defined as an integer.
For example, let’s show the contour on top of the given image. See the code below.
import cv2
import numpy as np
image = cv2.imread("cat.jpg")
cv2.imshow("Original Image", image)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("Gray Image", gray)
_, binary = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
cv2.imshow("Binary image", binary)
contours, hierarchy = cv2.findContours(
binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
drawing = np.zeros((gray.shape[0], gray.shape[1], 3), dtype=np.uint8)
CountersImg = cv2.drawContours(drawing, contours, -1, (255, 255, 0), 3)
cv2.imshow("Contours", CountersImg)
ImgWithCounter = cv2.drawContours(image, contours, -1, (255, 255, 0), 3)
cv2.imshow("Image with counters", ImgWithCounter)
cv2.waitKey(0)
Output: