Drawing Shapes and Text
The cv2 drawing functions paint directly onto an image array: lines, circles, ellipses, rectangles, polylines, filled polygons, and text. They are the rendering half of every detection demo - the box around a face, the circle on a detected point, the label with the class name - and they share one convention: coordinates are (x, y) with the origin at the top-left, and colors are BGR tuples.
Lines, Rectangles, Circles
import cv2
import numpy as np
img = np.zeros((240, 320, 3), dtype="uint8")
# line(point1, point2, color, thickness)
cv2.line(img, (0, 0), (319, 239), (255, 0, 0), 2)
# rectangle(top-left, bottom-right, color, thickness)
cv2.rectangle(img, (40, 40), (160, 140), (0, 255, 0), 2)
# circle(center, radius, color, thickness) - -1 fills
cv2.circle(img, (230, 80), 40, (0, 0, 255), 2)
cv2.circle(img, (230, 180), 25, (255, 255, 0), -1)
# ellipse(center, (major, minor) axes, angle, startAngle, endAngle, color, thickness)
cv2.ellipse(img, (80, 190), (50, 25), 30, 0, 360, (255, 0, 255), 2)
cv2.imwrite("shapes.png", img)
Every shape call takes a thickness - positive for an outline, -1 (with LINE_8) for a filled shape. Colors are (B, G, R) integers; a single-channel (grayscale) image takes a plain int. The coordinate system is the one to internalize: x grows right, y grows down, so "top-left" is (x_small, y_small) and a rectangle is specified by its two opposite corners.
Polylines and Polygons
import cv2
import numpy as np
img = np.zeros((240, 320, 3), dtype="uint8")
pts = np.array([[50, 50], [150, 30], [180, 120], [90, 150]], np.int32)
pts = pts.reshape((-1, 1, 2)) # OpenCV wants shape (N, 1, 2)
# open polyline
cv2.polylines(img, [pts], False, (0, 255, 255), 2)
# closed filled polygon
pts2 = np.array([[200, 60], [280, 90], [260, 180], [210, 160]], np.int32)
cv2.fillPoly(img, [pts2], (0, 200, 100))
# isPointInPolygon: the query that drives "is this pixel inside?"
from cv2 import pointPolygonTest
inside = pointPolygonTest(pts2.reshape((-1, 2)), (240, 120), False)
print(inside > 0) # True - the test point is inside
polylines takes a list of point arrays (so one call can draw several separate polylines), and the points must be np.int32 with shape (N, 1, 2) - the reshape is the part everyone gets wrong the first time. fillPoly is the closed, filled version. pointPolygonTest answers the reverse question - is this point inside the polygon - with a signed distance when you ask for it, which is the basis of custom mask generation.
Text
import cv2
import numpy as np
img = np.full((120, 320, 3), 40, dtype="uint8")
# putText(image, text, org, font, scale, color, thickness, lineType)
cv2.putText(img, "OpenCV", (20, 40),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 2)
cv2.putText(img, "det: face 0.92", (20, 80),
cv2.FONT_HERSHEY_DUPLEX, 0.7, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imwrite("text.png", img)
putText places text with its origin at the bottom-left of the text box (unlike the shapes, where the point is a corner of the geometry). The font flags (FONT_HERSHEY_SIMPLEX, FONT_HERSHEY_DUPLEX, ...) select a built-in bitmap font, scale is the size, and LINE_AA gives antialiased edges. For richer typography (custom fonts, wrapping) the pattern is to render with PIL or Qt and paste the result in - OpenCV's text is for labels, not documents.
The Annotation Idiom
import cv2
img = cv2.imread("photo.jpg")
# the detection box + label, the pattern of every demo
x, y, w, h = 120, 80, 200, 240
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
label = "face 0.94"
cv2.putText(img, label, (x, y - 8),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imwrite("annotated.jpg", img)
This rectangle-plus-label above the box is the universal annotation shape - every detector in the tutorial (contours, faces, DNN objects) renders its results this way. Keep the label offset above the box's top edge, use LINE_AA for readability at small sizes, and pick a color per class so multiple detections are distinguishable at a glance.
Summary
Draw with the cv2 shape functions - line, rectangle, circle, ellipse, polylines, fillPoly - remembering the top-left origin, BGR colors, thickness (-1 to fill), and the (N, 1, 2) int32 point shape for polygons. Place text with putText (bottom-left origin, built-in fonts, LINE_AA), and adopt the rectangle-plus-label idiom as the standard way to render any detection. Drawing is the output format of computer vision: the algorithm finds, and these calls make the finding visible.