NMS与Soft NMS算法解析以及numpy实现

news2024/11/18 2:56:22

1. NMS算法

1.1 什么是NMS算法

NMS全称为Non Maximum Suppression,中文意思是非极大值抑制,字面意思就是不是极大值的元素被抑制掉,其实就是筛选出局部最大值得到最优解。NMS算法被广泛运用于目标检测算法处理网络输出的边界框。

1.2 为什么在目标检测中要使用NMS算法

在目标检测中如果不是用NMS算法,则网络的输出结果就会向如下图所示,许多预测框都框住了目标,但是这些框并不是我们都想要的,我们想要的是其中框出来最好的那一个预测框。此时,我们就需要利用NMS算法去筛选出最适合的预测框。

在这里插入图片描述

1.3 在目标检测中怎么样使用NMS算法

我们以检测人脸为例,在目标检测中使用NMS算法的流程:

  1. 首先,需要通过置信度阈值消除小于阈值的预测框,比如阈值为0.5,如图下图所示,得到过滤后的预测框。

在这里插入图片描述

  1. 将所有的预测框的置信度降序排列,得到置信度最大的预测框,如下图红色框:

在这里插入图片描述

  1. 再设置一个IOU阈值,所谓IOU就是两个框面积的交并比,遍历其余的框,如果和当前最高分框的IOU大于一定阈值,我们就将框删除,如下图所示。

在这里插入图片描述

  1. 再重复1、2、3步骤,得到最终的结果。

在这里插入图片描述

Python代码如下:
代码来自:https://github.com/rbgirshick/fast-rcnn/blob/master/lib/utils/nms.py


import numpy as np

def nms(dets, thresh):
	# ------------------------------------ #
	# 获取所有预测框的左上角x1, y1、右上角x2, y2以及置信度scores
	# ------------------------------------ #
    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为最后计算保留下来预测框的下标
	# ------------------------------------ #
    keep = []
    while order.size > 0:
    	# ------------------------------------ #
    	# 取出置信度值最大的下标
    	# ------------------------------------ #
        i = order[0]
        keep.append(i)
        
        # ------------------------------------ #
    	# 计算IOU
    	# ------------------------------------ #
        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)
		# ------------------------------------ #
    	# 过滤小于IOU阈值的边界框
    	# ------------------------------------ #
        inds = np.where(ovr <= thresh)[0]
        # ------------------------------------ #
        # ovr 数组的长度比 order 数组少一个,这里将所有下标后移一位
        # ------------------------------------ #
        order = order[inds + 1]

    return keep

2. Soft NMS算法

2.1 什么是Soft NMS算法

Soft NMS是对NMS的优化算法,它在不增加额外参数的情况下且只需要对NMS算法进行简单的改动就能提高AP。该Soft-NMS算法在标准数据集PASCAL VOC2007(较R-FCN和Faster-RCNN提升1.7%)和MS-COCO(较R-FCN提升1.3%,较Faster-RCNN提升1.1%)上均有提升。

Soft NMS的主要思想

如下图所示,假设重叠的阈值为 0.5,图 中当黑框与红框比较时,两者之间的IoU为0.51,则红框将被删除,即使置信度高于许多其他 IoU 较小的框。因此,如果有两个并排的对象,则其中一个将被消除,这会降低模型的精度。

NMS与Soft NMS都有一个共同点,都是从置信度最大的框开始逐渐迭代的。

在这里插入图片描述

因此,Soft NMS则不再是直接将大于重叠的阈值的框删除,而是根据重叠程度衰减框的置信度得分,再根据设定的置信度阈值,去除小于置信度阈值的框。

改变置信度的方法有两种:

  1. 线性法

如下公式:
其中, i o u ( M , b i ) iou(M, b_i) iou(M,bi)代表最大置信度得分的框 M M M与第 i i i个框 b i b_i bi的IOU, N t N_t Nt代表重叠的阈值, s i s_i si代表第 i i i个框的置信度得分 s i s_i si

在这里插入图片描述

通过分析可以得出,当重叠的IOU增大时,置信度得分确实得到线性的下降。

  1. 高斯法

