NMS 顾名思义,非极大值抑制,也就是把极值周围的给抑制掉,不输出。在深度学习中叫去重,只保留最可靠的那个输出。
首先定义一个相似度,深度学习中用IOU表示两个框的相似度。
步骤:
1、取分值最大的框。
2、将IOU大于阈值(0.5)的框抑制掉。
3、取剩下框分值最大的框,循环步骤1、2。
很简单,是不是!
代码:
def NMS(boxes, scores, th):
x1 = boxes[:,0]
y1 = boxes[:,1]
x2 = boxes[:,2]
y2 = boxes[:,3]
box_erea = (y2 - y1) * (x2 - x1)
orders = scores.argsort()[::-1] ## 取逆序
print(orders)
keep = []
print(orders.size)
while orders.size > 0:
item = orders[0]
keep.append(item)
cur_box = boxes[item]
ix1 = np.maximum(cur_box[0], x1[orders[1:]])
iy1 = np.maximum(cur_box[1], y1[orders[1:]])
ix2 = np.minimum(cur_box[2], x2[orders[1:]])
iy2 = np.minimum(cur_box[3], y2[orders[1:]])
iners = np.maximum(ix2 - ix1 + 1, 0.) * np.maximum(iy2 - iy1 + 1, 0.)
unions = (box_erea[orders[1:]] + box_erea[item]) - iners
ious = iners / unions
temp = np.where(ious < th)[0]
orders = orders[temp + 1]
return keep
代码解析:
1、先计算所有框的面积
2、分值降序排序,得到一个位置序列
3、循环:如果序列(N个值)不空:
取最大分值框,id对应第0个位置。
取所有剩余的框,id对应第0个位置之后。
剩余框(N-1个值)和最大分值框求IOU(N-1 个 IOU)
保留(N-1个)剩余框中对应IOU小于阈值的框的序列编号。作为新的序列。
注意事项:
temp = np.where(ious < th)[0]
orders = orders[temp + 1]
因为 temp 对应的是(N-1个)剩余框的位置,要取原序列(N个值)对应的位置,所以temp 对应的位置要加1。
np.max() 求最大值
np.minimum(array, a)array 和 a 逐个比较取最大。
顾名思义,柔和的NMS。也就是不会立马斩杀,而是降低分值待考察。为的就是防止漏检。
怎么降低score呢?有很多种方式,
1、IOU线性抑制
2、IOU 高斯抑制
抑制死亡阈值: th = 0.001 , 未达到死亡阈值,仍可保留。
主要用在:
NMS时用到的score仅仅是分类置信度得分,不能反映Bounding box的定位精准度,既分类置信度和定位置信非正相关的。
基于soft-NMS,对预测标注方差范围内的候选框加权平均,使得高定位置信度的bounding box具有较高的分类置信度。
其实很简单,预测的四个顶点坐标,分别对IoU>Nt的预测加权平均计算,得到新的4个坐标点。