IoU及其变体
IoU
IoU简介
IoU (Intersection over Union),又称为交并比,常被用于目标检测中正样本分配、AP计算、非极大值抑制过程中,它就是评估预测框与GT框之间的重合度,IoU值越大,说明预测框更加精确。
假设A是gt框,B为预测框,那么IoU的计算公式为:
如上图,IoU即为图中的深色重叠部分。
代码实现
def compute_iou(box1,box2): """ :param box1: (x0,y0,x1,y1),分别对应框的(左,上,右,下)边界 box2: (x0,y0,x1,y1) :return iou的值 """ assert(box1[2] > box1[0] and box1[3] > box1[1]) assert(box2[2] > box2[0] and box2[3] > box2[1]) # 分别计算两个框的面积 S_1 = (box1[2] - box1[0])*(box1[3] - box1[1]) S_2 = (box2[2] - box2[0])*(box2[3] - box2[1]) # 总面积 sum_area = S_1 + S_2 # 计算相交区域面积 left = max(box1[0],box2[0]) top = max(box1[1],box2[1]) right = min(box1[2],box2[2]) bottom = min(box1[3],box2[3]) if left >= right or top >= bottom: return 0. else: intersect = (right - left)*(bottom - top) return intersect / (sum_area - intersect)
IoU的优点
目标检测中,回归loss相同的情况下,IoU可能大不相同,上图中的各种相交框的情况中,l2或l1的距离相同,但是IoU值不同。
满足度量函数的性质,满足非负性;同一性;对称性;三角不等性。
IoU存在的问题
- 如果两个目标没有重叠,IoU将会为0,并且不会反应两个目标之间的距离,在这种情况下,如果将IoU作为损失函数,梯度为0,无法优化。
- IoU无法区分两个对象之间不同的对齐方式,例如,两个不同方向上的物体可能会和同一个预测框的IoU相同,如下图所示。也可以理解为,下面三种情况的IoU相同,相比之下,左边的图回归效果更好。
GIoU
为了解决IoU无法直接优化的问题,Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression 2019 CVPR提出GIoU。
GIoU的计算公式为:
表示两个框的最小闭包区域面积,即同时包含了预测框和真实框的最小框的面积。再计算闭包区域中不属于两个框的区域占闭包区域的比重,最后用IoU减去这个比重。
代码实现
def compute_generalized_iou(box1,box2): """ :param box1 (x0,y0,x1,y1) 分别表示框的左、上、右、下边界。 box2 (x0,y0,x1,y1) :return giou """ assert(box1[2] > box1[0] and box1[3] > box1[1]) assert(box2[2] > box2[0] and box2[3] > box2[1]) # 计算相交区域面积 left = max(box1[0],box2[0]) top = max(box1[1],box2[1]) right = min(box1[2],box2[2]) bottom = min(box1[3],box2[3]) if left >= right or top >= bottom: intersect = 0 else: intersect = (right - left)*(bottom - top) # 闭包区域 area_c = (max(box1[2],box2[2]) - min(box1[0],box2[0])) * (max(box1[3],box2[3]) - min(box1[1],box2[1])) # 分别计算两个框的面积 S_1 = (box1[2] - box1[0])*(box1[3] - box1[1]) S_2 = (box2[2] - box2[0])*(box2[3] - box2[1]) # 总面积 sum_area = S_1 + S_2 giou = intersect/(sum_area - intersect) - ((area_c - (sum_area - intersect))/area_c) return giou
GIoU的优点
- 与IoU相似,GIoU也是一种距离度量,作为损失函数的话,,满足损失函数的基本要求;
- GIoU对scale不敏感;
- GIoU是IoU的下界,在两个框无限重叠的情况下,GIoU = IoU = 1
- IoU取值为[0,1],但是GIoU有对称区间,取值范围[-1,1],两个框无限远的时候取最小值-1,因此GIoU是非常好的距离度量指标。
- IoU只关注重叠区域,GIoU在此基础上,还考虑其他非重叠区域,能更好地反应二者的重合度。
GIoU存在问题
- 存在两个框的闭包,等于两个框的并集,此时GIoU退化为IoU,如下图:
或者一个框被另一个框包围,如下图:
DIoU(Distance-IoU)
对于上述GIoU存在的问题,Distance-IoU Loss: Faster and Better Learning for Bounding Box Regression提出DIoU,考虑了两个框闭包的大小,以及两个框中心点的距离,如下图:
图中,d表示两个框中心点距离,c表示闭包区域的对角线距离,DIoU引入了两个框中心点距离以缓解上述GIoU存在的问题。
代码实现
def compute_distanceiou(box1,box2): """ :param box1 (x0,y0,x1,y1) 分别表示框的左、上、右、下边界。 box2 (x0,y0,x1,y1) :return giou """ assert(box1[2] > box1[0] and box1[3] > box1[1]) assert(box2[2] > box2[0] and box2[3] > box2[1]) # 计算相交区域面积 left = max(box1[0],box2[0]) top = max(box1[1],box2[1]) right = min(box1[2],box2[2]) bottom = min(box1[3],box2[3]) if left >= right or top >= bottom: intersect = 0 else: intersect = (right - left)*(bottom - top) # 计算中心点 center_x1 = (box1[0] + box1[2])/2 center_y1 = (box1[1] + box1[3])/2 center_x2 = (box2[0] + box2[2])/2 center_y2 = (box2[1] + box2[3])/2 # 中心点之间的距离 center_diag = (center_x2 - center_x1)**2 + (center_y2 - center_y1)**2 # 闭包区域的对角线长度 outer_diag = (max(box1[2],box2[2]) - min(box1[0],box2[0]))**2 + (max(box1[3],box2[3]) - min(box1[1],box2[1]))**2 # 分别计算两个框的面积 S_1 = (box1[2] - box1[0])*(box1[3] - box1[1]) S_2 = (box2[2] - box2[0])*(box2[3] - box2[1]) # 总面积 sum_area = S_1 + S_2 diou = intersect/(sum_area - intersect) - center_diag/outer_diag return diou
优点
- DIoU直接优化两个框的距离,收敛速度比GIoU快,特别是两个框存在包裹的情况。
CIoU (Complete-IoU)
CIoU在DIoU的基础上,还考虑长宽比。
其中为权重系数,用来度量长宽比的相似性,定义为: