Visualising detections, boxes and debug info on frames is how you check that a vision pipeline works.
OpenCV's drawing functions modify the image in place and take coordinates as (x, y) tuples of ints:
cv2.line(img, pt1, pt2, color, thickness)cv2.rectangle(img, top_left, bottom_right, color, thickness)cv2.circle(img, center, radius, color, thickness)cv2.polylines(img, [pts], isClosed, color, thickness)whereptsis an int32 array of shape(n, 1, 2)or(n, 2)cv2.putText(img, text, origin, font, scale, color, thickness, lineType); the origin is the bottom-left of the text
Colours are BGR tuples, (0, 0, 255) is red. A thickness of -1 (or cv2.FILLED) fills the shape. Pass lineType=cv2.LINE_AA for anti-aliased, smoother edges.
Coordinates must be integers. Detection boxes often come as floats, so convert with int(...) or np.round(...).astype(int) before drawing; recent versions raise an error on floats.
Because drawing changes the array, draw on img.copy() when you still need the clean image, for example to feed it to the next stage of a pipeline.
cv2.getTextSize(text, font, scale, thickness) returns the text's width and height plus the baseline, which lets you draw a filled background box behind a label so it stays readable on any image. Only a small set of Hershey fonts is built in, without Unicode; for other scripts, render text with Pillow.
Example
import cv2
import numpy as np
canvas = np.zeros((200, 300, 3), np.uint8)
cv2.rectangle(canvas, (20, 30), (140, 120), (0, 255, 0), 2) # green box
cv2.circle(canvas, (220, 75), 40, (0, 0, 255), -1) # filled red
cv2.line(canvas, (0, 199), (299, 150), (255, 255, 255), 1, cv2.LINE_AA)
pts = np.array([[160, 180], [200, 140], [240, 180]], np.int32)
cv2.polylines(canvas, [pts], True, (255, 0, 0), 2) # blue triangle
label = "cat 0.93"
font = cv2.FONT_HERSHEY_SIMPLEX
(tw, th), base = cv2.getTextSize(label, font, 0.5, 1)
cv2.rectangle(canvas, (20, 30 - th - base), (20 + tw, 30), (0, 255, 0), -1)
cv2.putText(canvas, label, (20, 30 - base), font, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
print(canvas[75, 220]) # [ 0 0 255] inside the red circle
print(canvas[30, 80]) # [ 0 255 0] on the box edgeRemember
- Drawing functions modify the image in place; copy first if needed
- Points are integer (x, y) tuples, colours are BGR
- thickness=-1 fills; LINE_AA smooths edges
- putText's origin is the text's bottom-left corner
Watch out for
- Passing float coordinates from a detector straight into cv2.rectangle.