Skip to content

Instantly share code, notes, and snippets.

@CMCDragonkai
Last active July 3, 2021 18:10
Show Gist options
  • Save CMCDragonkai/1be3402e261d3c239a307a3346360506 to your computer and use it in GitHub Desktop.
Save CMCDragonkai/1be3402e261d3c239a307a3346360506 to your computer and use it in GitHub Desktop.
Non-Maximum Suppression for Bounding Boxes #python #algorithms
import numpy as np
def non_max_suppression(boxes, scores, threshold):
assert boxes.shape[0] == scores.shape[0]
# bottom-left origin
ys1 = boxes[:, 0]
xs1 = boxes[:, 1]
# top-right target
ys2 = boxes[:, 2]
xs2 = boxes[:, 3]
# box coordinate ranges are inclusive-inclusive
areas = (ys2 - ys1) * (xs2 - xs1)
scores_indexes = scores.argsort().tolist()
boxes_keep_index = []
while len(scores_indexes):
index = scores_indexes.pop()
boxes_keep_index.append(index)
if not len(scores_indexes):
break
ious = compute_iou(boxes[index], boxes[scores_indexes], areas[index],
areas[scores_indexes])
filtered_indexes = set((ious > threshold).nonzero()[0])
# if there are no more scores_index
# then we should pop it
scores_indexes = [
v for (i, v) in enumerate(scores_indexes)
if i not in filtered_indexes
]
return np.array(boxes_keep_index)
def compute_iou(box, boxes, box_area, boxes_area):
# this is the iou of the box against all other boxes
assert boxes.shape[0] == boxes_area.shape[0]
# get all the origin-ys
# push up all the lower origin-xs, while keeping the higher origin-xs
ys1 = np.maximum(box[0], boxes[:, 0])
# get all the origin-xs
# push right all the lower origin-xs, while keeping higher origin-xs
xs1 = np.maximum(box[1], boxes[:, 1])
# get all the target-ys
# pull down all the higher target-ys, while keeping lower origin-ys
ys2 = np.minimum(box[2], boxes[:, 2])
# get all the target-xs
# pull left all the higher target-xs, while keeping lower target-xs
xs2 = np.minimum(box[3], boxes[:, 3])
# each intersection area is calculated by the
# pulled target-x minus the pushed origin-x
# multiplying
# pulled target-y minus the pushed origin-y
# we ignore areas where the intersection side would be negative
# this is done by using maxing the side length by 0
intersections = np.maximum(ys2 - ys1, 0) * np.maximum(xs2 - xs1, 0)
# each union is then the box area
# added to each other box area minusing their intersection calculated above
unions = box_area + boxes_area - intersections
# element wise division
# if the intersection is 0, then their ratio is 0
ious = intersections / unions
return ious
@Odianosen25
Copy link

Hello @CMCDragonkai,

I am working on little project of mine, where I do some basic motion detection. As it leads me to some boundary boxes, with large and small ones, I thought about using the non-maximum suppression algorithm to reduce the boundary boxes to 1. So instead of having so many, I can "merge" close small ones to large ones do I have a single boxes.

Now as its just simple motion detection, I have no scores or something to pass to the function. Please could you let me know, on the possible way to use your code, without score and it will still work? I thought about arranging my contours based on size, which will now act as the score, but not sure its the way to go. Or is there a better way to do what I want?

Kind regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment