Skip to content

Instantly share code, notes, and snippets.

@fivejjs
Forked from AruniRC/bbox_iou_evaluation.py
Created October 5, 2023 09:37
Show Gist options
  • Save fivejjs/c76fe74c682d82d727d9ee09568f74ec to your computer and use it in GitHub Desktop.
Save fivejjs/c76fe74c682d82d727d9ee09568f74ec to your computer and use it in GitHub Desktop.
Object detector util: match a set of detected bounding boxes and a set of ground-truth bounding boxes
from __future__ import division
import scipy.optimize
import numpy as np
def bbox_iou(boxA, boxB):
# https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/
# ^^ corrected.
# Determine the (x, y)-coordinates of the intersection rectangle
xA = max(boxA[0], boxB[0])
yA = max(boxA[1], boxB[1])
xB = min(boxA[2], boxB[2])
yB = min(boxA[3], boxB[3])
interW = xB - xA + 1
interH = yB - yA + 1
# Correction: reject non-overlapping boxes
if interW <=0 or interH <=0 :
return -1.0
interArea = interW * interH
boxAArea = (boxA[2] - boxA[0] + 1) * (boxA[3] - boxA[1] + 1)
boxBArea = (boxB[2] - boxB[0] + 1) * (boxB[3] - boxB[1] + 1)
iou = interArea / float(boxAArea + boxBArea - interArea)
return iou
def match_bboxes(bbox_gt, bbox_pred, IOU_THRESH=0.5):
'''
Given sets of true and predicted bounding-boxes,
determine the best possible match.
Parameters
----------
bbox_gt, bbox_pred : N1x4 and N2x4 np array of bboxes [x1,y1,x2,y2].
The number of bboxes, N1 and N2, need not be the same.
Returns
-------
(idxs_true, idxs_pred, ious, labels)
idxs_true, idxs_pred : indices into gt and pred for matches
ious : corresponding IOU value of each match
labels: vector of 0/1 values for the list of detections
'''
n_true = bbox_gt.shape[0]
n_pred = bbox_pred.shape[0]
MAX_DIST = 1.0
MIN_IOU = 0.0
# NUM_GT x NUM_PRED
iou_matrix = np.zeros((n_true, n_pred))
for i in range(n_true):
for j in range(n_pred):
iou_matrix[i, j] = bbox_iou(bbox_gt[i,:], bbox_pred[j,:])
if n_pred > n_true:
# there are more predictions than ground-truth - add dummy rows
diff = n_pred - n_true
iou_matrix = np.concatenate( (iou_matrix,
np.full((diff, n_pred), MIN_IOU)),
axis=0)
if n_true > n_pred:
# more ground-truth than predictions - add dummy columns
diff = n_true - n_pred
iou_matrix = np.concatenate( (iou_matrix,
np.full((n_true, diff), MIN_IOU)),
axis=1)
# call the Hungarian matching
idxs_true, idxs_pred = scipy.optimize.linear_sum_assignment(1 - iou_matrix)
if (not idxs_true.size) or (not idxs_pred.size):
ious = np.array([])
else:
ious = iou_matrix[idxs_true, idxs_pred]
# remove dummy assignments
sel_pred = idxs_pred<n_pred
idx_pred_actual = idxs_pred[sel_pred]
idx_gt_actual = idxs_true[sel_pred]
ious_actual = iou_matrix[idx_gt_actual, idx_pred_actual]
sel_valid = (ious_actual > IOU_THRESH)
label = sel_valid.astype(int)
return idx_gt_actual[sel_valid], idx_pred_actual[sel_valid], ious_actual[sel_valid], label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment