前言
nms和softnms的原理及相关简单代码总结
预测框筛选的方法
预测框的筛选,是检测模块后处理阶段的一个十分重要的过程。因为我们预测输出的预测框,几乎大部分都不是一一对应的(DETR里的是一一对应的),所以一个目标我们可能预测许多框,这些框的分类分数和位置都不同,进行验证和 推理的时候,我们就要使用相应的方法去进行我们预测框的筛选。
1.nms
nms:非极大值抑制。
1> 根据检测框的分类分数(置信度得分)进行降序排序,选取同类分数最高的检测框;
2> 分别计算检测框与相邻检测框的重叠度IOU,对大于阈值Nt的检测框得分直接置零,也就是舍去,并标记将检测框保留下来;
3> 重复这个过程,找到所有被保留下来的检测框;
把iou值大于所给的阈值的框给置为0筛选掉
这里提供cpu版本的简单的nms实现,现在pytorch里提供的都是使用GPU的nms算子,速度要快的多
import numpy as np
import matplotlib.pyplot as plt
def nms_cpu(dets,iou_thres):
x1 = dets[:,0]
y1 = dets[:,1]
x2 = dets[:,2]
y2 = dets[:,3]
scores = dets[:,4]
areas = (x2-x1+1)*(y2-y1+1)
keep = []
index = scores.argsort()[::-1]
while index.size>0:
i = index[0]
keep.append(i)
x_l = np.maximum(x1[i],x1[index[1:]])
y_l = np.maximum(y1[i], y1[index[1:]])
x_r = np.minimum(x2[i],x2[index[1:]])
y_r = np.maximum(y2[i], y2[index[1:]])
h = np.maximum(0,y_r-y_l+1)
w = np.maximum(0,x_r-x_l+1)
intersection = h*w
union = areas[i]+areas[index[1:]]-intersection
ious = intersection/union+1e-8
idx = np.where(ious<=iou_thres)[0]
index = index[idx + 1]
return keep
画图,可视化下看看:
参考:https://blog.csdn.net/EMIvv/article/details/122484524
def draw_boxes(boxes,color):
x1 = boxes[:,0]
y1 = boxes[:,1]
x2 = boxes[:,2]
y2 = boxes[:,3]
s = boxes[:,4]
print(s)
plt.plot([x1,x1],[y1,y2],color)
plt.plot([x1,x2],[y1,y1],color)
plt.plot([x1,x2],[y2,y2],color)
plt.plot([x2,x2],[y1,y2],color)
for i in range(len(s)):
plt.text(float(x1[i]), float(y2[i]), str(round(s[i],3)),ha='center', fontdict=None,bbox=dict(facecolor='red', alpha=0.5))
boxes = np.array([[100, 100, 210, 210, 0.72],
[250, 250, 420, 420, 0.8],
[220, 220, 320, 330, 0.92],
[200, 210, 300, 300, 0.81],
[220, 230, 315, 340, 0.9]])
keep = nms_cpu(boxes,0.6)
plt.figure()
ax1 = plt.subplot(121)
ax2 = plt.subplot(122)
plt.sca(ax1)
draw_boxes(boxes,'b')
plt.sca(ax2)
draw_boxes(boxes[keep],'r')
plt.show()
2.softnms
softnms:是对nms的重叠框处理的方法的改进,认为直接舍去可能不太好,有可能存在同一类的两个目标靠的比较近的情况。所以提出用温和的手段去处理重叠的框,给重叠的框乘以一个与Iou值有关的因子,来控制iou大的分类分数。与nms不同的是,最后是根据所给的分数阈值取框,而不是iou阈值。
1> 根据检测框的置信度得分进行降序排序,选取分数最高的检测框A,
2> 分别计算检测框与相邻检测框的重叠度IOU,对大于阈值的检测框设置一个惩罚函数,降低这些检测框的置信度得分
3> 重复这个过程,找到所有被保留下来的检测框
- 1.线性因子,大于阈值的部分乘以(1-iou):这样重叠度高的,si会变小,比如最大的分类分数为0.9,iou=0.7大于阈值的一个框si=0.6,这样0.6*(1-0.7)=0.18,这样一下降低了分数,后续要根据重新计算的分数阈值筛选。
- 2.高斯置信度降低策略,所有原来的分数乘以一个与iou有关的高斯变量。因为高斯变量符合均值为0,所以这样没有重叠的分类分数还是si,重叠的iou值越大,相乘后分数越低。但是没线性一下降低这么多,相对来说更加平缓。
def softnms_cpu(dets,iou_thres,score_thres,sigma=0.5,method=1):
x1 = dets[:,0]
y1 = dets[:,1]
x2 = dets[:,2]
y2 = dets[:,3]
scores = dets[:,4]
areas = (x2-x1+1)*(y2-y1+1)
keep = []
index = scores.argsort()[::-1]
while index.size>0:
i = index[0]
keep.append(i)
x_l = np.maximum(x1[i],x1[index[1:]])
y_l = np.maximum(y1[i], y1[index[1:]])
x_r = np.minimum(x2[i],x2[index[1:]])
y_r = np.maximum(y2[i], y2[index[1:]])
h = np.maximum(0,y_r-y_l+1)
w = np.maximum(0,x_r-x_l+1)
intersection = h*w
union = areas[i]+areas[index[1:]]-intersection
ious = intersection/union+1e-8
if method==0:
weights = np.ones(ious.shape)
weights[ious>=iou_thres] = weights[ious>=iou_thres]-ious[ious>=iou_thres]
elif method==1:
weights = np.exp(-ious*ious/sigma)
scores[index[1:]] *= weights
update_index = scores[index[1:]].argsort()[::-1]+ 1
print(update_index)
index = index[update_index]
keep_idx = np.where(scores[index]>score_thres)[0]
index = index[keep_idx]
return keep
画图:
def draw_boxes(boxes,color):
x1 = boxes[:,0]
y1 = boxes[:,1]
x2 = boxes[:,2]
y2 = boxes[:,3]
s = boxes[:,4]
print(s)
plt.plot([x1,x1],[y1,y2],color)
plt.plot([x1,x2],[y1,y1],color)
plt.plot([x1,x2],[y2,y2],color)
plt.plot([x2,x2],[y1,y2],color)
for i in range(len(s)):
plt.text(float(x1[i]), float(y2[i]), str(round(s[i],3)),ha='center', fontdict=None,bbox=dict(facecolor='red', alpha=0.5))
box1 = boxes.copy()
keep_sf = softnms_cpu(box1,iou_thres=0.5,score_thres=0.1,sigma=0.5,method=1)
plt.figure()
ax1 = plt.subplot(121)
ax2 = plt.subplot(122)
plt.sca(ax1)
draw_boxes(box1,'b')
plt.sca(ax2)
draw_boxes(box1[keep_sf],'r')
plt.show()
高斯方法的图
实际上是返回索引,然后在原来的boxes里取相应的框和分数,这里是为了看看softnms后的分数变化。实际上还是下图:只有目标比较密集的时候效果才比较明显,常用的是高斯方法的softnms。而且由上面的图可知用softnms时,分数阈值可以设置的小点。
线性方法的图
总结
softnms相对于nms的改进,其实就是一种对原来部分加权进行一种软处理的一种方法,这种方法的思想其实在很多论文里的创新点都有看到过类似的身影。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)