非极大值抑制(Non-Maximum Suppression,NMS),即抑制不是极大值的元素,可以理解为局部最大搜索。
目标检测的piplinne:
NMS在post-processing中起到了筛选最大IOU相似度的类别anchor的作用。
soft-NNMS:在NMS中存在的一个问题:高度重叠的同类目标会被滤除,因此需要对IOU的计算结果做非线性变换,保留IOU较低的值而不是直接滤除,即打分根据来确定。
NMS和soft-NMS的对比:
基于python的nms简单实现:
import numpy as np
boxes = np.array([[100, 100, 210, 210, 0.72],
[250, 250, 420, 420, 0.8],
[220, 220, 320, 320, 0.92],
[230, 240, 325, 330, 0.81],
[220, 230, 315, 340, 0.91],
])
def nms(dets, thresh):
#get left head and right bootlom parameters
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
#calculate area, scores, and keep
areas = (y2 - y1 + 1) * (x2 - x1 + 1)
scores = dets[:, 4]
keep = []
#sort box by score form highest to lowest
index = scores.argsort()[::-1]
while index.size > 0:
i = index[0]
keep.append(i)
#get the overlaps parameters
x11 = np.maximum(x1[i], x1[index[1:]])
y11 = np.maximum(y1[i], y1[index[1:]])
x22 = np.minimum(x2[i], x2[index[1:]])
y22 = np.minimum(y2[i], y2[index[1:]])
w = np.maximum(0, x22 - x11 + 1)
h = np.maximum(0, y22 - y11 + 1)
overlaps = w * h
#claculate IoU
ious = overlaps / (areas[i] + areas[index[1:]] - overlaps)
#get the available index
idx = np.where(ious <= thresh)[0]
index = index[idx + 1]
return keep
import matplotlib.pyplot as plt
%matplotlib inline
def plot_bbox(dets, c='k', t='after nms'):
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
plt.plot([x1, x2], [y1, y1], c)
plt.plot([x1, x1], [y1, y2], c)
plt.plot([x1, x2], [y2, y2], c)
plt.plot([x2, x2], [y1, y2], c)
plt.title(t)
plot_bbox(boxes, 'b', 'before nms')
keep = nms(boxes, thresh=0.4)
plot_bbox(boxes[keep], 'r--', 'after nms')
基于python的soft-NMS简单实现:
import numpy as np
boxes = np.array([[100, 100, 210, 210, 0.72],
[250, 250, 420, 420, 0.8],
[220, 220, 320, 320, 0.92],
[230, 240, 325, 330, 0.81],
[220, 230, 315, 340, 0.91],
])
def softnms(dets, thresh, sigma = 0.5):
#get left head and right bootlom parameters
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
#calculate area, scores, and keep
areas = (y2 - y1 + 1) * (x2 - x1 + 1)
scores = dets[:, 4]
keep = []
#sort box by score form highest to lowest
index = scores.argsort()[::-1]
while index.size > 0:
i = index[0]
keep.append(i)
#get the overlaps parameters
x11 = np.maximum(x1[i], x1[index[1:]])
y11 = np.maximum(y1[i], y1[index[1:]])
x22 = np.minimum(x2[i], x2[index[1:]])
y22 = np.minimum(y2[i], y2[index[1:]])
w = np.maximum(0, x22 - x11 + 1)
h = np.maximum(0, y22 - y11 + 1)
overlaps = w * h
#claculate IoU
ious = overlaps / (areas[i] + areas[index[1:]] - overlaps)
weight = np.exp(-(ious * ious)/sigma)
#get the available index
idx = np.where(weight > thresh)[0]
index = index[idx + 1]
return keep
import matplotlib.pyplot as plt
%matplotlib inline
def plot_bbox(dets, c='k', t='after nms'):
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]
plt.plot([x1, x2], [y1, y1], c)
plt.plot([x1, x1], [y1, y2], c)
plt.plot([x1, x2], [y2, y2], c)
plt.plot([x2, x2], [y1, y2], c)
plt.title(t)
plot_bbox(boxes, 'b', 'before nms')
keep = softnms(boxes, thresh=0.4)
plot_bbox(boxes[keep], 'r--', 'after softnms')
实验结论:
蓝色为原始Anchor,红色为NMS/soft-NMS后的检测框,论文中是对anchor的重新打分,此处简化为直接对weight打分,可以看到同一阈值下,soft-NMS能更有效地保留重叠框。
参考博客:非极大值抑制(Non-Maximum Suppression,NMS)