Bounding Boxes and Overlap
Knowing that a seed appears in a photograph does not tell us where it is. Rectangles give us a location to predict, and overlap gives us a way to compare that prediction with a labelled target.
13 sections · 4 questions · 2 coding challenges
The arrow keys move between sections too.
Comparing Where Systems Said an Object Was
BOTIE
That challenge did not invent rectangles or overlap. It illustrates why detection needs a localisation criterion in addition to a class score. We will use continuous rectangle boundaries; always check a dataset's coordinate convention before applying the same arithmetic to its annotations.
Sources for this history
The Model Found a Seed. Where Should Botie Look?
An image classifier can tell Botie that a photograph contains a seed. If he needs to inspect that seed, an answer about the whole photograph is not enough. He needs a location, and possibly several locations for several objects.
One way to describe a location is a rectangle around the object. We can supply labelled rectangles during training and ask a detector to predict them. Before discussing a whole detector, let's work out how to represent a rectangle and judge whether two rectangles refer to roughly the same region.
The rectangles use continuous boundary coordinates on an illustrative image.
Step 1 of 3
Describe the proposed region
A rectangle needs a left, top, right, and bottom boundary. Here we use ordinary plotting axes for the geometry; array row order is a separate convention.
Vertical: Vertical position
Horizontal: Horizontal position
Step 2 of 3
Find the shared rectangle
A second prediction starts farther to the right. Only the middle strip belongs to both boxes.
Vertical: Vertical position
Horizontal: Horizontal position
Step 3 of 3
Compare shared area with covered area
The union counts positions covered by either box, once each. Intersection divided by union penalises both missed area and extra area.
First box area: 16 Second box area: 16 Shared area: 8 Union = 16 + 16 − 8 = 24 Intersection over union = 8 / 24 ≈ 0.3333
Overlap needs a common denominator
Subtracting the intersection prevents the union from counting shared area twice. The ratio compares shared coverage with all covered area.
How much do the two rectangles actually share?
Move an edge of the predicted box. Compare the shared area with the total area covered by either rectangle, including the point where the boxes stop overlapping.
BOTIE
Intersection over union
0.3333
Follow the operations
1. Predicted rectangle
- 00
- 10
- 24
- 34
2. Labelled rectangle
- 02
- 10
- 26
- 34
3. Measure two rectangles' intersection
8
4. Measure a rectangle's area
16
5. Measure a rectangle's area
16
6. Add
32
7. Subtract
24
8. Divide
0.3333
9. Result
0.3333
All rectangles must have positive width and height. This calculation is one pairwise localisation measure, not a complete detection evaluation.
1. Fix the Coordinate Convention
We store each rectangle as x-min, y-min, x-max, y-max. The first two entries identify its upper-left boundary in image coordinates; the last two identify its lower-right boundary. The right and bottom boundaries are exclusive.
A valid rectangle has positive width and height. These boundary coordinates may be floating-point values. Do not add one when calculating their lengths. An inclusive integer-pixel annotation format uses different bookkeeping and should be converted deliberately.
box = [1, 2, 5, 6]
width = 5 - 1 = 4
height = 6 - 2 = 4
area = 4 × 4 = 16Some models instead output centre, width, and height. Translate representations before comparing them.
2. Find the Region Shared by Both Rectangles
To find the shared part of two rectangles, choose the farther-right left boundary and the lower top boundary. For the other side, choose the nearer-left right boundary and the higher bottom boundary. Those choices give the intersection limits.
A negative width or height means there is no overlap in that direction. Set that length to zero before calculating area. Otherwise two negative lengths could multiply to a positive number and report an overlap that does not exist.
intersection_width = max(0, min(right_A, right_B) - max(left_A, left_B))
intersection_height = max(0, min(bottom_A, bottom_B) - max(top_A, top_B))
intersection_area = intersection_width × intersection_heightRectangles that only touch along an edge have zero intersection area under this convention.
3. Count the Union Without Counting the Overlap Twice
Adding the two areas counts their shared region twice. Subtract the intersection once to obtain the union. Intersection over union, or IoU, is the shared area divided by that combined covered area.
For valid positive-area rectangles, IoU lies between zero and one. Identical boxes score one. Disjoint boxes score zero. A small box fully inside a large one does not score one because the extra area still belongs to the union.
A = [0,0,4,4], B = [2,0,6,4]
intersection = 2 × 4 = 8
union = 16 + 16 - 8 = 24
IoU = 8 / 24 = 1 / 3This ratio is unitless, provided both boxes use the same coordinate system.
Calculate the overlap directly
Clamp both overlap lengths before calculating the shared area.
import numpy as np
a = np.array([0.,0.,4.,4.])
b = np.array([2.,0.,6.,4.])
def iou(a, b):
overlap = np.maximum(0, np.minimum(a[2:], b[2:]) - np.maximum(a[:2], b[:2]))
intersection = np.prod(overlap)
union = np.prod(a[2:] - a[:2]) + np.prod(b[2:] - b[:2]) - intersection
return intersection / union
print(f'{iou(a, b):.4f}')0.3333Neither a classification score nor the distance between box centres gives this area-overlap measure.
4. Keep Localisation Separate From Classification
A detector often predicts a class, a score, and a rectangle for each candidate object. A high class score does not guarantee that the rectangle is well placed. Conversely, a well-placed rectangle with the wrong class is still a wrong detection.
Training and evaluation need labels appropriate to the task. A collection containing only whole-image class labels does not automatically supply the object coordinates required by a supervised box detector.
A bounding box also differs from a segmentation mask: it can include background around an irregularly shaped object.
5. Interpret the Evaluation Rule, Not Just One IoU
An evaluation protocol specifies an overlap threshold, class matching, and how predictions are matched to annotated objects. Duplicate predictions cannot all count as separate correct detections of one object.
An identical coordinate error can hurt a small object more than a large one. Inspect examples across object sizes and read the protocol rather than treating one IoU threshold as universally correct.
Botie's workshop computes IoU for one pair. The next lesson uses overlap to handle duplicate candidates; a full detection metric also needs matching across an entire labelled dataset.
6. A Detection Needs a Class, a Location and a Match
To score a detector, sort predictions by confidence under the evaluation protocol and match eligible predictions to labelled objects. One labelled seed should not become several true positives because several boxes cover it.
Class agreement and sufficient overlap are both necessary. Keep unmatched predictions as false positives and unmatched labels as misses. Average precision summarises a ranking under a particular matching and overlap protocol; one good IoU calculation is only a component of that procedure.
7. Resize Coordinates Along with the Photograph
If width and height change by different factors, x coordinates and y coordinates need different multipliers. The box order must be known before applying them. A detector output in resized coordinates must be mapped back before displaying it on the original image.
Letterboxing introduces padding offsets as well as scaling. Keep both transformations, and undo them in reverse order. Clipping to image bounds is a separate policy and can turn a box into an empty one.
Resize a box with unequal scale factors
The image changes from width eight and height six to width four and height six.
import numpy as np
box = np.array([2., 1., 6., 5.])
scale = np.array([.5, 1., .5, 1.])
resized = box * scale
print(resized.tolist())
print((resized / scale).tolist())[1.0, 1.0, 3.0, 5.0]
[2.0, 1.0, 6.0, 5.0]The y coordinates stay fixed because height did not change. Applying one scale to all four values would move the box vertically.
Check yourself
Questions on Parts 1 to 7
Question 1 of 4
What is the area?
Use the information below.
Box boundaries: [1,2,5,6]
Right and bottom boundaries are exclusive.Try it with Botie
Build with Botie
Write and run Python