Non-Maximum Suppression with cv2.dnn.NMSBoxes: A Comprehensive Guide

In this article, we’ll explore the cv2.dnn.NMSBoxes function in OpenCV, an essential tool for reducing overlapping bounding boxes in object detection tasks. By the end of this article, you’ll have a clear understanding of the function, its parameters, and how to use it in your projects.

Understanding Non-Maximum Suppression (NMS)

Non-Maximum Suppression (NMS) is a post-processing technique used in object detection tasks to remove overlapping bounding boxes and retain only the most accurate ones. Object detection algorithms, such as YOLO, SSD, and Faster R-CNN, often produce multiple bounding boxes for the same object. NMS helps to refine the final output by keeping only the most relevant bounding boxes and discarding the rest.

cv2.dnn.NMSBoxes Function

The cv2.dnn.NMSBoxes function is an implementation of Non-Maximum Suppression in OpenCV. It takes a list of bounding boxes and their corresponding confidence scores as input and returns the indices of the bounding boxes that should be retained.

Function Syntax

import cv2

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)

Let’s examine the parameters of cv2.dnn.NMSBoxes:

  • bboxes: A list of bounding boxes, where each bounding box is represented as a tuple or list of four integers (x, y, width, height).
  • scores: A list of confidence scores corresponding to each bounding box in bboxes. The length of scores should be equal to the length of bboxes.
  • score_threshold: A float value representing the minimum confidence score required for a bounding box to be considered. Bounding boxes with confidence scores below this threshold are discarded.
  • nms_threshold: A float value representing the Intersection over Union (IoU) threshold for determining whether two bounding boxes overlap. If the IoU of two bounding boxes is greater than this threshold, the one with a lower confidence score is discarded.

The cv2.dnn.NMSBoxes function returns:

  • indices: A list of indices of the bounding boxes that should be retained. These indices correspond to the input bboxes and scores lists.

Example: Applying NMS to Bounding Boxes

Let’s demonstrate the use of the cv2.dnn.NMSBoxes function with an example. Suppose we have the following bounding boxes and confidence scores:

bboxes = [
(50, 50, 100, 100),
(55, 55, 100, 100),
(200, 200, 100, 100),
(205, 205, 100, 100)
]

scores = [0.9, 0.8, 0.95, 0.85]

In this example, we have four bounding boxes with their corresponding confidence scores. We can see that the first two bounding boxes and the last two bounding boxes have a significant overlap. We’ll apply NMS using cv2.dnn.NMSBoxes to refine the bounding boxes:

score_threshold = 0.5
nms_threshold = 0.3

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)

We’ve set the score_threshold to 0.5 and the nms_threshold to 0.3. These values can be adjusted depending on the specific requirements of your application.

The resulting indices list will contain the indices of the bounding boxes that should be retained. In this case, the indices list will be [[0], [2]], which means that we should keep the first and third bounding boxes:

filtered_bboxes = [bboxes[i[0]] for i in indices]
filtered_scores = [scores[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)
print("Filtered scores:", filtered_scores)

Running the code above will output:

Filtered bounding boxes: [(50, 50, 100, 100), (200, 200, 100, 100)]
Filtered scores: [0.9, 0.95]

The cv2.dnn.NMSBoxes function has successfully removed the overlapping bounding boxes and retained only the most accurate ones.

Applications of Non-Maximum Suppression

Non-Maximum Suppression is widely used in object detection tasks to refine the output of detection algorithms. Here are some examples of where NMS is applied:

  • Object detection algorithms: NMS is a standard post-processing step in object detection algorithms like YOLO, SSD, and Faster R-CNN. It helps remove overlapping bounding boxes and retain the most accurate ones.
  • Custom object detectors: If you’re building a custom object detector, applying NMS as a post-processing step can improve the detection results by removing redundant bounding boxes.
  • Image segmentation: In some cases, NMS can be used to refine the output of image segmentation tasks by removing overlapping segments and retaining the most accurate ones.

More Examples

Example 1: Simple Overlapping Boxes

Let’s start with a simple example of two overlapping boxes:

bboxes = [
(20, 20, 50, 50),
(40, 40, 50, 50)
]

scores = [0.8, 0.7]

score_threshold = 0.6
nms_threshold = 0.3

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(20, 20, 50, 50)]

Example 2: Multiple Objects with Overlapping Boxes

In this example, we have multiple objects, and some of their bounding boxes overlap:

