终于弄懂了 非极大抑制 NMS

news2024/11/18 20:13:56

NMS的作用就是有效地剔除目标检测结果中多余的检测框,保留最合适的检测框。

以YOLOv5为例,yolov5模型的输入三个feature map的集合,加上batch的维度,也就是三维张量,即 [ b a t c h , ( p 0 ∗ p 0 + p 1 ∗ p 1 + p 2 ∗ p 2 ) ∗ 3 , 4 + c o n f + c l s n u m ] [batch,(p0*p0+p1*p1+p2*p2)*3,4+conf+clsnum] [batch(p0p0+p1p1+p2p2)34+conf+clsnum],模型输出的为相对于调整图片的 x y w h xywh xywh,然后后面就要进入后处理阶段。

具体来看,模型输入为 640 ∗ 640 640*640 640640时,推理输出结果在 20 ∗ 20 , 40 ∗ 40 , 80 ∗ 80 20*20,40*40,80*80 2020,40408080 三个尺度上的预测框总和为 20 ∗ 20 ∗ 3 + 40 ∗ 40 ∗ 3 + 80 ∗ 80 ∗ 3 = 25200 20*20*3+40*40*3+80*80*3=25200 20203+40403+80803=25200,推理时一般一次输入一张图片,batch=1,coco数据集80类,最终的输出张量为 [ 1 , 25200 , 85 ] [1,25200,85] [1,25200,85]

非极大值抑制一般分为置信度抑制和IOU抑制

  • 置信度抑制,即根据设定阈值,从检测结果结果中剔除置信度小于阈值的检测框,保留置信度较高的检测框,这一步非常交单。
  • IOU(交并比)抑制较为复杂,如果目标检测包含多个分类,则需要对每个分类的检测框单独进行IOU抑制,以一个置信度较高的检测框为基准,与另一个同类检测框计算IOU值,如果IOU值大于设定阈值,则认为另一个检测框与基准检测框为同一目标,需要剔除该检测框。

交并比 (IOU) 如何计算?

交并比(IOU)是度量两个检测框(对于目标检测来说)的交叠程度,公式如下:
I o U = A ∩ B A ∪ B IoU = \frac{A\cap B}{A \cup B} IoU=ABAB
img

假设两个矩形框A和B的位置分别为:

A : [ x a 1 , y a 1 , x a 2 , y a 2 ] A: [x_{a1}, y_{a1}, x_{a2}, y_{a2}] A:[xa1,ya1,xa2,ya2]

B : [ x b 1 , y b 1 , x b 2 , y b 2 ] B: [x_{b1}, y_{b1}, x_{b2}, y_{b2}] B:[xb1,yb1,xb2,yb2]

假如位置关系如图3 所示:

img

如果二者有相交部分,则相交部分左上角坐标为:
x 1 = m a x ( x a 1 , x b 1 ) ,       y 1 = m a x ( y a 1 , y b 1 ) x_1 = max(x_{a1}, x_{b1}), \ \ \ \ \ y_1 = max(y_{a1}, y_{b1}) x1=max(xa1,xb1),     y1=max(ya1,yb1)

相交部分右下角坐标为:
x 2 = m i n ( x a 2 , x b 2 ) ,       y 2 = m i n ( y a 2 , y b 2 ) x_2 = min(x_{a2}, x_{b2}), \ \ \ \ \ y_2 = min(y_{a2}, y_{b2}) x2=min(xa2,xb2),     y2=min(ya2,yb2)

计算先交部分面积:
i n t e r s e c t i o n = m a x ( x 2 − x 1 + 1.0 , 0 ) ⋅ m a x ( y 2 − y 1 + 1.0 , 0 ) intersection = max(x_2 - x_1 + 1.0, 0) \cdot max(y_2 - y_1 + 1.0, 0) intersection=max(x2x1+1.0,0)max(y2y1+1.0,0)

矩形框A和B的面积分别是:
S A = ( x a 2 − x a 1 + 1.0 ) ⋅ ( y a 2 − y a 1 + 1.0 ) S_A = (x_{a2} - x_{a1} + 1.0) \cdot (y_{a2} - y_{a1} + 1.0) SA=(xa2xa1+1.0)(ya2ya1+1.0)

计算相并部分面积:
u n i o n = S A + S B − i n t e r s e c t i o n union = S_A + S_B - intersection union=SA+SBintersection

计算交并比:

I o U = i n t e r s e c t i o n u n i o n IoU = \frac{intersection}{union} IoU=unionintersection

交并比计算程序如下:

