softnms源码解读(python)

news2024/11/18 22:29:48

前言

想写这篇文章的原因是最近碰见了一个比较棘手的事情,如果想把一个目标检测模型及其相关的后处理移到嵌入式设备上,不能用c++的opencv库,也就不能用cv2.dnn.nms这个函数来进行nms的后处理,需要用c实现,那就必须了解nms的过程并手写一个c的nms,于是我去网上找了softnms的python源码尝试解读,其实softnms和nms的区别无非在nms时每个框的分数乘的权重不同,所以这篇文章也可以看作是对nms的源码解读。

思想

鉴于有些入门的人可能不了解nms,我先在这里讲一下总体过程和思想。
比如yolov5s的coco预训练权重导出的onnx模型,你会发现它的输出是一个float32[1,20160,85]向量。
1表示batch,这个基本概念就不说了。
85表示coco80个分类+4个坐标(x1,x2,y1,y2)+1个置信度(confidence)。
20160表示输出有20160个行,也就是有这么多框,那我们当然不可能把所有的框都算作我们的目标,画出来你会发现图上都是杂乱无章的框,所以就需要一个方法来帮助我们筛选掉多余的框,而nms的思想简单理解就是将每一个框和其余的框进行iou的计算,去掉超过设定iou阈限的框。
关于iou,见下图,转自wiki iou:
在这里插入图片描述
也就是两个框的重叠面积除以它们总共覆盖的面积,交集除以并集。

代码和关键问题

代码选自softnms,加了一些方便理解的print函数并去掉了tensorflow的依赖。

import numpy as np
import time


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

    # 就是在框矩阵的最后一列加上从0开始的序号
    N = dets.shape[0]
    indexes = np.array([np.arange(N)])
    dets = np.concatenate((dets, indexes.T), axis=1)
    print(f'dets is {dets}\n')
    # 顺序是y1,x1,y2,x2
    y1 = dets[:, 0]
    x1 = dets[:, 1]
    y2 = dets[:, 2]
    x2 = dets[:, 3]
    print(y1)
    print(x1)
    print(y2)
    print(x2)
    scores = sc
    print(f'scores is {scores}\n')
    areas = (x2 - x1 + 1) * (y2 - y1 + 1)
    print(f'areas is {areas}\n')
    for i in range(N):
        # 临时存储方便后面参数交换
        tBD = dets[i, :].copy()
        print(f'tBD before is{tBD}')
        tscore = scores[i].copy()
        print(f'tscore is {tscore}')
        tarea = areas[i].copy()
        pos = i + 1

        # 选取最大分数
        if i != N-1:
            maxscore = np.max(scores[pos:], axis=0)
            print(f'maxscore is : {maxscore}')
            maxpos = np.argmax(scores[pos:], axis=0)
            print(f'maxpos is : {maxpos}')
        # 这里如果是最后一位了就直接选取它自己,节省时间
        else:
            maxscore = scores[-1]
            maxpos = 0
        if tscore < maxscore:
            print(1)
            dets[i, :] = dets[maxpos + i + 1, :]
            dets[maxpos + i + 1, :] = tBD
            tBD = dets[i, :]
            print(f'dets After is{dets}')
            print(f'tBD After is{tBD}')
            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 计算
        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)
        print(ovr)
        # 三种方法: 1.linear 2.gaussian 3.原始的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:  # 原始的NMS
            weight = np.ones(ovr.shape)
            weight[ovr > Nt] = 0

        scores[pos:] = weight * scores[pos:]
        print(f'scores [pos:] is {scores[pos:]}')
    # 选择正确的box序号
    inds = dets[:, 4][scores > thresh]
    keep = inds.astype(int)

    return keep


def test():
    # 模拟数据
    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)
    print(boxes.shape)
    boxscores = np.array([0.9, 0.8, 0.7, 0.6, 0.5], dtype=np.float32)
    index = py_cpu_softnms(boxes, boxscores, method=3)
    print(index)


if __name__ == '__main__':
    test()

