IoU(Intersection over union)
:交并比IoU衡量的是两个区域的重叠程度,是两个区域重叠部分面积占二者总面积的比例。在目标检测中,如果模型输出的结果与真值gt的交并比 > 某个阈值(0.5或0.7)时,即认为我们的模型输出了正确的结果。
IoU 计算的必要项:
- groundtruth bounding boxes,例如,测试集中手工标注的物体边界框.A
- predicted bounding boxes, 检测算法模型所预测的输出.B
目标检测中,算法的性能好坏,预测的边界框与 groundtruth 边界框间的重叠覆盖成都,如图例示:
IoU有三种计算方式:
(1)2D IoU:将3D检测结果框映射回2D的Image View
(2)3D IoU:直接在3D空间计算检测结果与Ground truth的IoU
(3)BEV IoU:将3D检测结果与Gound truth映射到2D的鸟瞰图上再计算IoU
2D IoU python实现
from collections import namedtuple
import numpy as np
import cv2
def bb_intersection_over_union(boxA, boxB):
# 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])
# compute the area of intersection rectangle
# 交集
interArea = (xB - xA + 1) * (yB - yA + 1)
# compute the area of both the prediction and ground-truth rectangles
# 并集
boxAArea = (boxA[2] - boxA[0] + 1) * (boxA[3] - boxA[1] + 1)
boxBArea = (boxB[2] - boxB[0] + 1) * (boxB[3] - boxB[1] + 1)
# compute the intersection over union by taking the intersection
# area and dividing it by the sum of prediction + ground-truth
# areas - the interesection area
iou = interArea / float(boxAArea + boxBArea - interArea)
# return the intersection over union value
return iou
# define the `Detection` object
Detection = namedtuple("Detection", ["image_path", "gt", "pred"])
# define the list of example detections
examples = [
Detection("dog.png", [39, 63, 203, 112], [54, 66, 198, 114]),
Detection("dog.png", [49, 75, 203, 125], [42, 78, 186, 126]),
Detection("dog.png", [31, 69, 201, 125], [18, 63, 235, 135]),
Detection("dog.png", [50, 72, 197, 121], [54, 72, 198, 120]),
Detection("dog.png", [35, 51, 196, 110], [36, 60, 180, 108])]
# loop over the example detections
for detection in examples:
# load the image
image = cv2.imread(detection.image_path)
# draw the ground-truth bounding box along with the predicted
# bounding box
cv2.rectangle(image, tuple(detection.gt[:2]),
tuple(detection.gt[2:]), (0, 255, 0), 2)
cv2.rectangle(image, tuple(detection.pred[:2]),
tuple(detection.pred[2:]), (0, 0, 255), 2)
# compute the intersection over union and display it
iou = bb_intersection_over_union(detection.gt, detection.pred)
cv2.putText(image, "IoU: {:.4f}".format(iou), (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
print("{}: {:.4f}".format(detection.image_path, iou))
# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)
3D IoU python实现
# 3D IOU 计算
def boxes_iou3d_gpu(boxes_a, boxes_b):
"""
Args:
boxes_a: (N, 7) [x, y, z, dx, dy, dz, heading]
boxes_b: (N, 7) [x, y, z, dx, dy, dz, heading]
Returns:
ans_iou: (N, M)
"""
assert boxes_a.shape[1] == boxes_b.shape[1] == 7
# height overlap
boxes_a_height_max = (boxes_a[:, 2] + boxes_a[:, 5] / 2).view(-1, 1)
boxes_a_height_min = (boxes_a[:, 2] - boxes_a[:, 5] / 2).view(-1, 1)
boxes_b_height_max = (boxes_b[:, 2] + boxes_b[:, 5] / 2).view(1, -1)
boxes_b_height_min = (boxes_b[:, 2] - boxes_b[:, 5] / 2).view(1, -1)
# bev overlap
overlaps_bev = torch.cuda.FloatTensor(torch.Size((boxes_a.shape[0], boxes_b.shape[0]))).zero_() # (N, M)
iou3d_nms_cuda.boxes_overlap_bev_gpu(boxes_a.contiguous(), boxes_b.contiguous(), overlaps_bev)
max_of_min = torch.max(boxes_a_height_min, boxes_b_height_min)
min_of_max = torch.min(boxes_a_height_max, boxes_b_height_max)
overlaps_h = torch.clamp(min_of_max - max_of_min, min=0)
# 3d iou
overlaps_3d = overlaps_bev * overlaps_h
vol_a = (boxes_a[:, 3] * boxes_a[:, 4] * boxes_a[:, 5]).view(-1, 1)
vol_b = (boxes_b[:, 3] * boxes_b[:, 4] * boxes_b[:, 5]).view(1, -1)
iou3d = overlaps_3d / torch.clamp(vol_a + vol_b - overlaps_3d, min=1e-6)
return iou3d
2D和3D代码几乎完全一样,都是先算两个框各自面积/体积,再算重叠部分,最后计算IOU。