【目标检测】非极大值抑制(NMS)的原理与实现

🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个性化解决方案等服务,如有需要请站内私信或者联系任意文章底部的的VX名片(ID:xf982831907

💬 博主粉丝群介绍:① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。③ 群内也有职场精英,大厂大佬,可交流技术、面试、找工作的经验。④ 进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬。⑤ 进群赠送CSDN评论防封脚本,送真活跃粉丝,助你提升文章热度。有兴趣的加文末联系方式,备注自己的CSDN昵称,拉你进群,互相学习共同进步。

在这里插入图片描述

@TOC

一、引言

  在目标检测中,NMS是提升模型性能的关键后处理技术,但90%的初学者对其实现原理理解不足。本文将彻底解密NMS的工作原理,并提供可直接运行的Python代码,让你真正掌握这一核心技能!

二、为什么需要非极大值抑制(NMS)?

  目标检测模型在处理图像时,往往会对同一个目标产生多个重叠的预测框。如下图所示:

  图片来源于:https://blog.csdn.net/weixin_62264287/article/details/133936328

  这些重叠框会导致:

  1. 重复检测:同一目标被多次识别
  2. 结果冗余:输出包含大量无效预测
  3. 性能下降:影响后续处理效率

  非极大值抑制(Non-Maximum Suppression, NMS) 正是为了解决这一问题而诞生。它像一位"裁判",从众多候选框中选出最合适的一个,淘汰冗余预测。

三、NMS核心原理揭秘

3.1 NMS工作原理四步曲

  1. 排序候选框:将所有预测框按置信度(confidence score)从高到低排序
  2. 选择最高分:选取置信度最高的框作为保留框
  3. 计算IOU:计算该保留框与剩余所有框的IOU
  4. 剔除重叠框:删除IOU超过阈值的框(通常阈值设为0.5)

  重复步骤2-4,直到所有框都被处理完毕。整个过程如下图所示:

四、Python实现NMS算法

  下面我们实现一个完整的NMS算法,并可视化处理效果:

import numpy as np
import cv2
import matplotlib.pyplot as plt
import matplotlib.patches as patchesdef nms(boxes, scores, threshold=0.5):"""非极大值抑制(NMS)实现参数:boxes: 边界框列表 [x1, y1, x2, y2]scores: 每个框的置信度threshold: IOU阈值返回:保留的框索引列表"""# 如果没有框,直接返回空列表if len(boxes) == 0:return []# 将框坐标转换为float类型boxes = np.array(boxes, dtype=np.float32)# 获取框的坐标x1 = boxes[:, 0]y1 = boxes[:, 1]x2 = boxes[:, 2]y2 = boxes[:, 3]# 计算每个框的面积areas = (x2 - x1 + 1) * (y2 - y1 + 1)# 按置信度降序排序idxs = np.argsort(scores)# 初始化保留列表keep = []while len(idxs) > 0:# 取出当前置信度最高的框last = len(idxs) - 1i = idxs[last]keep.append(i)# 计算当前框与其他框的IOUxx1 = np.maximum(x1[i], x1[idxs[:last]])yy1 = np.maximum(y1[i], y1[idxs[:last]])xx2 = np.minimum(x2[i], x2[idxs[:last]])yy2 = np.minimum(y2[i], y2[idxs[:last]])# 计算交集区域的宽和高w = np.maximum(0, xx2 - xx1 + 1)h = np.maximum(0, yy2 - yy1 + 1)# 计算IOUintersection = w * hiou = intersection / (areas[i] + areas[idxs[:last]] - intersection)# 删除IOU大于阈值的框delete_idxs = np.where(iou > threshold)[0]idxs = np.delete(idxs, np.concatenate(([last], delete_idxs)))return keepdef visualize_boxes(image, boxes, scores, title, color='r'):"""可视化边界框"""plt.figure(figsize=(10, 6))plt.imshow(image)ax = plt.gca()for i, box in enumerate(boxes):x1, y1, x2, y2 = boxrect = patches.Rectangle((x1, y1), x2-x1, y2-y1, linewidth=2, edgecolor=color, facecolor='none')ax.add_patch(rect)plt.text(x1, y1-10, f'{scores[i]:.2f}', fontsize=10, color='white', bbox=dict(facecolor=color, alpha=0.8))plt.title(title)plt.axis('off')plt.show()# 创建模拟图像
image = np.ones((400, 600, 3), dtype=np.uint8) * 255
cv2.putText(image, 'Target Detection', (150, 200), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 0), 3)# 模拟检测结果 (格式: [x1, y1, x2, y2])
boxes = [[100, 100, 300, 300],   # 高置信度[120, 120, 320, 320],   # 与第一个高度重叠[150, 150, 350, 350],   # 与第一个高度重叠[400, 150, 550, 350],   # 不同位置[380, 130, 530, 330],   # 与第四个重叠[420, 170, 570, 370]    # 与第四个重叠
]# 对应的置信度
scores = [0.95, 0.90, 0.85, 0.92, 0.88, 0.80]# 可视化原始检测结果
visualize_boxes(image, boxes, scores, '原始检测结果 (NMS前)', color='r')# 应用NMS
keep = nms(boxes, scores, threshold=0.5)# 筛选保留的框
nms_boxes = [boxes[i] for i in keep]
nms_scores = [scores[i] for i in keep]# 可视化NMS后的结果
visualize_boxes(image, nms_boxes, nms_scores, 'NMS处理后的结果', color='g')

五、代码解析与运行结果

5.1 核心函数解析

  1. nms函数

    • 输入:边界框列表、置信度列表、IOU阈值
    • 处理流程:
      • 按置信度排序
      • 循环处理每个框
      • 计算当前框与其他框的IOU
      • 删除IOU超过阈值的框
    • 输出:保留框的索引列表
  2. visualize_boxes函数

    • 功能:在图像上绘制边界框和置信度
    • 参数:图像、框列表、置信度列表、标题、颜色

5.2 运行效果展示

  运行上述代码,你将看到两个对比图像:

NMS前

  • 红色框表示原始检测结果
  • 同一目标有多个重叠框

NMS后

  • 绿色框表示NMS处理后的结果

六、NMS的进阶应用与优化

6.1 软性NMS(Soft-NMS)

  传统NMS直接删除重叠框,可能导致以下问题:

  • 密集目标漏检
  • 阈值设置敏感

  软性NMS的改进方案:

# 在NMS循环中替换删除操作
for j in delete_idxs:# 根据IOU降低置信度,而不是直接删除scores[j] = scores[j] * (1 - iou[j])

6.2 多类别NMS处理

  当处理多类别检测时,需要:

# 按类别分组处理
for class_id in unique_classes:class_indices = np.where(class_ids == class_id)[0]class_boxes = boxes[class_indices]class_scores = scores[class_indices]keep_indices = nms(class_boxes, class_scores)# 合并各类别结果

6.3 其他改进方法

方法核心思想适用场景
Weighted NMS加权融合重叠框需要更精确位置
Adaptive NMS动态调整阈值密集目标检测
DIoU NMS考虑中心点距离解决边界框错位

七、NMS在实际项目中的应用技巧

7.1 阈值选择策略

  • 通用目标:0.5-0.7
  • 密集小目标:0.3-0.5
  • 大目标/精确检测:0.7-0.9

7.2 性能优化技巧

# 向量化加速
def vectorized_nms(boxes, scores, threshold):# 使用矩阵运算代替循环x1 = boxes[:, 0]y1 = boxes[:, 1]x2 = boxes[:, 2]y2 = boxes[:, 3]areas = (x2 - x1 + 1) * (y2 - y1 + 1)order = scores.argsort()[::-1]keep = []while order.size > 0:i = order[0]keep.append(i)# 向量化计算IOUxx1 = np.maximum(x1[i], x1[order[1:]])yy1 = np.maximum(y1[i], y1[order[1:]])xx2 = np.minimum(x2[i], x2[order[1:]])yy2 = np.minimum(y2[i], y2[order[1:]])w = np.maximum(0.0, xx2 - xx1 + 1)h = np.maximum(0.0, yy2 - yy1 + 1)inter = w * hiou = inter / (areas[i] + areas[order[1:]] - inter)# 向量化索引inds = np.where(iou <= threshold)[0]order = order[inds + 1]return keep

八、总结与思考

  NMS作为目标检测中不可或缺的后处理步骤,其重要性不言而喻。通过本文的学习,你应该掌握:

  1. NMS的核心原理和工作流程
  2. NMS的Python实现方法
  3. NMS的优化技巧和变体
  4. 实际应用中的参数调整策略