# 计算IoU,矩形框的坐标形式为xyxy,这个函数会被保存在box_utils.py文件中
def box_iou_xyxy(box1, box2):
    # 获取box1左上角和右下角的坐标
    x1min, y1min, x1max, y1max = box1[0], box1[1], box1[2], box1[3]
    # 计算box1的面积
    s1 = (y1max - y1min + 1.) * (x1max - x1min + 1.)
    # 获取box2左上角和右下角的坐标
    x2min, y2min, x2max, y2max = box2[0], box2[1], box2[2], box2[3]
    # 计算box2的面积
    s2 = (y2max - y2min + 1.) * (x2max - x2min + 1.)
    
    # 计算相交矩形框的坐标
    xmin = np.maximum(x1min, x2min)
    ymin = np.maximum(y1min, y2min)
    xmax = np.minimum(x1max, x2max)
    ymax = np.minimum(y1max, y2max)
    # 计算相交矩形行的高度、宽度、面积
    inter_h = np.maximum(ymax - ymin + 1., 0.)
    inter_w = np.maximum(xmax - xmin + 1., 0.)
    intersection = inter_h * inter_w
    # 计算相并面积
    union = s1 + s2 - intersection
    # 计算交并比
    iou = intersection / union
    return iou

bbox1 = [100., 100., 200., 200.]
bbox2 = [120., 120., 220., 220.]
iou = box_iou_xyxy(bbox1, bbox2)
print('IoU is {}'.format(iou))

IOU即为计算两个相同类别检测框的交并比。交并比即两个检测框相交区域与联合区域比值。假设两个检测框完全不相交,那么交集为0,IOU也就为0,那么可以认为两个检测框所预测为不同目标,需要保留。如果两个检测框完全重合,IOU值为1,两个检测框预测为同一个目标,那么就要剔除一个检测框。

IOU抑制代码实现

import numpy as np
 
# pred为[1,25200,85] ,conf_thres为置信度的阈值,iou_thres为iou阈值
def nms(pred, conf_thres, iou_thres):
    # 置信度抑制,小于置信度阈值的则删除
    conf = pred[..., 4] > conf_thres
    box = pred[conf == True]
    # 所有层的第5个到最后一个值,即获取所有类别的得分
    cls_conf = box[..., 5:]
    cls = []
    for i in range(len(cls_conf)):
        # 返回cls_conf[i]中最大值的索引,根据索引定位类别
        cls.append(int(np.argmax(cls_conf[i])))
    # 获取类别
    total_cls = list(set(cls))  #删除重复项,获取出现的类别标签列表,example=[0, 17]
    output_box = []   #最终输出的预测框 
    # 不同分类候选框置信度 
    for i in range(len(total_cls)):
        clss = total_cls[i]   # 当前类别标签
        # 从所有候选框中取出当前类别对应的所有候选框
        cls_box = []
        for j in range(len(cls)):
            if cls[j] == clss:
                box[j][5] = clss
                cls_box.append(box[j][:6])
        cls_box = np.array(cls_box)
        box_conf = cls_box[..., 4]   #取出候选框置信度
        box_conf_sort = np.argsort(box_conf)   #获取排序后索引
        max_conf_box = cls_box[box_conf_sort[len(box_conf) - 1]]
        output_box.append(max_conf_box)   # 将置信度最高的候选框输出为第一个预测框
        cls_box = np.delete(cls_box, 0, 0)  # 删除置信度最高的候选框
        while len(cls_box) > 0:
            max_conf_box = output_box[len(output_box) - 1]  # 将输出预测框列表最后一个作为当前最大置信度候选框
            del_index = []
            for j in range(len(cls_box)):
                current_box = cls_box[j] # 当前预测框
                interArea = getInter(max_conf_box, current_box)    
                iou = getIou(max_conf_box, current_box, interArea)  # 计算交并比
                if iou > iou_thres:
                    del_index.append(j)   # 根据交并比确定需要移出的索引
            cls_box = np.delete(cls_box, del_index, 0)   # 删除此轮需要移出的候选框
            if len(cls_box) > 0:
                output_box.append(cls_box[0])
                cls_box = np.delete(cls_box, 0, 0)
    return output_box

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

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

相关文章

SWC步骤

纲要: SWC属于AUTOSAR的Component文件夹下,而Composition属于Composition文件夹下。 目录 1. Import "Data Type" and "Interface" information 2. Creat Software Component(SWC) 3. Create "Port" for this SWC 4.…

nexus raw 仓库代理(node-sass离线安装node-sass: Command failed)

问题背景 内网环境中使用 node 构建项目,项目中依赖了 node-sass,环境自动下载 node-saas 失败(内网)。 下面是构建 node-sass 的错误代码: [5/5] Building fresh packages... error /workspace/node_modules/node-…

nuxt概念

文章目录前言nuxt项目结构介绍网页导航文字显示(商标)package.jsonnuxt.config.js路由固定路由动态路由总结前言 首先了解下B2C模式,分前后台,后台一般为管理系统,不需要展示给过多的用户,而前台需要展示给…

2023年有哪些具备潜力的加密投资标的?