如下公式:
其中: i o u ( M , b i ) iou(M, b_i) iou(M,bi)代表最大置信度得分的框 M M M与第 i i i个框 b i b_i bi的IOU, σ \sigma σ为一个可设定的常数, s i s_i si代表第 i i i个框的置信度得分 s i s_i si

在这里插入图片描述

通过分析可以得出,当重叠的IOU增大时,置信度得分确实下降了。

如下图是原论文中Soft NMS在R-FCN中 N t N_t Nt σ \sigma σ的变化对AP的影响。

在这里插入图片描述

2.2 代码实现:

参考代码:https://github.com/DocF/Soft-NMS/blob/master/soft_nms.py

import numpy as np



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:
            dets[i, :] = dets[maxpos + i + 1, :]
            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:]

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

    return keep

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

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

相关文章

浅谈Linux内核页面换入换出

【推荐阅读】 浅谈linux 内核网络 sk_buff 之克隆与复制 深入linux内核架构--进程&线程 了解Docker 依赖的linux内核技术 怎么在Windows下使用Makefile文件 浅析linux内核网络协议栈--linux bridge 0x00内存页面分类与换入换出规则 内存页面分为用户页面和内核页面。…

GDT践行(第一期):起床---运动--阅读

这里记录每周GDT践行记录.【2022】年第【51】周的第【6】天 封面图 第三部分&#xff1a;起床---运动--阅读 ❝ 小贴士&#xff1a; 在学校&#xff0c;出租房&#xff0c;宾馆&#xff0c;工位很多因素导致 学习区&#xff0c;运动区 卧室 都是同一个地方 环境导致你彻底彻底糊…

[附源码]Python计算机毕业设计Django课程在线测评系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

JVM部分知识点

目录 JVM主要组成部分及其作用&#xff1f; JAVA程序运行机制详情 JVM运行时的数据区 堆和栈的区别&#xff1f; Java垃圾回收机制 Java中有哪些引用类型&#xff1f; 如何判断对象是否可以被回收&#xff1f; JVM中的永久代会发生垃圾回收吗&#xff1f; JVM有哪些垃圾…

我国航空煤油行业发展趋势:燃油附加费复收 或将缓解企业经营压力

根据观研报告网发布的《中国航空煤油市场现状深度研究与投资前景分析报告&#xff08;2022-2029年&#xff09;》显示&#xff0c;航空煤油是石油产品之一&#xff0c;别名无臭煤油&#xff0c;主要由不同馏分的烃类化合物组成。航空煤油密度适宜&#xff0c;热值高&#xff0c…

【C语言】浮点型的存储方式

目录 一、浮点型和整型存储方式一样吗&#xff1f; 二、浮点型的存储规则 2.1 S&#xff0c;M&#xff0c;E求法 2.2 如何存放&#xff33;&#xff0c;&#xff2d;&#xff0c;&#xff25; 2.2.1 IEEE 754规定 2.2.2 特别的规定 2.2.3 验证 2.3 取出规则 2.3…

改造冰蝎马,实现免杀之default_aes php

本专栏是笔者的网络安全学习笔记&#xff0c;一面分享&#xff0c;同时作为笔记 文章目录 文章目录文章目录前文链接前言效果目标密码验证功能免杀后话前文链接 WAMP/DVWA/sqli-labs 搭建burpsuite工具抓包及Intruder暴力破解的使用目录扫描&#xff0c;请求重发&#xff0c;漏…

[附源码]Python计算机毕业设计黑格伯爵国际英语贵族学校官网Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

5G无线技术基础自学系列 | 单站点验证概述

素材来源&#xff1a;《5G无线网络规划与优化》 一边学习一边整理内容&#xff0c;并与大家分享&#xff0c;侵权即删&#xff0c;谢谢支持&#xff01; 附上汇总贴&#xff1a;5G无线技术基础自学系列 | 汇总_COCOgsta的博客-CSDN博客 单站点验证是指在基站硬件安装调试完成…

RNA-seq 详细教程:可视化(12)

