非极大值抑制算法(NMS)及python实现

本文详细介绍了目标检测中非极大值抑制(NMS)算法的作用及其实现过程,并通过示例展示了如何使用Python实现NMS算法,帮助读者理解NMS在去除冗余候选框中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在目标检测中,常会利用非极大值抑制算法(NMS)对生成的大量候选框进行后处理,去除冗余的候选框,得到最具代表性的结果,以加快目标检测的效率。即如下图所示,消除多余的候选框,找到最佳的bbox。
这里写图片描述

NMS算法过程

根据候选框的类别分类概率做排序: A &lt; B &lt; C &lt; D &lt; E &lt; F A&lt;B&lt;C&lt;D&lt;E&lt;F A<B<C<D<E<F

  1. 先标记最大概率矩形框F是我们要保留下来的;
  2. 从最大概率矩形框F开始,分别判断A~E与F的重叠度IOU(两框的交并比)是否大于某个设定的阈值,假设B、D与F的重叠度超过阈值,那么就扔掉B、D;
  3. 从剩下的矩形框A、C、E中,选择概率最大的E,标记为要保留下来的,然后判读E与A、C的重叠度,扔掉重叠度超过设定阈值的矩形框

就这样一直重复下去,直到剩下的矩形框没有了,标记完所有要保留下来的矩形框

NMS算法的python实现

# python3
import numpy as np

def py_nms(dets, thresh):
    """Pure Python NMS baseline."""
    #x1、y1、x2、y2、以及score赋值
    x1 = dets[:, 0]
    y1 = dets[:, 1]
    x2 = dets[:, 2]
    y2 = dets[:, 3]
    scores = dets[:, 4]

    #每一个候选框的面积
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    #order是按照score降序排序的
    order = scores.argsort()[::-1]

    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)
        #计算当前概率最大矩形框与其他矩形框的相交框的坐标,会用到numpy的broadcast机制,得到的是向量
        xx1 = 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或h算出来会是负数,用0代替
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        #计算重叠度IOU:重叠面积/(面积1+面积2-重叠面积)
        ovr = inter / (areas[i] + areas[order[1:]] - inter)

        #找到重叠度不高于阈值的矩形框索引
        inds = np.where(ovr <= thresh)[0]
        #将order序列更新,由于前面得到的矩形框索引要比矩形框在原order序列中的索引小1,所以要把这个1加回来
        order = order[inds + 1]
    return keep

# test
if __name__ == "__main__":
    dets = np.array([[30, 20, 230, 200, 1], 
                     [50, 50, 260, 220, 0.9],
                     [210, 30, 420, 5, 0.8],
                     [430, 280, 460, 360, 0.7]])
    thresh = 0.35
    keep_dets = py_nms(dets, thresh)
    print(keep_dets)
    print(dets[keep_dets])

测试结果:
在这里插入图片描述
只有第2个框与第1个框的IoU(0.38)超过了阈值,从结果看其被成功滤除掉了。NMS的大致原理和代码实现大致就是这样~

参考资料:

  1. 目标检测的几个名词
  2. faster rcnn 源码解读