bboxes = [
(10, 10, 30, 30),
(15, 15, 30, 30),
(100, 100, 30, 30),
(110, 100, 30, 30)
]

scores = [0.9, 0.8, 0.85, 0.95]

score_threshold = 0.7
nms_threshold = 0.2

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(10, 10, 30, 30), (110, 100, 30, 30)]

Example 3: Boxes with Different Aspect Ratios

In this example, we have bounding boxes with different aspect ratios:

bboxes = [
(20, 20, 40, 60),
(25, 30, 45, 55),
(150, 150, 70, 30),
(155, 145, 65, 35)
]

scores = [0.92, 0.85, 0.95, 0.88]

score_threshold = 0.8
nms_threshold = 0.4

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(20, 20, 40, 60), (150, 150, 70, 30)]

Example 4: Boxes with Different Confidence Scores

In this example, we have bounding boxes with different confidence scores:

bboxes = [
(50, 50, 100, 100),
(60, 60, 100, 100),
(200, 200, 100, 100),
(210, 210, 100, 100)
]

scores = [0.99, 0.65, 0.95, 0.55]

score_threshold = 0.6
nms_threshold = 0.3

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(50, 50, 100, 100), (200, 200, 100, 100)]

Example 5: Densely Overlapping Boxes

In this example, we have densely overlapping boxes:

bboxes = [
(30, 30, 50, 50),
(32, 32, 50, 50),
(34, 34, 50, 50),
(36, 36, 50, 50)
]

scores = [0.9, 0.85, 0.88, 0.92]

score_threshold = 0.8
nms_threshold = 0.1

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(36, 36, 50, 50)]

Example 6: Non-overlapping Boxes

In this example, we have non-overlapping boxes:

bboxes = [
(10, 10, 30, 30),
(50, 50, 30, 30),
(90, 90, 30, 30),
(130, 130, 30, 30)
]

scores = [0.9, 0.8, 0.85, 0.95]

score_threshold = 0.7
nms_threshold = 0.2

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(10, 10, 30, 30), (50, 50, 30, 30), (90, 90, 30, 30), (130, 130, 30, 30)]

Example 7: Boxes with Varying Confidence Thresholds

In this example, we have boxes with varying confidence thresholds:

bboxes = [
(20, 20, 40, 60),
(30, 30, 45, 55),
(150, 150, 70, 30),
(160, 140, 65, 35)
]

scores = [0.6, 0.4, 0.9, 0.7]

score_threshold = 0.5
nms_threshold = 0.4

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(20, 20, 40, 60), (150, 150, 70, 30)]

Example 8: Boxes with Varying NMS Threshold s

In this example, we have boxes with varying NMS thresholds:

bboxes = [
(10, 10, 30, 30),
(20, 20, 30, 30),
(100, 100, 30, 30),
(105, 105, 30, 30)
]

scores = [0.9, 0.8, 0.85, 0.95]

score_threshold = 0.7
nms_threshold = 0.5

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(10, 10, 30, 30), (105, 105, 30, 30)]

Example 9: Boxes with Identical Confidence Scores

In this example, we have boxes with identical confidence scores:

bboxes = [
(50, 50, 100, 100),
(55, 55, 100, 100),
(200, 200, 100, 100),
(205, 205, 100, 100)
]

scores = [0.9, 0.9, 0.9, 0.9]

score_threshold = 0.8
nms_threshold = 0.3

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(50, 50, 100, 100), (200, 200, 100, 100)]

Example 10: Boxes with High NMS Threshold

In this example, we have boxes with a high NMS threshold:

bboxes = [
(30, 30, 50, 50),
(40, 40, 50, 50),
(100, 100, 50, 50),
(105, 105, 50, 50)
]

scores = [0.9, 0.8, 0.85, 0.95]

score_threshold = 0.7
nms_threshold = 0.7

indices = cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold)
filtered_bboxes = [bboxes[i[0]] for i in indices]

print("Filtered bounding boxes:", filtered_bboxes)

The output should be:

Filtered bounding boxes: [(30, 30, 50, 50), (105, 105, 50, 50)]

Conclusion

In this comprehensive guide, we explored the cv2.dnn.NMSBoxes function in OpenCV, a crucial tool for refining the output of object detection tasks. We discussed the function’s parameters and provided an example to demonstrate how to use it effectively. By understanding the Non-Maximum Suppression technique and its applications, you can now leverage cv2.dnn.NMSBoxes in your computer vision projects.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.