Contours and Bounding Boxes
Intuition
After thresholding, each white blob is an object. A contour is the list of points along a blob's boundary. From it you get a bounding box (where is it?), an area (how big?) and a centroid (where is its centre of mass?) — enough to count, locate and filter objects.
Precise explanation
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
x, y, w, h = cv2.boundingRect(c) # top-left corner and size, in pixels
area = cv2.contourArea(c) # area of the polygon through the boundary pixels
m = cv2.moments(c)
cx, cy = m["m10"] / m["m00"], m["m01"] / m["m00"] # centroid (needs m00 > 0)
- The mask must be single-channel
uint8; any non-zero pixel is foreground. RETR_EXTERNALreturns only outer boundaries, so holes inside objects are ignored;RETR_TREEreturns the full nesting.CHAIN_APPROX_SIMPLEstores only the corners of straight runs (a rectangle has 4 points).contourAreameasures the polygon through boundary pixel centres, so a filled w × h rectangle has area (w − 1)(h − 1), not w·h. For pixel counts use connected components (later in this topic).- In OpenCV 4.x
findContoursreturns two values.
Worked example
A filled rectangle covering columns 4–11 and rows 5–9 gives boundingRect (4, 5, 8, 5),
contourArea 7 × 4 = 28 and centroid (7.5, 7.0).
Common mistakes
- Passing a greyscale photo instead of a binary mask.
- Expecting
contourAreato equal the number of pixels. - Dividing by
m00for a degenerate contour (a single pixel or line) without checking for zero.
Why this matters
Contours locate documents in photos, count parts on a conveyor belt and produce the boxes that detection post-processing (IoU and NMS, later in this topic) works with. The document-scanner project idea after this step is built on them.
References
- Contours: Getting Started (OpenCV 4.13) — OpenCV team (
S120) - Structural Analysis and Shape Descriptors (OpenCV 4.13) — OpenCV team (
S121)