Non-Maximum Suppression (NMS) - CNNs & Computer Vision
Implement Non-Maximum Suppression (NMS) in Python with NumPy. medium exercise with examples, hints, and instant feedback. No setup or signup required.
Non-Maximum Suppression (NMS)
What you'll build
Greedy Non-Maximum Suppression: from a set of scored boxes, keep the best box for each object and drop the overlapping duplicates.
Background
Detectors predict a box at every anchor or grid cell, so one object usually gets many near-identical boxes. NMS is the post-processing step (in Faster R-CNN, SSD, RetinaNet and YOLO up to v8) that keeps the highest-scoring box and removes boxes that overlap it too much.
Algorithm
- Sort the box indices by score, highest first.
- Take the first remaining index
iand append it tokeep. - Remove every remaining box whose IoU with box
iis greater thaniou_threshold. - Repeat steps 2 and 3 until no boxes remain, then return
keep.
IoU uses the xyxy convention of the IoU problem: intersection / (area_a + area_b - intersection), with the intersection width and height clamped at 0.
Inputs
boxes: array or list of shape(N, 4), each row[x1, y1, x2, y2](top-left, bottom-right).scores: array or list of shape(N,), one confidence per box.iou_threshold: float in[0, 1], default0.5.
Expected return format
A Python list of int indices into the original boxes, in the order they were kept (decreasing score).
Edge cases and conventions
- A box with IoU exactly equal to the threshold is kept; only
IoU > iou_thresholdsuppresses. - Boxes are compared with the box just kept, not only with the overall top box.
- Empty input returns
[]. - Scores are distinct in the tests; with ties, a stable sort keeps the lower index first.
- This is class-agnostic NMS: all boxes compete with each other.
Constraints
NumPy or plain Python; no torchvision.ops.nms. Vectorising the IoU of the kept box against all remaining boxes is a nice touch.
Follow-up
- What is the worst-case time complexity, and how do you make NMS class-aware with one call (the coordinate-offset trick)?
- How does Soft-NMS differ (decay the scores instead of deleting boxes), and when does it help?
Examples
Input: boxes = [[0, 0, 4, 4], [1, 1, 4, 4], [6, 6, 8, 8]], scores = [0.9, 0.75, 0.8], iou_threshold = 0.5 Output: [0, 2]
Keep box 0 (0.9). Box 1 overlaps it with IoU 9/16 = 0.5625 > 0.5, so it is removed; box 2 does not overlap and is kept.
Input: boxes = [[0, 0, 1, 1], [3, 3, 4, 4], [6, 6, 7, 7]], scores = [0.5, 0.9, 0.7] Output: [1, 2, 0]
Nothing overlaps, so every box is kept, in decreasing score order.
Practice in Python
import numpy as np
def nms(boxes, scores, iou_threshold=0.5):
"""
Greedy Non-Maximum Suppression (class-agnostic).
Args:
boxes: (N, 4) boxes in xyxy format [x1, y1, x2, y2]
scores: (N,) confidence score per box
iou_threshold: suppress boxes with IoU > iou_threshold (default 0.5)
Returns:
List of kept indices (ints), in decreasing score order
"""
# Your code here
pass
The interactive editor loads with Python and NumPy. Run your implementation against 8 tests, or use the progressive hints.