# softnms源码解读（python）

## 思想

1表示batch，这个基本概念就不说了。
85表示coco80个分类+4个坐标(x1,x2,y1,y2）+1个置信度(confidence)。
20160表示输出有20160个行，也就是有这么多框，那我们当然不可能把所有的框都算作我们的目标，画出来你会发现图上都是杂乱无章的框，所以就需要一个方法来帮助我们筛选掉多余的框，而nms的思想简单理解就是将每一个框和其余的框进行iou的计算，去掉超过设定iou阈限的框。

## 代码和关键问题

``````import numpy as np
import time

def py_cpu_softnms(dets, sc, Nt=0.3, sigma=0.5, thresh=0.001, method=2):
"""
py_cpu_softnms
:param dets:   boexs 坐标矩阵 format [y1, x1, y2, x2]
:param sc:     每个 boxes 对应的分数
:param Nt:     iou 交叠门限
:param sigma:  使用 gaussian 函数的方差
:param thresh: 最后的分数门限
:param method: 使用的方法
:return:       留下的 boxes 的 index
"""

# 就是在框矩阵的最后一列加上从0开始的序号
N = dets.shape[0]
indexes = np.array([np.arange(N)])
dets = np.concatenate((dets, indexes.T), axis=1)
print(f'dets is {dets}n')
# 顺序是y1,x1,y2,x2
y1 = dets[:, 0]
x1 = dets[:, 1]
y2 = dets[:, 2]
x2 = dets[:, 3]
print(y1)
print(x1)
print(y2)
print(x2)
scores = sc
print(f'scores is {scores}n')
areas = (x2 - x1 + 1) * (y2 - y1 + 1)
print(f'areas is {areas}n')
for i in range(N):
# 临时存储方便后面参数交换
tBD = dets[i, :].copy()
print(f'tBD before is{tBD}')
tscore = scores[i].copy()
print(f'tscore is {tscore}')
tarea = areas[i].copy()
pos = i + 1

# 选取最大分数
if i != N-1:
maxscore = np.max(scores[pos:], axis=0)
print(f'maxscore is : {maxscore}')
maxpos = np.argmax(scores[pos:], axis=0)
print(f'maxpos is : {maxpos}')
# 这里如果是最后一位了就直接选取它自己，节省时间
else:
maxscore = scores[-1]
maxpos = 0
if tscore < maxscore:
print(1)
dets[i, :] = dets[maxpos + i + 1, :]
dets[maxpos + i + 1, :] = tBD
tBD = dets[i, :]
print(f'dets After is{dets}')
print(f'tBD After is{tBD}')
scores[i] = scores[maxpos + i + 1]
scores[maxpos + i + 1] = tscore
tscore = scores[i]

areas[i] = areas[maxpos + i + 1]
areas[maxpos + i + 1] = tarea
tarea = areas[i]

# IoU 计算
xx1 = np.maximum(dets[i, 1], dets[pos:, 1])
yy1 = np.maximum(dets[i, 0], dets[pos:, 0])
xx2 = np.minimum(dets[i, 3], dets[pos:, 3])
yy2 = np.minimum(dets[i, 2], dets[pos:, 2])

w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)
inter = w * h
ovr = inter / (areas[i] + areas[pos:] - inter)
print(ovr)
# 三种方法: 1.linear 2.gaussian 3.原始的NMS
if method == 1:  # linear
weight = np.ones(ovr.shape)
weight[ovr > Nt] = weight[ovr > Nt] - ovr[ovr > Nt]
elif method == 2:  # gaussian
weight = np.exp(-(ovr * ovr) / sigma)
else:  # 原始的NMS
weight = np.ones(ovr.shape)
weight[ovr > Nt] = 0

scores[pos:] = weight * scores[pos:]
print(f'scores [pos:] is {scores[pos:]}')
# 选择正确的box序号
inds = dets[:, 4][scores > thresh]
keep = inds.astype(int)

return keep

def test():
# 模拟数据
boxes = np.array([[200, 200, 400, 400], [220, 220, 420, 420], [200, 240, 400, 440], [240, 200, 440, 400], [1, 1, 2, 2]], dtype=np.float32)
print(boxes.shape)
boxscores = np.array([0.9, 0.8, 0.7, 0.6, 0.5], dtype=np.float32)
index = py_cpu_softnms(boxes, boxscores, method=3)
print(index)

if __name__ == '__main__':
test()
``````

THE END

)">