相比于传统的IOU,判别重合程度时,使用GIOU,是为了解决以下两个问题:
1.预测的检测框如果和真实物体的检测框没有重叠,无法进一步优化。
2.对于两个IoU相同的物体,他们的对齐方式IoU并不敏感。
于是有如下公式:
GIoU对scale不敏感
GIoU是IoU的下界,在两个框无线重合的情况下,IoU=GIoU
IoU取值[0,1],但GIoU有对称区间,取值范围[-1,1]。在两者重合的时候取最大值1,在两者无交集且无限远的时候取最小值-1,因此GIoU是一个非常好的距离度量指标。
实现giou的pytorch代码为:
def box_giou( b1, b2):
"""
输入为:
b1: tensor, shape=(batch, feat_w, feat_h, anchor_num, 4),
最后一维xywh为box中心坐标及宽高
b2: tensor, shape=(batch, feat_w, feat_h, anchor_num, 4), xywh
返回为:
giou: tensor, shape=(batch, feat_w, feat_h, anchor_num, 1)
"""
#首先计算两者IOU
'''
计算两框相交的部分面积InterArea:画图分析可知,a框与b框相交时,
两框左上角中坐标值较大的一个点,及两框右下角中坐标值较小的一个点,最终围成相交区域。
若两框及两框右下角中坐标值较小的一个点坐标减去两框左上角中坐标值较大的一个点坐标小于0,
则证明无相交,最终结果直接赋值为0。
'''
#先将两者坐标转为左上角及右下角的坐标形式:
box1=torch.zeros_like(b1)
box2 = torch.zeros_like(b2)
box1[...,[0,1]]=b1[...,[0,1]]-b1[...,[2,3]]/2
box1[..., [2, 3]] = b1[..., [0, 1]] + b1[..., [2, 3]] / 2
box2[...,[0,1]]=b2[...,[0,1]]-b2[...,[2,3]]/2
box2[..., [2, 3]] = b2[..., [0, 1]] + b2[..., [2, 3]] / 2
#计算两框相并的面积b1AddB2area
leftTop=torch.max(box1[...,0:2],box2[...,0:2])
bottomRight=torch.min(box1[...,2:4],box2[...,2:4])
#如出现负值表示框不相交截取为0:输出[...,w,h]
b1AndB2=torch.clamp(bottomRight-leftTop,min=0)
#计算了相交面积,形状[...,1]
b1AndB2Area=b1AndB2[...,0:1]*b1AndB2[...,1:2]
#再计算b1及b2自己的面积:形状[...,1]
b1Area=b1[...,2:3]*b1[...,3:4]
b2Area = b2[..., 2:3] * b2[..., 3:4]
#得出IOU的结果
iou=b1AndB2Area/(b1Area+b2Area-b1AndB2Area)
#然后再确定封闭b1及b2的整个矩形:确定该矩形的2个对角:
leftTop=torch.min(box1[...,0:2],box2[...,0:2])
bottomRight=torch.max(box1[...,2:4],box2[...,2:4])
gap=bottomRight-leftTop
#计算封闭矩形的面积:
outerArea=gap[...,0:1]*gap[...,1:2]
#返回giou
return iou-(outerArea-(b1Area+b2Area-b1AndB2Area))/outerArea
编写程序做测试:
b1=torch.FloatTensor([1,1,2,2])
b2=torch.FloatTensor([2,2,2,2])
b1=b1.view(1,1,1,1,4)
b2=b2.view(1,1,1,1,4)
print(box_giou(b1,b2))
输出结果为
tensor([[[[[-0.0794]]]]])