nms算法就是对同一个anhor 的box 进行基于阈值的去重

1、目的

对于尺寸为416×416的输入图像,YOLO预测((52×52)+(26×26)+ 13×13))×3 = 10647个边界框。 但是,在我的图像中只有三个物体(本人,水杯,手机)。 我们如何将检测结果从10647减少到3呢?

2、基于对象置信度的阈值。

首先,我们根据对象分数(objectness score)过滤框。 通常,具有低于阈值分数的框被忽略。

3、非最大抑制(NMS)

NMS打算解决同一图像的多重检测问题。通过抑制不是极大值的元素,可以理解为局部最大搜索。这个局部代表的是一个邻域,邻域有两个参数可变,一是邻域的维数,二是邻域的大小。这里讨论用于目标检测中提取分数最高的窗口的。例如在行人检测中,滑动窗口经提取特征,经分类器分类识别后,每个窗口都会得到一个分数。但是滑动窗口会导致很多窗口与其他窗口存在包含或者大部分交叉的情况。这时就需要用到NMS来选取那些邻域里分数最高(是行人的概率最大),并且抑制那些分数低的窗口。
3.1、算法过程
Step1:按置信概率排列相应的备选框
:取最大的框作为保留框,与其IOU大于阈值的框删除掉
:剩下的框执行Step2
# python3
import numpy as np

def py_nms(dets, thresh):
"""Pure Python NMS baseline."""
#x1、y1、x2、y2、以及score赋值
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
scores = dets[:, 4]

#每一个候选框的面积
areas = (x2 - x1 + 1) * (y2 - y1 + 1)


### argsort()函数是将x中的元素从小到大排列,提取其对应的index(索引)

or1=scores.argsort() #array([3, 2, 1, 0])

#降序排序的
order = or1[::-1]

keep = []
while order.size > 0:

#先取order最大的那个索引 i
i = order[0]

#保留score最大的那个box
keep.append(i)

#计算当前概率最大矩形框与其他矩形框的相交框的坐标,会用到numpy的broadcast机制,得到的是向量
xx1 = np.maximum(x1[i], x1[order[1:]])
yy1 = np.maximum(y1[i], y1[order[1:]])
xx2 = np.minimum(x2[i], x2[order[1:]])
yy2 = np.minimum(y2[i], y2[order[1:]])

#计算相交框的面积,注意矩形框不相交时w或h算出来会是负数,用0代替
#分别计算其他box 与 i box 的交集
w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
inter = w * h
#计算重叠度IOU:重叠面积/(面积1+面积2-重叠面积)

#其他box 与i box 的iou
ovr = inter / (areas[i] + areas[order[1:]] - inter)

#找到重叠度不高于阈值的矩形框索引
inds = np.where(ovr <= thresh)[0]
#因为ovr 是三维,已经去掉了score最大的那一个
#将order序列更新,由于前面得到的矩形框索引要比矩形框在原order序列中的索引小1,所以要把这个1加回来
order = order[inds + 1]
return keep

# test
if __name__ == "__main__":
dets = np.array([[30, 20, 230, 200, 1],
[50, 50, 260, 220, 0.9],
[210, 30, 420, 5, 0.8],
[430, 280, 460, 360, 0.7]])
thresh = 0.35
keep_dets = py_nms(dets, thresh)
print(keep_dets)
print(dets[keep_dets])
tensorflow 有内置的nms算法api
tf.image.non_max_suppression_with_scores(
boxes, scores, max_output_size, iou_threshold=0.5,
score_threshold=float('-inf'), soft_nms_sigma=0.0, name=None
)