Last active
July 3, 2021 18:10
-
-
Save CMCDragonkai/1be3402e261d3c239a307a3346360506 to your computer and use it in GitHub Desktop.
Non-Maximum Suppression for Bounding Boxes #python #algorithms
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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