随着2022年一系列的黑天鹅事件(Terra、Luna的暴雷、FTX、Three Arrows Capital等知名加密机构的破产),加密货币总市值已经从最高点的2.9万亿美元(2021年的11月),下降到8500亿美元(与2021年1月的…

NKOJ P7842 疫情防控

分析 这道题的本质就是找可以使得每座城市有且仅有一条道单行路进入该市的图有什么特点; 首先,我们假设图联通,则由于每个城市只有一条单行道可以进入,即一个城市必须有且仅有一条单行道与之配对,所以这个图至少要有nnn条边,即图中必须要有环才可以满足要求! 那如果图不连通…

Java多线程之读写锁ReentrantReadWriteLock类使用

在JDK中提供了一种读写锁ReentrantReadWriteLock类,相比ReentrantLock类,使用前者可以加快运行效率。ReentrantLock类是具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务,这样做虽然保证了…

【UE4 第一人称射击游戏】40-改变武器的可见性

上一篇:【UE4 第一人称射击游戏】39-“M4A1”武器设置本篇效果:步骤:打开“Weapon_M4A1”,删除带有“AK47”的那个骨架网格体打开事件图表,将“SkeletalMesh1”拖入打开“ThirdPersonCharacter”,在事件图表…

Docker:独具魅力的开源容器引擎

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口&#…

MATLAB-控制系统模型之间的转换

系统的线性时不变(LTI)模型有传递函数(tf)模型、零极点增益(zpk)模型和状态空间(ss)模型,它们之间可以相互转换。模型之间的转换函数可以分为以下两类。第一类是把其他类型的模型转换为函数表示的模型自身&…

PHP多进程(一)

多进程的作用是一个程序启动多个进程。 一个程序启动起来本应该是一个进程,但它可作为父进程启动多个子进程来一起操作 形成并发操作 pcntl是php官方的多进程扩展,只能在linux环境使用 以下所有操作请在Linux环境下操作: 先认识两个函数,下面是官方文档地址: …

铜缆测试——近端和远端串扰(NEXT和FNEXT)

如果您非常熟悉铜缆测试,那么很可能听说过串扰——一对或一个通道上传输的信号对另外一对或一个通道产生不良影响的现象。(杂讯) 串扰会对具体的一对导线或整根电缆形成干扰,导致误码或数据无法传输。例如,您是否曾经在电话中听到有其他人说话…

马蹄集 数组最大公约数

给定一个由N个正整数组成的数组&#xff0c;求所有数组元素的最大公约数。 格式 输入格式&#xff1a;第一行输入数组长度N,第二行输入数组元素&#xff0c;整型 空格分隔。 输出格式&#xff1a;输出整型 #include <bits/stdc.h> using namespace std;int gcd(int a…

(十八)Java的时间与日期(2)

目录 前言: 一、JDK8新增日期类 二、LocalDate&#xff0c;LocalTime,LocalDateTime 三、Instant时间戳 四、DateTimeFormatter类 五、Duration/Period类 六、ChronoUnit类 前言: JDK 8中增加了一套全新的日期时间API&#xff0c;这套API设计合理&#xff0c;是线程安全的。新的…

ctfshow学习记录-web入门(sql注入191-200)

目录web191web192web193web194web195web196web197web198web199web200九某人来更新啦&#xff1a;2023年第一篇wp新鲜出炉&#xff5e; web191 解答&#xff1a;增加了过滤 过滤了ascii&#xff0c;可以用ord方法代替。&#xff08;这里手册中也有告知~&#xff09; web190的pa…

【数据结构与算法】Trie

&#x1f600;大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#x1f62b;&#xff0c;但是也想日更的人✈。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4…

集合引用类型 下

目录 Map Map.set() Map.get() Map.delete() Map.has() Map.values() Map.entries() Map.clear() 选择Object 还是Map 数据转换 转为数组 转为 JSON 对象转为 Map 数组转为 Map 转为Object WeakMap 基本API 弱键 不可迭代 Set 创建Set实例 Set实例转数组 si…

STM32-启动文件详解

✅作者简介&#xff1a;嵌入式入坑者&#xff0c;与大家一起加油&#xff0c;希望文章能够帮助各位&#xff01;&#xff01;&#xff01;&#xff01; &#x1f4c3;个人主页&#xff1a;rivencode的个人主页 &#x1f525;系列专栏&#xff1a;玩转FreeRTOS &#x1f4ac;推荐…

python基础篇之数字类型(下)

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a;lqj_本人的博客_CSDN博客-微信小程序,前端,vue领域博主lqj_本人擅长微信小程序,前端,vue,等方面的知识https://blog.csdn.net/lbcyllqj?spm1000.2115.3001.5343 哔哩哔哩欢迎关注&…

在vue2使用百度脑图的kityminder-core进行二次开发思维导图,在源码中添加新的命令

需求说明&#xff1a;最近在搞kityminder-core的思维导图&#xff0c;需要增加一个给节点添加文件的功能&#xff0c;一直在研究源码&#xff0c;发现都是通过执行命令的方式实现的。一直卡在新增命令的步骤&#xff0c;搞了好多天了今天找到了如何在源码里新增命令&#xff0c…

leetcode 1807. 替换字符串中的括号内容【python3双指针+哈希表】实现过程分析以及思路整理

题目 给你一个字符串s&#xff0c;它包含一些括号对&#xff0c;每个括号中包含一个非空的键。 比方说&#xff0c;字符串"(name)is(age)yearsold"中&#xff0c;有两个括号对&#xff0c;分别包含键"name"和"age"。 你知道许多键对应的值&…