这里估计很多人疑惑的是这个for循环为什么搞的这么复杂,不是只要每个和其他所有框计算iou不就行了吗?
其实这就是这个代码的精妙之处,假如我像上面代码模拟的五个框,如果我是每个和其他所有框计算iou,我得计算5x4=20次
但如果我每次选取后面最大的分数,然后如果当前的分数小于它,我就把它们的位置交换,这样计算iou的次数变成了4+3+2+1=5x4/2=10次,节省了一半的时间,如果不能理解,建议自己运行一遍,这个用言语还是很难传达,得细品。
那原始nms和soft-nms的区别在代码中体现在哪里呢?
注意代码中的weights矩阵,这里的weights有三种方法选取,每次计算一遍weights后会和当前分数矩阵相乘,如果是原始nms,会把所有与它重叠分数大于阈限的值全部置为0,等于说在接下来的计算过程中那些框就被无视了,但如果是softnms,不管是linear还是gaussian,都会给框保留一定的分数,这样还能起一些作用,其实这种方法在很多算法中都有体现,但能否提高现实中模型的表现,这个是不确定的,得试过才知道。

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

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

相关文章

重磅综述|Nat Rev Gastroenterol Hepatol:人类胃肠道中的产甲烷古菌

期刊&#xff1a;Nat Rev Gastroenterol Hepatol 影响因子&#xff1a;73.082 发表时间&#xff1a;2022年9月 一、摘要 人类微生物群与人类健康和疾病密切相关。除了细菌、病毒和真核生物外&#xff0c;人类胃肠道中许多古菌与甲烷的产生有关&#xff0c;临床上可…

PMP一般要提前多久备考?

一般是1-3个月吧&#xff0c;PMP考试通过率至少有60%&#xff0c;报培训班可以有80%以上&#xff0c;不用备考太长时间&#xff0c;但时间太短也无法把项目管理的知识学完&#xff0c;1-3个月是最佳备考时间。 &#xff08;字数很多&#xff0c;都是干货&#xff0c;资料在文末…

写给Java程序员的GRPC入门系列(1)

点击上方GRPC专栏看系列 文章目录Abstract前置依赖本文初始状态创建MAVEN module修改依赖测试下一步Abstract 网上有很多GRPC的例子&#xff0c;但是却没有能够写给普通Java开发人员手把手入门少走弯路的教程。 本教程保证按照步骤一步步来你就可以完成GRPC从0到1的构建。 源码…

一文读懂机器学习常用算法的基本概念和适用场景

引用一句英国统计学家George E. P. Box的名言&#xff1a;All models are wrong, but some are useful. 没有哪一种算法能够适用所有情况&#xff0c;只有针对某一种问题更有用的算法。 机器学习算法不会要求一个问题被 100%求解&#xff0c;取而代之的是把问题转化为最优化的…

基于小程序技术栈的跨端框架有哪些?

回顾过去的几年&#xff0c;市场上的跨端开发框架一直在迭代&#xff0c;同时也有新的跨端框架冒出来。在过往的文章中&#xff0c;我们也有盘点过基于HTML5语法实现的跨端开发平台。在本篇文章中&#xff0c;就让我们盘点一下以小程序语法进行转译的跨端平台&#xff0c;以及他…

相机标定笔记(1) -- 相机模型

什么需要相机标定 我们知道&#xff0c;相机的图像是三维世界到2D平面的一个投影。仅从这个2D图像来看&#xff0c;我们无法得知图像中的物体在真实物理世界中有多大&#xff0c;距离相机的距离有多远。那么我们有没有办法从这个2D的图片结合相机的参数获得这些信息呢&#xff…

ElasticSearch-全文检索

docker 下载安装 #es镜像 docker pull elasticsearch:7.4.2 #es的可视化工具 docker pull kibana:7.4.2mkdir -p /mydata/elasticsearch/config mkdir -p /mydata/elasticsearch/dataecho "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsear…

2023年北京/成都/南宁山东DAMA-CDGA/CDGP数据治理工程师认证报名

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

制造业ERP软件如何破解企业质量管理难题?

随着生产制造企业的快速发展&#xff0c;产品的好坏&#xff0c;在很大程度上取决于产品制造的质量管理水平&#xff0c;其水平的高低直接对应产品的竞争力。许多企业都面临着质量管控能力不足、质量检验数据记录不全、部分物料追溯困难等问题&#xff0c;一旦企业的产品出现质…

异步请求池的实现

