系列博客总结一下目标检测中的基本模块
1.IoU(本文)
2.mAP
3.RPN&&Selective search
4.ROI pooling&&ROI align
5.backbone
Intersection over Union (IoU)
1.IoU的概念
为了用IoU指标来评估目标检测器,我们需要:
ground-truth bounding boxes和我们训练好的模型预测的bounding boxes。
下图是一个示例。图中绿色框为Ground-truth bounding box,红色框为预测框,我们的目标是计算它们的IoU。
计算IoU的公式如下图,可以看到IoU是一个比值,即交并比。
在分子中,我们计算预测框和ground-truth之间的重叠区域;
分母是并集区域,或者更简单地说,是预测框和ground-truth所包含的总区域。
重叠区域和并集区域的比值,就是IoU。
2.为什么使用IoU来评估目标检测器
与分类任务不同,我们预测的bounding box的坐标需要去匹配ground-truth的坐标,而坐标完全匹配基本是不现实的。因此,我们需要定义一个评估指标,奖励那些与ground-truth匹配较好(重叠较大)的预测框。
上图展示了IoU的好坏对比,与ground-truth bounding boxes 重叠比例更大的预测边界框比重叠较少的边界框具有更高的分数,这使得IoU成为评估目标检测器的极佳指标。
我们并不关心(x,y)坐标的精确匹配,但我们确实希望确保我们预测的边界框尽可能匹配——IoU可以做到这一点。
3.IoU的python实现
现在我们已经了解了IoU是什么以及为什么用它来评估目标检测模型,接下来就用Python实现它!
我们的目标是使用IoU来评估目标探测器的性能。 具体来说,给定预测的边界框(红色)与ground-truth(绿色),也就是我们训练好模型的输出与真实label,我们用IoU指标来评估模型的好坏。
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 = max(0, xB - xA + 1) * max(0, 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
函数需要两个参数:boxA和boxB,假定是我们的ground-truth和预测框。
第3-6行确定两个矩形框的(x,y)坐标,然后我们用它们来计算交集的面积(第9行)。
interArea变量表示IoU公式中的分子。
为了计算分母,我们首先需要计算出预测框和ground-truth的区域(第13和14行)。
然后可以在19行上通过将交集区域除以两个边界框的并集区域与交叉区域的差来计算IoU,(注意从分母中减去交叉区域,否则交叉区域将被双倍计数)。
最后,IoU分数将返回到第22行的调用函数。
现在我们的IoU方法已经完成。
4.IoU的实际使用
下面实现是商汤mmdet中的实现,基本是一样的,只是是batch的矩阵运算。
import numpy as np
def bbox_overlaps(bboxes1, bboxes2, mode='iou'):
"""Calculate the ious between each bbox of bboxes1 and bboxes2.
Args:
bboxes1(ndarray): shape (n, 4)
bboxes2(ndarray): shape (k, 4)
mode(str): iou (intersection over union) or iof (intersection
over foreground)
Returns:
ious(ndarray): shape (n, k)
"""
assert mode in ['iou', 'iof']
bboxes1 = bboxes1.astype(np.float32)
bboxes2 = bboxes2.astype(np.float32)
rows = bboxes1.shape[0]
cols = bboxes2.shape[0]
ious = np.zeros((rows, cols), dtype=np.float32)
if rows * cols == 0:
return ious
exchange = False
if bboxes1.shape[0] > bboxes2.shape[0]:
bboxes1, bboxes2 = bboxes2, bboxes1
ious = np.zeros((cols, rows), dtype=np.float32)
exchange = True
area1 = (bboxes1[:, 2] - bboxes1[:, 0] + 1) * (
bboxes1[:, 3] - bboxes1[:, 1] + 1)
area2 = (bboxes2[:, 2] - bboxes2[:, 0] + 1) * (
bboxes2[:, 3] - bboxes2[:, 1] + 1)
for i in range(bboxes1.shape[0]):
x_start = np.maximum(bboxes1[i, 0], bboxes2[:, 0])
y_start = np.maximum(bboxes1[i, 1], bboxes2[:, 1])
x_end = np.minimum(bboxes1[i, 2], bboxes2[:, 2])
y_end = np.minimum(bboxes1[i, 3], bboxes2[:, 3])
overlap = np.maximum(x_end - x_start + 1, 0) * np.maximum(
y_end - y_start + 1, 0)
if mode == 'iou':
union = area1[i] + area2 - overlap
else:
union = area1[i] if not exchange else area2
ious[i, :] = overlap / union
if exchange:
ious = ious.T
return ious
5.参考资料
Intersection over Union (IoU) for object detection