软NMS详解

一、算法介绍

软 NMS (Non-Maximum Suppression,非极大值抑制)是一种目标检测算法,它可以在减少重复框的同时保证准确率。传统的 NMS 算法会选择最高分值的框,但在多目标检测中,它可能会选择重叠较多的框。软 NMS 是通过计算 IoU(Intersection over Union,交并比)的方式来调整框的得分值,减少重叠框的选择。

下面是一个简单的软 NMS 算法实现:

def soft_nms(dets, sigma=0.5, Nt=0.3, threshold=0.001, method='linear'):
    """
    @param dets:(numpy.array) 要检测的目标框,(x1,y1,x2,y2,score)、score表示得分
    @param sigma:(float) 常量为卷积核的方差σ。
    @param Nt: IoU阈值,小于此阈值的框被过滤。
    @param threshold: score阈值,当score小于这个阈值时就不会再被考虑。
    @param method: 下降函数的类型,可选择 'linear' 或 'gaussian'

二、软 NMS 的具体实现

1、算法思路

软 NMS 的核心思路就是对所有框按照得分从大到小排序,然后依次处理每个框,计算其与后面框的 IoU 值,并按照下降函数(如线性函数或者高斯函数)的方法对其得分进行调整,最后筛选出得分高于阈值并且没有被过滤掉的框。

具体细节如下:

def soft_nms(dets, sigma=0.5, Nt=0.3, threshold=0.001, method='linear'):
    """
    @param dets:(numpy.array) 要检测的目标框,(x1,y1,x2,y2,score)、score表示得分
    @param sigma:(float) 常量为卷积核的方差σ。
    @param Nt: IoU阈值,小于此阈值的框被过滤。
    @param threshold: score阈值,当score小于这个阈值时就不会再被考虑。
    @param method: 下降函数的类型,可选择 'linear' 或 'gaussian'
    """

    N = dets.shape[0]
    pos = 0
    maxscore = 0
    maxpos = 0
    tmp = 0
    if N == 0:
        return []

    if sigma < 0.001:
        sigma = 0.001

    for i in range(N):
        # 找出得分最大的框
        maxscore = dets[i, 4]
        maxpos = i

        # if we have one box to cluster
        dets[i, 4] = 0

        # 遍历所有剩余的 box,计算它和当前 box 的 IoU 值
        pos = i + 1
        while pos  threshold:
                # 计算框的 IoU 值
                xx1 = np.maximum(dets[i, 0], dets[pos, 0])
                yy1 = np.maximum(dets[i, 1], dets[pos, 1])
                xx2 = np.minimum(dets[i, 2], dets[pos, 2])
                yy2 = np.minimum(dets[i, 3], dets[pos, 3])
                w = np.maximum(0.0, xx2 - xx1)
                h = np.maximum(0.0, yy2 - yy1)
                o = w * h / ((dets[i, 2] - dets[i, 0]) * (dets[i, 3] - dets[i, 1])
                             + (dets[pos, 2] - dets[pos, 0]) *
                             (dets[pos, 3] - dets[pos, 1]) - w * h)

                # 对得分进行调整
                if method == 'linear':
                    if o > Nt:
                        weight = 1 - o
                    else:
                        weight = 1
                elif method == 'gaussian':
                    weight = np.exp(-(o * o) / sigma)

                dets[pos, 4] = weight * dets[pos, 4]

                # 如果得分小于阈值,就把它和最后一个框位置互换,然后将 N 减 1,剔除最后一个得分低的框
                if dets[pos, 4]  threshold]

    return keep

2、下降函数的选择

软 NMS 中下降函数的选择影响着得分的调整过程。一般有两种下降函数可供选择:线性函数(linear)和高斯函数(gaussian)。

线性函数调整基于 IoU 值的得分,其计算公式如下:

if o > Nt:
    weight = 1 - o
else:
    weight = 1

其中,o 是 IoU 值,Nt 是 IoU 阈值,weight 是调整得分后的值。如果 IoU 值大于阈值 Nt,则使用线性函数进行调整;否则不进行调整,保持原来的得分。

高斯函数调整基于框之间距离的指数函数,其计算公式如下:

weight = np.exp(-(o * o) / sigma)

其中,sigma 是常量,是卷积核的方差。sigma 越大,框之间的距离越远,得分越低。

三、使用示例

下面是一个使用软 NMS 进行目标检测的示例:

import cv2
import numpy as np

# 加载模型及其配置文件
net = cv2.dnn.readNetFromDarknet("yolov3.cfg", "yolov3.weights")
classes = open("coco.names").read().strip().split("\n")
layer_names = net.getLayerNames()
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]

# 加载图片,并进行目标检测
img = cv2.imread("object.jpg")
img = cv2.resize(img, None, fx=0.4, fy=0.4)
height, width, channels = img.shape

blob = cv2.dnn.blobFromImage(img, 0.00392, (416, 416), (0, 0, 0), True, crop=False)

net.setInput(blob)
outs = net.forward(output_layers)

class_ids = []
confidences = []
boxes = []

for out in outs:
    for detection in out:
        scores = detection[5:]
        class_id = np.argmax(scores)
        confidence = scores[class_id]
        if confidence > 0.5:
            center_x = int(detection[0] * width)
            center_y = int(detection[1] * height)
            w = int(detection[2] * width)
            h = int(detection[3] * height)
            x = center_x - w // 2
            y = center_y - h // 2
            boxes.append([x, y, w, h])
            confidences.append(float(confidence))
            class_ids.append(class_id)

# 进行非极大值抑制,使用软 NMS
indices = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)

for i in indices:
    i = i[0]
    box = boxes[i]
    x = box[0]
    y = box[1]
    w = box[2]
    h = box[3]
    label = str(classes[class_ids[i]])
    confidence = confidences[i]
    color = (0, 255, 0)
    cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
    cv2.putText(img, label + " " + str(round(confidence, 2)), (x, y - 5),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

cv2.imshow("Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

四、小结

软 NMS 是一种目标检测算法,应用广泛。在处理重复的检测框时,传统的 NMS 算法可能会将得分较低的框筛选出来,导致准确率降低。而软 NMS 可以通过计算 IoU 值来调整框的得分,以减少重复框的选择,同时保证准确率。此外,软 NMS 中下降函数的选择也影响着得分的调整过程。在实际应用中,需要根据具体需求进行选择和调整。

原创文章,作者:YZGEU,如若转载,请注明出处:https://www.506064.com/n/368237.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
YZGEUYZGEU
上一篇 2025-04-12 01:13
下一篇 2025-04-12 01:13

相关推荐

  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • nginx与apache应用开发详解

    一、概述 nginx和apache都是常见的web服务器。nginx是一个高性能的反向代理web服务器,将负载均衡和缓存集成在了一起,可以动静分离。apache是一个可扩展的web…

    编程 2025-04-25
  • Python输入输出详解

    一、文件读写 Python中文件的读写操作是必不可少的基本技能之一。读写文件分别使用open()函数中的’r’和’w’参数,读取文件…

    编程 2025-04-25
  • 详解eclipse设置

    一、安装与基础设置 1、下载eclipse并进行安装。 2、打开eclipse,选择对应的工作空间路径。 File -> Switch Workspace -> [选择…

    编程 2025-04-25
  • C语言贪吃蛇详解

    一、数据结构和算法 C语言贪吃蛇主要运用了以下数据结构和算法: 1. 链表 typedef struct body { int x; int y; struct body *nex…

    编程 2025-04-25
  • Java BigDecimal 精度详解

    一、基础概念 Java BigDecimal 是一个用于高精度计算的类。普通的 double 或 float 类型只能精确表示有限的数字,而对于需要高精度计算的场景,BigDeci…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25
  • Python安装OS库详解

    一、OS简介 OS库是Python标准库的一部分,它提供了跨平台的操作系统功能,使得Python可以进行文件操作、进程管理、环境变量读取等系统级操作。 OS库中包含了大量的文件和目…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25

发表回复

登录后才能评论