NMS的python实现
本篇文章主要是对NMS模块的python实现,因为最近在做有关目标检测的东西,而NMS作为目标检测深度模型之后对图片方框的后处理,是非常重要的一个部分。参考原文(NMS的python实现)
具体的原理建议参考原文,我这里就是搬运一下代码, 当然也有增加了一些自己对代码的解释。
import numpy as np
boxes=np.array([[100,100,210,210,0.72],
[250,250,420,420,0.8],
[220,220,320,330,0.92],
[100,100,210,210,0.72],
[230,240,325,330,0.81],
[220,230,315,340,0.9]])
def py_cpu_nms(dets, thresh):
#首先数据赋值和计算对应矩形框的面积
#dets的数据格式是dets=np.array[[xmin,ymin,xmax,ymax,scores]....]
x1 = dets[:,0]
y1 = dets[:,1]
x2 = dets[:,2]
y2 = dets[:,3]
areas = (y2-y1+1) * (x2-x1+1)
scores = dets[:,4]
print('areas ',areas)
print('scores ',scores)
#这边的keep用于存放,NMS后剩余的方框
keep = []
# 取出分数从大到小排列的索引。.argsort()是从小到大排列,[::-1]是列表头和尾颠倒一下。
index = scores.argsort()[::-1]
print(scores)
print(index)
# 上面这两句比如分数[0.72 0.8 0.92 0.72 0.81 0.9 ]
# 对应的索引index[ 2 5 4 1 3 0 ]记住是取出索引,scores列表没变。scores[2]>scores[5]>scores[4]>...>scores[0]
# index会剔除遍历过的方框,和合并过的方框。
while index.size >0:
print(index.size)
# 取出第一个方框进行和其他方框比对,看有没有可以合并的
i = index[0] # every time the first is the biggst, and add it directly
#因为我们这边分数已经按从大到小排列了。
#所以如果有合并存在,也是保留分数最高的这个,也就是我们现在那个这个
#keep保留的是索引值,不是具体的分数。
keep.append(i)
# 计算交集的左上角和右下角
# 这里要注意,比如x1[i]这个方框的左上角x和所有其他的方框的左上角x的最大值
x11 = np.maximum(x1[i], x1[index[1:]]) # 返回值是【max(x1[i], x1[1]), max(x1[i], x1[2]),....】
y11 = np.maximum(y1[i], y1[index[1:]]) # np.maximum是逐个位置比较。
x22 = np.minimum(x2[i], x2[index[1:]])
y22 = np.minimum(y2[i], y2[index[1:]])
# 这边要注意,如果两个方框相交,X22-X11和Y22-Y11是正的。
# 如果两个方框不相交,X22-X11和Y22-Y11是负的,我们把不相交的W和H设为0.
w = np.maximum(0, x22-x11+1)
h = np.maximum(0, y22-y11+1)
#计算重叠面积就是上面说的交集面积。不相交因为W和H都是0,所以不相交面积为0
overlaps = w*h
print('overlaps is',overlaps)
# 这个就是IOU公式(交并比)。
# 得出来的ious是一个列表,里面拥有当前方框和其他所有方框的IOU结果。
ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
print('ious is',ious)
# 接下来是合并重叠度最大的方框,也就是合并ious中值大于thresh的方框
# 我们合并的操作就是把他们剔除,因为我们合并这些方框只保留下分数最高的。
# 我们经过排序当前我们操作的方框就是分数最高的,所以我们剔除其他和当前重叠度最高的方框
# 这里np.where(ious<=thresh)[0]是一个固定写法。
idx = np.where(ious <= thresh)[0] # 说明index[idx+1]这些位置是IOU小于指定阈值的位置
print('=============', idx)
# 把留下来框再进行NMS操作
# 这边留下的框是去除当前操作的框,和当前操作的框重叠度大于thresh的框
# 每一次都会先去除当前操作框(i框没有参与计算IOU),所以索引的列表就会向前移动移位,要还原就+1,向后移动一位
index = index[idx+1] # because index start from 1
return keep
print(py_cpu_nms(boxes, 0.5))
上面已经在关键地方进行了标注。大家可以下载下来试一试。
以上内容如有错误,恳请指正
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南