Edges and contours
Sobel, Canny and findContours: how to find, count and measure outlines without training a single model.
The idea
Where an image jumps from light to dark there is an edge. A computer finds those places by subtracting neighbouring pixels: a small difference means a surface, a large one means an edge.
What it is good for
- Counting parts on a conveyor.
- Checking whether a component has the right outline.
- Finding a document in a photo and rectifying it.
- Measuring lines, circles and rectangles.
Canny with automatic thresholds
import cv2, numpy as np
def auto_canny(grey, sigma=0.33):
v = float(np.median(grey))
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
return cv2.Canny(grey, lower, upper)
img = cv2.imread("parts.jpg")
grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
grey = cv2.GaussianBlur(grey, (5, 5), 0) # without this: noise edges
edges = auto_canny(grey)
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
area = cv2.contourArea(c)
if area < 800:
continue
perim = cv2.arcLength(c, True)
corners = cv2.approxPolyDP(c, 0.02 * perim, True)
circ = 4 * np.pi * area / (perim ** 2) # 1.0 = perfect circle
shape = "circle" if circ > 0.85 else f"{len(corners)}-gon"
print(f"area {area:8.0f} circularity {circ:.2f} -> {shape}")The contour features you need
| Feature | Function | Used for |
|---|---|---|
| Area | contourArea | Filtering, size checks |
| Perimeter | arcLength | Circularity, smoothness |
| Bounding box | boundingRect | Cropping, position |
| Rotated box | minAreaRect | Determining angle |
| Convex hull | convexHull | Spotting missing pieces |
| Moments | moments | Computing the centroid |
The gradient
Canny's four steps
- 01
Smooth
Gaussian filter, so that noise does not create gradients.
- 02
Compute the gradient
Sobel in both directions, then magnitude and direction.
- 03
Non-maximum suppression
Only the strongest point across the edge direction survives, which makes the lines one pixel thin.
- 04
Hysteresis
Points above the upper threshold are certainly edges. Points between the two thresholds only if they connect to a certain edge.
The fourth step is the real gain: it joins broken lines while suppressing isolated noise points, which a single threshold cannot do simultaneously.
Measuring with a reference
The "same plane" restriction is decisive. Objects closer to the camera appear larger, and without rectification the measurement is wrong by the perspective factor. With a perpendicular shot and a reference next to the part, accuracies below one percent are attainable; with an angled shot and no rectification, ten percent errors are easy.
Related courses and sources
OpenCV tutorials
The official guides to filters, edges, features and calibration, each with runnable Python code.
For anyone writing image processing themselves; every example runs.