- Published on
NMS 是什么
NMS (Non-Maximum Suppression) 分析
什么是 NMS?
NMS 是 Non-Maximum Suppression(非极大值抑制) 的缩写。
NMS 的作用
YOLO 等目标检测模型会产生很多个检测框,可能:
同一个物体被检测多次
- 模型可能对同一个物体输出多个重叠的检测框
- 每个框都有不同的置信度
检测框位置接近
- 多个框几乎在同一个位置
- 只需要保留最好的一个
NMS 的工作原理
输入: 同一个物体的多个检测框
[框A: 置信度 0.95] ─┐
[框B: 置信度 0.90] ─┼── 重叠度高
[框C: 置信度 0.85] ─┘
NMS 处理后:
[框A: 置信度 0.95] ← 保留置信度最高的
[框B, 框C] ← 被抑制/删除
算法流程
- 按置信度降序排序检测框
- 保留置信度最高的框
- 删除与已保留框重叠度(IoU)超过阈值的框
- 重复直到所有框处理完毕
代码中的实现
位置: src/nodes/processing.rs:348-414
pub fn non_maximum_suppression(
boxes: Vec<DetectionBox>,
iou_threshold: Option<f32>, // IoU 阈值,默认 0.5
confidence_threshold: Option<f32>, // 置信度阈值,默认 0.0
) -> Vec<DetectionBox> {
let iou_thresh = iou_threshold.unwrap_or(0.5);
// 先过滤低置信度的框
let boxes: Vec<DetectionBox> = boxes
.into_iter()
.filter(|b| b.confidence >= conf_thresh)
.collect();
// 按标签分组
// 对每个标签分别进行 NMS
// ... 按置信度降序排序
// ... 保留最高置信度的框,抑制重叠框
}
调用位置
位置: src/pipeline.rs:520-524
// 应用 NMS 去除重叠的检测框(背景误检框通常与真实框重叠)
// IoU 阈值 0.5,置信度阈值 0.75(过滤低置信度的背景误检)
let nms_boxes = crate::nodes::processing::non_maximum_suppression(
filtered_boxes,
Some(0.5), // IoU 阈值
Some(0.76), // 置信度阈值(提高到 0.75 过滤背景误检)
);
为什么需要 NMS?
没有 NMS 的情况
一个物体 → 5 个重叠的检测框 → UI 显示 5 个相同的标签
有 NMS 的情况
一个物体 → 5 个重叠的检测框 → NMS 后保留 1 个最好的 → UI 显示 1 个标签
快速移动物体的问题
当物体快速斜着通过 ROI 时:
YOLO 可能在不同帧检测到多个框
- 框 A(帧1):物体在 ROI 边缘,IoU 0.3
- 框 B(帧2):物体在 ROI 中心,IoU 0.7
- 框 C(帧3):物体离开 ROI,IoU 0.2
如果 NMS 的 IoU 阈值(0.5)太高
- 框 A 和 框 B 重叠度高,可能有一个被抑制
- 框 B 和 框 C 重叠度高,可能有一个被抑制
- 导致关键帧的检测丢失
参数调优建议
1. 降低 NMS IoU 阈值
// 当前配置
Some(0.5), // IoU 阈值
// 建议改为
Some(0.2) or Some(0.3) // 保留更多检测框
优点: 减少漏检,特别是快速移动的物体 缺点: 可能会有少量重复检测
2. 调整置信度阈值
// 当前配置
Some(0.76), // 置信度阈值
// 根据实际需求调整
Some(0.5) or lower // 允许更多低置信度检测通过
3. 帧间检测框跟踪
更高级的方案是使用帧间跟踪(如 DeepSORT、ByteTrack):
- 基于运动轨迹关联不同帧的检测框
- 即使某一帧漏检,也能通过跟踪保持检测
- 适合快速移动的物体场景
总结
- NMS 是目标检测后处理的标准步骤
- 用于去除重复检测,保留最佳结果
- IoU 阈值(默认 0.5)控制重叠检测的抑制程度
- 置信度阈值(默认 0.76)过滤低质量检测
- 快速移动物体可能需要降低 IoU 阈值以减少漏检
THE END