在有锚框的目标检测算法中,如何衡量某个锚框较好地覆盖了图像中的目标物体?在该目标的真实边界框已知时,一种直观的方法是衡量锚框和真实边界框之间的相似度。
Jaccard系数(Jaccard index)可以衡量两个集合的相似度。给定集合A和B,它们的Jaccard系数为
实际上,我们可以把边界框内的像素区域看成是像素的集合。这样,可以用两个边界框的像素集合的Jaccard系数衡量这两个边界框的相似度。在这种情况下,通常将Jaccard系数称为交并比(Intersection over Union,IoU),即两个边界框相交面积与相并面积的比值。
1、边界框的交集
给定两个边界框A、B的四个顶点的坐标,
A
(
x
1
m
i
n
,
y
1
m
i
n
,
x
1
m
a
x
,
y
1
m
a
x
)
A(x_{1min}, y_{1min}, x_{1max}, y_{1max})
A(x1min,y1min,x1max,y1max)、
B
(
x
2
m
i
n
,
y
2
m
i
n
,
x
2
m
a
x
,
y
2
m
a
x
)
B(x_{2min}, y_{2min}, x_{2max}, y_{2max})
B(x2min,y2min,x2max,y2max),则相交得到的矩形四个顶点的坐标为
(
m
a
x
(
x
1
m
i
n
,
x
2
m
i
n
)
,
m
a
x
(
y
1
m
i
n
,
y
2
m
i
n
)
,
m
i
n
(
x
1
m
a
x
,
x
2
m
a
x
)
,
m
i
n
(
y
1
m
a
x
,
y
2
m
a
x
)
)
(max(x_{1min},x_{2min}), max(y_{1min},y_{2min}),min(x_{1max},x_{2max}),min(y_{1max},y_{2max}))
(max(x1min,x2min),max(y1min,y2min),min(x1max,x2max),min(y1max,y2max))
如下图所示:
def intersect(box_a, box_b):
'''
Args:
box_a: Ground truth bounding box: shape[N, 4]
box_b: Priors bounding box: shape[M, 4]
'''
N = box_a.size(0)
M = box_b.size(0)
# 左上角,选出最大值
LT = torch.max(
box_a[:, :2].unsqueeze(1).expand(N, M, 2), #(N,2)-->(N,1,2)-->(N,M,2)
box_b[:, :2].unsqueeze(0).expand(N, M, 2), #(M,2)-->(M,1,2)-->(N,M,2)
)
# 右下角,选出最小值
RB = torch.min(
box_a[:, 2:].unsqueeze(1).expand(N, M, 2), #(N,2)-->(N,1,2)-->(N,M,2)
box_b[:, 2:].unsqueeze(0).expand(N, M, 2), #(M,2)-->(M,1,2)-->(N,M,2)
)
wh = RB - LT
wh[wh < 0] = 0 # 两个box没有重叠区域
inter = wh[:, :, 0] * wh[:, :, 1] # A∩B
return inter
2、边界框的并集
def unionset(box_a, box_b):
N = box_a.size(0)
M = box_b.size(0)
# box_a和box_b的面积
area_a = (box_a[:, 2]-box_a[:, 0]) * (box_a[:, 3]-box_a[:, 1]) #(N,)
area_b = (box_b[:, 2]-box_b[:, 0]) * (box_b[:, 3]-box_b[:, 1]) #(M,)
# 把面积的shape扩展为inter一样的(N,M)
area_a = area_a.unsqueeze(1).expand(N, M)
area_b = area_b.unsqueeze(0).expand(N, M)
return area_a + area_b - intersect(box_a, box_b)
3、Jaccard系数
def jaccard(box_a, box_b):
inter = intersect(box_a, box_b)
union = unionset(box_a, box_b)
return inter / union
# 测试代码
if __name__ == "__main__":
box_a = torch.Tensor([[2,1,4,3],[2,2,2,2]])
box_b = torch.Tensor([[3,2,5,4],[2,1,5,7],[4,2,9,1]])
print('IOU = ',jaccard(box_a, box_b))