CV Contours and Shapes
A contour is a curve that follows the boundary of an object. Picture tracing the coastline of an island with a pen. The pen path is the contour, and the island is the object. Contours let software count objects, measure sizes, and name shapes such as circles and rectangles.
The Contour Pipeline
Contour tools work best on clean black-and-white images, so a short preparation chain comes first.
Photo -> Grayscale -> Blur -> Threshold -> Find contours -> Measure and label
Blurring removes noise, thresholding separates objects from the background, and contour finding traces each white region.
Finding Contours
import cv2
img = cv2.imread("shapes.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
_, binary = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY_INV)
contours, hierarchy = cv2.findContours(
binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print("Objects found:", len(contours))
cv2.drawContours(img, contours, -1, (0, 255, 0), 2)OpenCV expects white objects on a black background. The inverse threshold flag above flips dark shapes on paper into white shapes on black.
Measuring a Contour
Area and Perimeter
Area counts the pixels inside the outline. Perimeter measures the outline length.
area = cv2.contourArea(c)
perimeter = cv2.arcLength(c, True)Bounding Shapes
Bounding shapes wrap an object in the simplest box or circle that fits.
Straight box Rotated box Enclosing circle
+---------+ /\ .-"""-.
| /\ | / \ / /\ \
| / \ | / \ | / \ |
|/____\ | \ / \/____\ /
+---------+ \ / '-...-'
\/
x, y, w, h = cv2.boundingRect(c)
rect = cv2.minAreaRect(c)
(cx, cy), radius = cv2.minEnclosingCircle(c)Center Point
Image moments reveal the centroid, which is the balance point of the shape.
M = cv2.moments(c)
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])Naming Shapes With Corners
The function approxPolyDP simplifies a wiggly outline into a few straight edges. Counting the corners of the simplified outline names the shape.
Corners Likely Shape ------- ---------------------------------- 3 Triangle 4 Rectangle (square if width = height) 5 Pentagon 8 to 12+ Circle or oval
epsilon = 0.02 * cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, epsilon, True)
corners = len(approx)A smaller epsilon keeps more detail, and a larger epsilon simplifies more aggressively. A value near two percent of the perimeter suits most clean shapes.
Circularity Check
Many corners can describe a circle or a star. Circularity separates them with a single number.
circularity = 4 x pi x area / perimeter^2 Perfect circle -> 1.0 Square -> about 0.78 Thin rod -> close to 0
Convex Hull
The convex hull is the tightest rubber band stretched around a shape. Comparing the contour area with the hull area measures how many dents a shape has. Hand gesture tools use this idea to count raised fingers.
hull = cv2.convexHull(c)
solidity = cv2.contourArea(c) / cv2.contourArea(hull)Nested Shapes and Hierarchy
A donut has an outer outline and an inner hole outline. Retrieval modes control which outlines OpenCV returns.
RETR_EXTERNALreturns only outer outlinesRETR_LISTreturns every outline without family linksRETR_TREEreturns every outline plus parent and child links
Practical Tips
- Skip tiny contours by testing that area exceeds a minimum value
- Clean masks with morphological opening before tracing
- Draw results on a copy so the original stays untouched
- Sort contours by area to find the largest object quickly
Real-World Walkthrough: Counting Screws
A factory camera photographs a tray of screws on a white background. The pipeline blurs the image, applies an inverse threshold, and finds external contours. A filter drops any contour with an area below 200 pixels, which removes dust and shadows. The remaining contour count equals the number of screws. Bounding boxes and labels show operators exactly what the system found.
Tray photo -> Blur -> Inverse threshold -> Contours -> Area filter -> Count: 24 screws
Common Mistakes
- Passing a color image to
findContours, which expects a single-channel binary image - Tracing white paper rather than dark shapes because the threshold direction is reversed
- Ignoring noise, which creates hundreds of tiny contours
- Reading the return values in the wrong order, since older OpenCV versions return three values
Practice Exercise
Draw a triangle, a square, and a circle on white paper and photograph it. Run the pipeline and print the corner count for each contour. Label every shape with putText. Try tilting the paper and watch how the rotated box adapts while the straight box does not.