<think>好的,用户想了解非极大值抑制(NMS)算法的原理和实现。我之前已经回答过关于先验框生成算法的问题,现在需要根据用户提供的引用内容来组织回答。首先,我得回顾用户提供的引用资料,确保准确引用相关内容。 用户提供的引用中,引用[1]定义了NMS的基本概念,提到它在目标检测中的应用。引用[2]和[3]分别给出了C++和Python实现注意事项,以及IoU的计算方法。引用[4]详细解释了NMS的原理,特别是滑动窗口带来的冗余检测框问题。引用[5]则提供了Python实现的参考资料。 接下来,我需要结合这些引用内容,分步骤解释NMS的原理和实现。首先,应该明确NMS的作用是去除重复的检测框,保留最可信的结果。原理部分需要说明为什么需要NMS,比如在目标检测中,多个重叠的框可能对应同一个物体,需要抑制低置信度的框。 然后,按照步骤详细描述算法流程。第一步是按置信度排序,这是引用[2]中提到的输入需要按分数从高到低排列的关键点。第二步是遍历并计算IoU,这里需要引用[3]中的IoU公式,并解释如何应用。第三步是抑制非极大值,即删除高IoU的框,这部分可以结合引用[4]中的局部极大值搜索概念。 在实现部分,用户可能希望看到Python代码示例,所以需要根据引用[3]和[5]的提示,编写一个简单的NMS函数,并注释关键步骤。同时要注意代码中的注意事项,如引用[2]提到的阈值调整和数据结构优化。 用户可能的问题包括NMS的变体、IoU的其他应用以及多类别处理,这些都需要在相关问题部分列出。同时,确保引用正确,比如在解释IoU时引用[3],在算法步骤中引用[4]。 需要检查是否有遗漏的引用内容,比如引用[1]中的NMS应用场景,可以在原理部分提到。另外,引用[2]提到的注意事项,如输入顺序和阈值调整,应该在实现注意事项中强调。 最后,确保回答结构清晰,分原理和实现两部分,代码可读性强,相关问题具有针对性。同时,使用正确的中文表达,避免技术术语错误,保持口语化但专业的语气。</think>### 非极大值抑制(NMS)算法原理与实现 #### 核心原理 非极大值抑制(NMS)是目标检测中用于去除冗余检测框的关键后处理算法。其核心思想是:**在重叠区域中仅保留置信度最高的检测框,抑制其他低置信度的冗余框**。以下是分步原理说明: 1. **冗余框产生原因** 目标检测模型(如YOLO、Faster R-CNN)可能对同一物体生成多个重叠的候选框(例如通过滑动窗口或锚框机制),这些框的置信度(score)差异较小但覆盖区域高度重叠[^4]。 2. **算法目标** 从一组重叠的候选框中,选择置信度最高的框作为代表,并抑制其他与它交并比(IoU)超过阈值的低置信度框[^1]。 3. **关键数学定义** - **交并比(IoU)**:衡量两个框的重叠程度,计算为交集面积与并集面积的比值[^3]: $$ \text{IoU} = \frac{A \cap B}{A \cup B} $$ - **抑制阈值**:通常设置为$0.5$或$0.7$,用于判定是否属于同一物体。 #### 算法流程 1. **按置信度排序** 将所有候选框按置信度从高到低排序,形成列表$B = \{b_1, b_2, ..., b_n\}$($b_1$为最高分)[^2]。 2. **迭代筛选** - 选择当前最高分框$b_i$,加入最终结果集 - 计算$b_i$与剩余所有框的IoU - 删除所有IoU超过阈值的框 - 重复上述过程直到列表为空 #### Python代码实现 ```python import numpy as np def nms(boxes, scores, iou_threshold=0.5): """ Args: boxes: 候选框坐标数组,格式为[[x1,y1,x2,y2], ...],shape=(N,4) scores: 每个框的置信度,shape=(N,) iou_threshold: 抑制阈值(默认0.5) Returns: keep_indices: 保留框的索引 """ # 按置信度降序排序 order = np.argsort(scores)[::-1] keep = [] while order.size > 0: # 取当前最高分框 i = order[0] keep.append(i) # 计算当前框与剩余框的IoU x1 = np.maximum(boxes[i, 0], boxes[order[1:], 0]) y1 = np.maximum(boxes[i, 1], boxes[order[1:], 1]) x2 = np.minimum(boxes[i, 2], boxes[order[1:], 2]) y2 = np.minimum(boxes[i, 3], boxes[order[1:], 3]) w = np.maximum(0.0, x2 - x1) h = np.maximum(0.0, y2 - y1) intersection = w * h area_i = (boxes[i, 2] - boxes[i, 0]) * (boxes[i, 3] - boxes[i, 1]) area_j = (boxes[order[1:], 2] - boxes[order[1:], 0]) * \ (boxes[order[1:], 3] - boxes[order[1:], 1]) union = area_i + area_j - intersection iou = intersection / union # 保留IoU低于阈值的框索引 inds = np.where(iou <= iou_threshold)[0] order = order[inds + 1] # +1补偿order[1:]的偏移 return keep ``` #### 关键实现细节 1. **排序重要性** 必须先将候选框按置信度降序排列,确保优先处理最可能的真实目标。 2. **IoU计算优化** 使用向量化计算替代循环,提升处理效率(如示例代码中的矩阵操作)[^3]。 3. **阈值选择** - 阈值过低(如$0.3$)可能导致漏检 - 阈值过高(如$0.8$)可能导致重复框残留 - 通常目标检测任务中取$0.5$-0.7[^4] #### 变体与改进 1. **Soft-NMS** 用连续函数衰减相邻框的分数,而非直接删除,缓解密集物体漏检问题[^5]。 2. **类别相关NMS** 对多类别检测任务,需按类别分别进行NMS处理。 --- ### 相关问题 1. 如何解决NMS在密集目标检测中的性能下降问题? 2. Soft-NMS相比传统NMS有哪些改进?数学原理是什么? 3. 在多类别目标检测中如何优化NMS的计算效率?
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值