IOU/GIOU/DIOU/CIOU计算公式及代码
box示意图
IoU计算步骤:
- 计算b1和b2右下角的x坐标最小值 (注意坐标轴方向)
- 计算b1和b2左上角y坐标最大值
- w = 步骤1-步骤2 (w小于0则为0,大于0则保持不变)
- 计算b1和b2右下角的y坐标最小值
- 计算b1和b2左上角y坐标最大值 (h小于0则为0,大于0则保持不变)
- h = 步骤4 - 步骤5 (h小于0则为0,大于0则保持不变)
- IoU = w*h / (b1面积+b2面积 - w*h)
def bbox_iou(box1, box2, GIoU=False, DIoU=False, CIoU=False):
'''
计算box1与box2中所有box的IoU
Returns the IoU of box1 to box2. box1 shape is (4,), box2 shapeis (n,4)
4分别表示box的左上角xy以及右下角xy, n表示bbox的个数
'''
box2 = box2.t()
# (x1,y1)为b1的左上角坐标,(x2,y2)则为其右下角坐标
b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]
b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]
# 计算交集面积
# (两个box右下角坐标x的最小值-两个box左上角坐标x的最大值)*
# (两个box右下角坐标y的最小值-两个box左上角坐标y的最大值)
# 注:这边clamp是把小于0的部分置为0,小于0就表示不相交,则计算出来的inter为0
inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
(torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)
# 并集面积
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1
union = (w1 * h1 + 1e-16) + w2 * h2 - inter
iou = inter / union # iou
# 计算GIoU/DIoU/CIoU
if GIoU or DIoU or CIoU:
# cw和ch分别表示把b1和b2围起来最小的长方形的宽和高 convex
cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1)
ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1)
if GIoU: # Generalized IoU https://arxiv.org/pdf/1902.09630.pdf
c_area = cw * ch + 1e-16 # convex area
return iou - (c_area - union) / c_area # GIoU
if DIoU or CIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
# convex对角线距离的平方
c2 = cw ** 2 + ch ** 2 + 1e-16
# b1和b2中心点距离的平方
rho2 = ((b2_x1 + b2_x2) - (b1_x1 + b1_x2)) ** 2 / 4 + ((b2_y1 + b2_y2) - (b1_y1 + b1_y2)) ** 2 / 4
if DIoU:
return iou - rho2 / c2 # DIoU
elif CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2)
with torch.no_grad():
alpha = v / (1 - iou + v)
return iou - (rho2 / c2 + v * alpha) # CIoU