softnms过程 代码

本文介绍了一种改进的目标检测算法——Soft-NMS,并提供了一个详细的Python实现。相较于传统的NMS算法直接移除重叠框,Soft-NMS通过降低重叠框的权重来保留更多潜在的有效检测结果。

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

nms为直接将iou>阈值的框全部移除,而softnms 对iou>阈值的框 降低它的权重,遍历完所有预测框之后,再通过一个阈值选择留下还是移除这个框。

import numpy as np
import cv2


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
    """

    # indexes concatenate boxes with the last column
    N = dets.shape[0]
    indexes = np.array([np.arange(N)])
    dets = np.concatenate((dets, indexes.T), axis=1)

    # the order of boxes coordinate is [y1,x1,y2,x2]
    y1 = dets[:, 0]
    x1 = dets[:, 1]
    y2 = dets[:, 2]
    x2 = dets[:, 3]
    scores = sc
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)

    for i in range(N):
        # intermediate parameters for later parameters exchange
        tBD = dets[i, :].copy()
        tscore = scores[i].copy()
        tarea = areas[i].copy()
        pos = i + 1

        #
        if i != N-1:
            maxscore = np.max(scores[pos:], axis=0)
            maxpos = np.argmax(scores[pos:], axis=0)
        else:
            maxscore = scores[-1]
            maxpos = 0
        if tscore < maxscore:
            #每次把最高score的 往上拿
            dets[i, :] = dets[maxpos + i + 1, :] #行置换,score,area也一样
            dets[maxpos + i + 1, :] = tBD
            tBD = dets[i, :]

            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 calculate
        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)

        # Three methods: 1.linear 2.gaussian 3.original 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:  # original NMS
            weight = np.ones(ovr.shape)
            weight[ovr > Nt] = 0

        scores[pos:] = weight * scores[pos:]
        # print(dets)
        # print(scores)
        plot_img(dets, scores)

    # select the boxes and keep the corresponding indexes
    inds = dets[:, 4][scores > thresh]
    keep = inds.astype(int)
    print(keep)

    return keep


# boxes and scores
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)
boxscores = np.array([0.9, 0.8, 0.7, 0.6, 0.5], dtype=np.float32)

def plot_img(boxes,score):
    img = np.ones((600, 600))
    for i, bbboxes in enumerate(boxes):
        cv2.rectangle(img, (int(bbboxes[0]), int(bbboxes[1])),(int(bbboxes[2]), int(bbboxes[3])),(0,0,255), 1)
        cv2.putText(img, str(score[i]), (int(bbboxes[0]), int(bbboxes[1])),fontFace=cv2.FONT_HERSHEY_SCRIPT_COMPLEX, fontScale=0.7, color=(0,0,244))
    win = cv2.namedWindow('image', cv2.WINDOW_NORMAL)
    cv2.imshow('image', img)
    cv2.waitKey(0)
plot_img(boxes, boxscores)

index = py_cpu_softnms(boxes, boxscores, method=1)
print(index)

我们来可视化一下,第一个是最初的权重(置信度) ,首先选择0.9这个框,计算所有与它iou>阈值的框,3个都大于,然后对他们降低权重,如下面,这里使用的线性方法

3个权重都被降低一次后

这次选择的是0.254449这个框,第一个0.9的不管,两外两个都与它重叠超过阈值,降低权重,如下图

 

然后选择0.07这个框,最后一个也是大于阈值,降低权重后

最后再来一个阈值来选择 是否留下,这里阈值是0.001 , 所以全部留下

https://github.com/DocF/Soft-NMS 参考的github代码链接

### Soft NMS 的改进方法与实现 Soft NMS 是一种对传统 Non-Maximum Suppression (NMS) 算法的优化版本,其核心思想是通过连续函数衰减重叠检测框的得分,而非直接将其置零。这种策略能够更平滑地处理多个边界框之间的关系,从而提升目标检测中的平均精度(AP)。以下是关于 Soft NMS 改进方法及其具体实现的一些分析: #### 1. 衰减函数的选择 Soft NMS 使用一个连续函数 \( f \) 来调整其他对象的检测分数 \( S_i \),基于它们与当前最大得分框 \( M \) 的交并比(IoU)。常见的衰减函数有线性函数和高斯函数两种形式。 - **线性衰减** 当 IoU 值超过一定阈值时,采用线性下降的方式降低检测框的得分[^3]。公式如下: \[ S_i = S_i \cdot (1 - d), \quad \text{其中 } d = \max(\text{IoU} - t, 0) \] 这里的 \( t \) 表示设定的 IoU 阈值。 - **高斯衰减** 另一种常用的形式是以高斯分布为基础设计衰减函数[^5]。这种方式更加灵活和平滑,定义为: \[ S_i = S_i \cdot e^{-\frac{\text{IoU}^2}{\sigma}} \] 参数 \( \sigma \) 控制衰减速率,较大的 \( \sigma \) 导致更缓慢的衰减效果。 #### 2. PyTorch 实现示例 以下是一个基于 Python 和 NumPy 的 Soft NMS 实现代码片段,展示了如何利用高斯衰减函数完成这一过程: ```python import numpy as np def soft_nms(dets, sigma=0.5, thresh=0.001): """ :param dets: 输入的检测框列表 [[x1,y1,x2,y2,score],...] :param sigma: 高斯衰减系数 :param thresh: 得分阈值 :return: 经过软 NMS 处理后的检测框索引 """ x1 = dets[:, 0] y1 = dets[:, 1] x2 = dets[:, 2] y2 = dets[:, 3] scores = dets[:, 4] areas = (x2 - x1 + 1) * (y2 - y1 + 1) order = scores.argsort()[::-1] keep = [] while order.size > 0: i = order[0] keep.append(i) 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 = np.maximum(0.0, xx2 - xx1 + 1) h = np.maximum(0.0, yy2 - yy1 + 1) inter = w * h ovr = inter / (areas[i] + areas[order[1:]] - inter) weight = np.exp(-(ovr * ovr) / sigma) scores[order[1:]] *= weight inds = np.where(scores[order[1:]] >= thresh)[0] order = order[inds + 1] return keep ``` 上述代码实现了 Soft NMS 中的核心逻辑,即通过高斯权重逐步减少重叠框的得分,最终仅保留满足条件的候选框。 #### 3. 性能优势 相比传统的硬裁剪方式,Soft NMS 提供了以下几个方面的性能改善[^1]: - 减少了因直接移除重叠框而导致的信息丢失; - 更加精细地控制不同框间的相对重要程度; - 不需要额外训练新的模型即可嵌入现有框架中。 这些特性共同作用下,在 PASCAL VOC2007 数据集上相对于 R-FCN 和 Faster R-CNN 方法分别提升了约 1.7% AP;而在 MS COCO 上也有显著增益——对于 R-FCN 达到了 1.3%,而针对 Faster R-CNN 则提高了大约 1.1%。 --- ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值