学习内容 了解如何为可视化准备数据了解如果利用可视化来探索分析结果火山图可视化热图可视化可视化结果 当我们处理大量数据时&#xff0c;以图形方式显示该信息以获得更多信息&#xff0c;可能很有用。在本课中&#xff0c;我们将让您开始使用探索差异基因表达数据时常用的一…

【数电实验】移位寄存器与计数器

实验四 移位寄存器与计数器 一 实验目的 1 掌握任意进制计数器的构成方法&#xff1b; 2 熟悉双向移位寄存器的使用方法。 二 实验内容 1 任意进制计数器的构成方法&#xff1a; 用中规模集成计数器74HC161和与非门74LS00&#xff0c;构成十进制计数器。要求分别使用同步预…

精华推荐 | 【深入浅出RocketMQ原理及实战】「性能原理挖掘系列」透彻剖析贯穿RocketMQ的事务性消息的底层原理并在分析其实际开发场景

什么是事务消息 事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败。RocketMQ的事务消息提供类似 X/Open XA 的分布事务功能,通过事务消息能达到分布式事务的最终一致。 事务消息所对应的场景 在一些对…

docker学习笔记(五)单个服务镜像部署

引言 当前微服务项目已经大面积普及&#xff0c;对于新需求迭代上线有许多疑惑的部分&#xff0c;比如线上的某些功能不能重启&#xff0c;在这种情况下我们需要部署和启动项目就不能搞大范围重启或干脆重新制作镜像&#xff0c;这种方式都是不可取的&#xff0c;这时候就需要…

重学webpack系列(二) -- webpack解决的问题与实现模块化的具体实践

只是根据几个想法&#xff0c;我们便创造出了webpack打包工具&#xff0c;它能够根据我们在前端项目中遇到的疑难杂症对症下药&#xff0c;那么这一章我们就一起来探讨一下我们项目落地所遇到的种种问题。 前端实践中的问题 Jsx / Tsx编译问题Less / Scss编译问题TypeScript编…

【Pintos】实现自定义 UserProg 系统调用 | 添加 syscall-nr 系统调用号 | 编写新的参数调用宏

&#x1f4ad; 写在前面&#xff1a;本文讲解的内容不属于 Pintos 的 Project 项目&#xff0c;而是关于 userprog 如何添加系统调用的&#xff0c;学习如何额外实现一些功能到系统调用中以供用户使用。因为涉及到 src/example 下的Makefile 的修改、lib 目录下 syscall-nr 系统…

门诊排队叫号系统,有序叫号就诊,适用医院医院、门诊部、诊所等

排队叫号系统&#xff0c;是将互联网信息技术与门诊预约、签到、提醒、叫号、接诊等环节相结合&#xff0c;实现门诊流程式便捷叫号服务。 为助力门诊营造一个良好有序的就诊环境&#xff0c;打造科学合理的就诊流程&#xff0c;今天给大家推荐一款一款便捷排队叫号系统&#x…

Linux基本权限(2)

Linux基本权限(2) &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;Linux &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要讲解了目录权限&#xff0c;和目录&#…

2022年底,我手里一共负责了30套系统

2022年真是不平凡的一年&#xff0c;往常熙熙攘攘的办公室人越来越少&#xff0c;真是像曹操说的兄弟相继凋零&#xff0c;好似风中落叶啊。 结果人少了&#xff0c;手里的系统一个没少&#xff0c;慢慢年底了&#xff0c;我汇总了一下&#xff0c;手里的系统达到了30来个。 搞…

Linux--基础IO

目录 C文件IO 系统文件IO 接口介绍 系统调用和库函数 文件描述符 open返回值 文件描述符的分配规则 重定向 代码演示 使用dup2系统调用 缓冲区 FILE 理解文件系统 文件系统 inode 软硬链接 静态库和动态库 概念 生成静态库 生成动态库 C文件IO 写文件 #in…

SpringBoot+Prometheus+Grafana 实现自定义监控

1.Spring Boot 工程集成 Micrometer 1.1引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency><groupId>io.micrometer<…