I want to compute a "distance" matrix, similarly to scipy.spatial.distance.cdist
, but using the intersection over union (IoU) between "bounding boxes" (4-dimensional vectors), instead of a typical distance metric (like the Euclidean distance).
For example, let's suppose that we have two collections of bounding boxes, such as
import numpy as np
A_bboxes = np.array([[0, 0, 10, 10], [5, 5, 15, 15]])
array([[ 0, 0, 10, 10],
[ 5, 5, 15, 15]])
B_bboxes = np.array([[1, 1, 11, 11], [4, 4, 13, 13], [9, 9, 13, 13]])
array([[ 1, 1, 11, 11],
[ 4, 4, 13, 13],
[ 9, 9, 13, 13]])
I want to compute a matrix J
, whose {i,j}-th element will hold the IoU between the i-th bbox of A_bboxes
and the the j-th bbox of B_bboxes
.
Given the following function for computing the IoU between two given bboxes:
def compute_iou(bbox_a, bbox_b):
xA = max(bbox_a[0], bbox_b[0])
yA = max(bbox_a[1], bbox_b[1])
xB = min(bbox_a[2], bbox_b[2])
yB = min(bbox_a[3], bbox_b[3])
interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)
boxAArea = (bbox_a[2] - bbox_a[0] + 1) * (bbox_a[3] - bbox_a[1] + 1)
boxBArea = (bbox_b[2] - bbox_b[0] + 1) * (bbox_b[3] - bbox_b[1] + 1)
iou = interArea / float(boxAArea + boxBArea - interArea)
return iou
the IoU matrix can be computed as follows:
J = np.zeros((A_bboxes.shape[0], B_bboxes.shape[0]))
for i in range(A_bboxes.shape[0]):
for j in range(B_bboxes.shape[0]):
J[i, j] = compute_iou(A_bboxes[i], B_bboxes[j])
which leads to:
J = array([[0.70422535, 0.28488372, 0.02816901],
[0.25388601, 0.57857143, 0.20661157]])
Now, I'd like to do the same, but without using that double for-loop. I know that scipy.spatial.distance.cdist
can perform a similar task for a user-defined 2-arity function, e.g.:
dm = cdist(XA, XB, lambda u, v: np.sqrt(((u-v)**2).sum()))
However, I cannot see how I could embed the computation of IoU into a lambda expression. Is there any way to do so or even a different way of avoiding the lambda function?
Edit: Answer
It seems that it's really very easy to embed the computation of IoU using a lambda form. The solution is as follows:
J = cdist(A_bboxes, B_bboxes, lambda u, v: compute_iou(u, v)))
J = array([[0.70422535, 0.28488372, 0.02816901],
[0.25388601, 0.57857143, 0.20661157]])