关键思考:当两个目标非常接近时,传统NMS可能导致其中一个被错误抑制。如何解决这个问题?

答案:可以尝试以下方法:

  1. 使用Soft-NMS替代传统NMS
  2. 降低IOU阈值(如0.3)
  3. 增加位置权重(如DIoU-NMS)
  4. 调整模型锚框设计

九、附录:完整项目代码

  获取NMS和可视化功能的完整代码:
https://gitee.com/zhang-xufang/object_detection_demo/blob/master/NMS.py


觉得本文有帮助?点击👍支持!如果有任何问题或建议,欢迎在评论区留言讨论~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87642.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87642.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DB-GPT启动提示please install by running `pip install cryptography`

DB-GPT项目需要 cryptography 库来处理加密功能&#xff0c;但环境中没有安装它。cryptography 是一个用于安全和加密操作的Python库&#xff0c;许多项目&#xff08;包括DB-GPT&#xff09;依赖它来处理敏感数据的加密存储。 解决方案 1. 安装 cryptography 库 在激活的环…

局域网文件共享及检索系统

标题:局域网文件共享及检索系统 内容:1.摘要 随着信息技术的飞速发展&#xff0c;局域网在企业、学校等场景中得到广泛应用&#xff0c;大量文件在局域网内存储和流转。然而&#xff0c;目前局域网内文件共享与检索存在效率低、管理困难等问题。本文旨在设计并实现一个高效的局…

Spring Boot医疗系统高并发难题:达梦数据库死锁排查与优化实战

Spring Boot医疗系统高并发难题:达梦数据库死锁排查与优化实战 引言:医疗系统中的并发挑战 在现代医疗系统中,检查申请处理是关键业务场景之一,每天需要处理数以万计的检查记录。当多个操作同时更新同一患者的申请状态时,数据库层面的死锁问题成为高并发环境下的典型痛点…

Go语言中的文件与IO:bufio 和 scanner

Go 标准库中的 bufio 包提供了带缓冲的读写功能&#xff0c;可以显著提高文件和数据处理效率。而 bufio.Scanner 则是读取文本文件中每一行的利器&#xff0c;常用于日志、配置等文本处理场景。 一、为什么使用 bufio&#xff1f; 直接对文件进行 os.File.Read() 或 os.File.W…

ABP微服务架构中网关层NullReferenceException问题解析与HTTP配置优化

ABP微服务架构中网关层NullReferenceException问题解析与HTTP配置优化 一、网关层System.NullReferenceException问题解析 1.1 问题现象与原因分析 在ABP微服务架构开发过程中&#xff0c;网关层启动后调用微服务接口时出现以下异常&#xff1a; System.NullReferenceExcep…

啊啊啊啊啊啊啊啊code

前序遍历和中序遍历构建二叉树 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNod…

【算法 day06】LeetCode 454.四数相加II | 15. 三数之和 | 18. 四数之和

454.四数相加II 题目链接 | 文档讲解 |视频讲解 : 链接 1.思路&#xff1a; 0.定义一个count&#xff0c;计算最终出现的次数 1.先遍历nums1和nums2,求出两者的和&#xff0c;map的key是和&#xff0c;value是出现的次数 2.再遍历nums3和nums4&#xff0c;求出0-两者的和 3…

【项目实训】【项目博客#09】HarmonySmartCodingSystem系统后端智能API检索与代码助手实现(6.2-6.15)

【项目实训】【项目博客#09】HarmonySmartCodingSystem系统后端智能API检索与代码助手实现&#xff08;6.2-6.15&#xff09; 文章目录 【项目实训】【项目博客#09】HarmonySmartCodingSystem系统后端智能API检索与代码助手实现&#xff08;6.2-6.15&#xff09;项目博客概述一…

【JVM】- 类加载与字节码结构3

类加载阶段 1. 加载 加载&#xff1a;将类的字节码载入方法区中&#xff0c;内部采用C的instanceKlass描述java类。如果这个类的父类还没加载&#xff0c;则先加载父类加载和链接可能是交替运行的 通过全限定名获取字节码 从文件系统&#xff08;.class 文件&#xff09;、JA…

Qt蓝图式技能编辑器状态机模块设计与实现