异步请求池 两种请求模式 pipline请求&#xff1a;A在一个连接上打包多个请求发送给B&#xff0c;B将这些请求的结果打包返回异步请求&#xff1a;A一个连接一个请求&#xff0c;并创建一个线程检查发送的所有请求是否有结果返回&#xff08;借助epoll&#xff09;&#xff0…

F280049C Buffered Digital-to-Analog Converter (DAC)

目录DAC15.1 Introduction15.1.1 Features15.1.2 Block Diagram15.2 Using the DAC15.2.1 Initialization Sequence 初始化顺序15.2.2 DAC Offset AdjustmentDAC偏移调整15.2.3 EPWMSYNCPER Signal EPWMSYNCPER信号15.3 Lock Registers总结代码配置 driverlib代码配置 bitfield…

Blender和C4D有哪些不同?选Blender还是C4D?

众所周知&#xff0c;Blender和Cinema 4D是美术界最著名的两个名字。在比较这两款软件的时候&#xff0c;我们要仔细的看不同的方面。因此&#xff0c;您如何知道使用哪一个以及每个的关键方面是什么&#xff0c;例如渲染、建模、社区等等&#xff01;Cinema 4D 是那些希望在电…

Doris(五)-监控、报警、优化、数据备份及恢复

目录1、监控和报警1.1、Prometheus1.2、Grafana2、优化2.1、查看 QueryProfile2.1.1、使用方式2.1.2、参数说明2.1.3、调试方式2.2、 Join Reorder2.2.1 原理2.2.2 示例2.3 Join 的优化原则2.4 导入导出性能优化2.4.1 FE 配置2.4.3 性能分析2.4.4 Broker 导入大文件2.5 Bitmap …

sharepoint 配置app id secret 用postman上传文件

配置APP ID 第一部是配置APPID&#xff0c;可以访问 https://{tenantName}.sharepoint.com/_layouts/15/appregnew.aspx 或者访问具体某个页面下的 https://{tenantName}.sharepoint.com/sites/testUpload/_layouts/15/appregnew.aspx 点击生成即可生成客户端的id和secret ti…

kubernetes控制器之StatefulSet

目录 一、无状态与有状态 1.1无状态 1.2有状态 二、StatefulSet 控制器 2.1 StatefulSet 控制器概述 2.2StatefulSet 控制器&#xff1a;网络标识 2.3StatefulSet 控制器&#xff1a;独享存储 一、无状态与有状态 Deployment控制器设计原则&#xff1a; 管理的所有Pod一…

TiDB丨Etcd API 未授权访问漏洞的修复

文章目录一、前言二、集群环境三、漏洞整改建议方案一方案二四、方案实施五、可能存在的风险六、总结一、前言 Etcd是一个采用HTTP协议的健/值对存储系统&#xff0c;它是一个分布式和功能层次配置系统&#xff0c;可用于构建服务发现系统。用于共享配置和服务发现的分布式&am…

KubeEdge云原生边缘计算公开课03——云原生边缘计算学术研究现状与趋势

KubeEdge云原生边缘计算公开课03——云原生边缘计算学术研究现状与趋势曹建农&#xff1a;Collaborative Edge ComputingEdge Computing: the Driven force of AIoTThe Emergence of AIoTEdge ComputingCurrent Research on Edge ComputingComputation at EdgeIntelligence at …

MCU-51:LED点阵屏

之前我们介绍了控制LED灯亮灭的操作&#xff0c;今天我们要介绍一下控制LED点阵屏亮灭的操作&#xff0c;8*8的LED点阵屏&#xff0c;可以理解为八行或者八列LED灯的一个组合&#xff0c;可以使用它来显示一些字体与图案。 一、点阵屏介绍 1.1 简介 LED点阵屏由若干个独立的…

八、购物车案例

一、购物车案例 1.1、使用npm i命令&#xff0c;安装依赖 1.2、编写页面布局 App.vue <template><div class"app-container"><Header></Header><Goods></Goods><Footer></Footer></div> </template>…

【直播教程】直播间没人看?5大技巧教你提升!

直播是连接店铺、品牌、产品和消费者之间的桥梁。人是视觉动物&#xff0c;店铺的产品、团队和服务是后端的内容&#xff0c;产品再好&#xff0c;团队再强大&#xff0c;前端的消费者看不到&#xff0c;背后的努力都是徒然。所以&#xff0c;在粉丝对店铺、对品牌不熟悉的情况…