引言
非极大值抑制(Non-Maximum Suppression,NMS),就是抑制不是极大值的元素,可以理解为局部最大搜索。其目的就是去掉冗余的检测框,相似的框只保留一个,这样可以消除多余的候选框,找到最佳的物体检测位置。
算法步骤
算法流程:
其中:B为初始化的候选框,S为每个框的相应得分,
N
t
N_t
Nt为NMS的阈值。
- 初始一个集合D
- 找到S中最高的得分m
- 将框 b m b_m bm加入几个D中,并且集合B中去除 b m b_m bm
- 计算集合B中每个框与 b m b_m bm的IOU值
- 如果IOU值大于 N t N_t Nt,则将该候选框从集合B和S中去除。
- 重复上面步骤2-5,直到没有大于 N t N_t Nt时结束。
def non_max_suppression(boxes, scores, threshold):
"""执行non-maximum suppression并返回保留的boxes的索引.
boxes: [N, (y1, x1, y2, x2)].注意(y2, x2)可以会超过box的边界.
scores: box的分数的一维数组.
threshold: Float型. 用于过滤IoU的阈值.
"""
assert boxes.shape[0] > 0
if boxes.dtype.kind != "f":
boxes = boxes.astype(np.float32)
#计算box面积
y1 = boxes[:, 0]
x1 = boxes[:, 1]
y2 = boxes[:, 2]
x2 = boxes[:, 3]
area = (y2 - y1) * (x2 - x1)
#获取根据分数排序的boxes的索引(最高的排在对前面)
ixs = scores.argsort()[::-1]
pick = []
while len(ixs) > 0:
#选择排在最前的box,并将其索引加到列表中
i = ixs[0]
pick.append(i)
#计算选择的box与剩下的box的IoU
iou = compute_iou(boxes[i], boxes[ixs[1:]], area[i], area[ixs[1:]])
#确定IoU大于阈值的boxes. 这里返回的是ix[1:]之后的索引,
#所以为了与ixs保持一致,将结果加1
remove_ixs = np.where(iou > threshold)[0] + 1
#将选择的box和重叠的boxes的索引删除.
ixs = np.delete(ixs, remove_ixs)
ixs = np.delete(ixs, 0)
return np.array(pick, dtype=np.int32)
pytorch结果调用:
torch.ops.torchvision.nms(boxes, scores, iou_threshold)