设计概述 这个模块是一个基于Qt的蓝图式技能编辑器状态机&#xff0c;主要用于游戏开发中的技能状态管理。核心功能包括&#xff1a; 状态节点&#xff08;开始、结束、普通状态&#xff09;的可视化 状态间连线的绘制与管理 状态转换逻辑的可视化编辑 动作选择与配置 核…

Unity AR识别物体的内容语音读取+使用说明功能

因之前一直在开发项目&#xff0c;断断续续写了一点博客&#xff0c;最后统一写了一下博客记录学习内容。 可以看到我的工作一直在进行。 目录 一、识别内容语音读取 二、点击齿轮按钮弹出使用说明界面 开发步骤 1. 创建齿轮按钮 UI 2. 创建使用说明面板 UI 3. 编写控制…

Unable to start embedded Tomcat

通常是由于xml文件配置错误导致 1. mapper 指向错误 <resultMap id"Waybill" type"c.Waybill"> 2. 字段类型错误 <result column"wstatus" property"stus" javaType"TINYINT"/>TINYINT 是数据库类型<resu…

Mac电脑 充电限制保护工具 AlDente Pro

AlDente Pro一款充电限制保护工具&#xff0c;是可以限制最大充电百分比来保护电池的工具。 锂离子和聚合物电池&#xff08;如 MacBook 中的电池&#xff09;在40&#xff05; 至 80&#xff05; 之间运行时&#xff0c;使用寿命最长。 始终将电池电量保持在 100&#xff05…

KungfuBot——基于物理约束和自适应运动追踪的人形全身控制PBHC,用于学习打拳或跳舞(即RL下的动作模仿和运控)

前言 昨天618&#xff0c;我司「七月在线」同事朝阳为主力&#xff0c;我打杂&#xff0c;折腾了整整一天&#xff0c;终于可以通过VR摇操宇树G1了——当然&#xff0c;摇操是为了做训练数据的采集&#xff0c;从而方便 下一步的模型(策略)训练&#xff0c;最终实现机器人自主…

Kafka多副本机制

副本和副本因子 Kafka 会为每个 Partition 创建多个副本。这些副本分布在不同的 Broker 上。副本确保了数据的冗余存储&#xff0c;即使某个 Broker 宕机或失效&#xff0c;其他副本可以继续提供服务。 副本因子指的是每个 Partition 有多少个副本。副本因子的设置决定了一个…

Vue3类似百度风格搜索框组件

Vue3百度风格搜索框组件&#xff0c;使用vue3进行设计&#xff0c;亦有vue3TS的版本。 vue3组件如下&#xff1a; <template><!-- 搜索组件容器 --><div class"search-container"><!-- 百度Logo - 新样式 --><div class"logo-conta…

智净未来:华为智选IAM以科技巧思优化家庭健康饮水体验

在中国家庭中&#xff0c;净水器早已成为厨房标配&#xff0c;但传统净水设备的使用体验却远未达到理想状态。根据《2023年中国家庭净水器使用调研报告》显示&#xff0c;超过65%的用户对传统净水器存在不满&#xff0c;主要痛点集中在功能单一、操作复杂、维护麻烦、噪音大、废…

细说STM32单片机SPI-Flash芯片的FatFS移植

目录 一、SPI-Flash芯片硬件电路 二、CubeMX项目基础设置 1、RCC、SYS、Code Generator、USART6、NVIC 2、RTC 3、SPI2 4、GPIO 5、FatFS模式 6、FatFS参数设置概述 &#xff08;1&#xff09;Version组 &#xff08;2&#xff09;Function Parameters组 1&#x…

ubuntu 22.04 安装部署logstash 7.10.0详细教程

安装部署logstash 7.10.0详细教程 一、下载并安装二、新建配置文件三、赋权文件权限四、检测文件grok语法是否异常五、启动服务六、安装启动常见问题 【背景】 整个elk安装是基于ubuntu 22.04和jdk 11环境。logstash采用 *.deb方式安装&#xff0c;需要服务器能联网。ubuntu 22…

JVM对象创建与内存分配机制深度剖析

对象创建的主要流程 类加载检查 在创建对象之前&#xff0c;JVM 首先会检查该类是否已经加载、解析并初始化&#xff1a; 如果没有&#xff0c;则会通过类加载机制加载类元信息&#xff08;Class Metadata&#xff09;到方法区。 这个过程包括&#xff1a;加载&#xff08;load…