嵌入式AI---如何用C++实现YOLO的NMS(非极大值抑制)算法

news2024/9/25 7:16:00

文章目录

  • 前言
  • 一、为什么需要NMS算法?
  • 二、什么是NMS算法?
  • 三、如何使用C++编写一个NMS算法
    • 1、预测框定义
    • 2、滤除无效框
  • 总结


前言

YOLO系列的目标检测算法在边缘部署方面展现出了强大的性能和广泛的应用潜力。大部分业务场景是利用PyTorch在服务器端完成检测模型的训练,得到相应的.pt、.onnx检测模型文件。随后,对模型计算量和硬件成本进行综合考量,完成边缘计算设备选型。最后,根据不同的硬件设备,将.pt或onnx模型文件转化成适配对应硬件平台的模型文件再进行推理(如瑞芯微的rknn格式、昇腾的om格式)。
目前网上大多数资料用的是YOLOV5官方源码提供的Python推理版本,然而实际业务场景往往需要基于C++在板子上完成模型推理。这就涉及到了一些模型输入预处理,输出后处理的问题,本文将简单介绍如何利用C++实现YOLOV5的后处理NMS算法。


一、为什么需要NMS算法?

先不思考什么是NMS,先思考为什么需要引入这个算法:
以YOLOV5为例,假设YOLOV5的输入图像大小为320x320x3,那么输出特征图的大小就为40x40、20x20、10x10。输出特征图的每个点都铺设了3个锚框,故最终有(40x40+20x20+10x10)x3个预测框。实际业务场景不可能有这么多的预测目标,我们需要先基于每个框的置信度筛除一批无效预测框(这一步还不是NMS,只是基于置信度进行筛除,因为大多数框都是无效框,利用置信度可以筛除90%以上的预测框)。
在这里插入图片描述
筛除了一批预测框后,由于目标附近可能会有多个预测框的置信度较高(也就是有多个预测框同时选中了目标),因此我们需要从中选取一个作为结果输出,这就需要引入一种滤除算法消除其它预测框,YOLO中用的就是NMS。

二、什么是NMS算法?

非极大值抑制(NMS),如名字所示,目的在于抑制非极大值的预测框。那么什么是极大值呢,其实就是局部区域内可信度得分最高的预测框。NMS算法的作用就是抑制局部区域内得分较低的预测框,最后保留那个极大值预测框。
对于目标检测场景,为了解决同一个目标被多个锚框选中的问题,我们引入了非极大值抑制算法(NMS),局部区域内只保留一个得分最高的目标框。

三、如何使用C++编写一个NMS算法

1、预测框定义

typedef struct Box{
    float x;	//预测框左上角坐标x
    float y;	//预测框左上角坐标y
    float w;	//框宽
    float h;	//框高
    float score;  //得分
}Box;

假设预测框的结构体定义如上所示,Box结构体中包含了预测框的位置、大小以及该框的得分。注意(需提前处理YOLO的输出内容,将输出内容都转化为Box结构体变量,此处省略该代码)

2、滤除无效框

NMS算法的思路如下:
(1)将所有预测框按照得分从高到低进行排序。
(2)从得分最高的预测框开始,依次遍历排序后的预测框列表中的每一个预测框,计算它与列表中后续所有预测框之间的IOU值。在计算IOU后,将那些IOU值大于预设阈值的后续预测框从候选框列表中移除。
(3)完成上述步骤后,继续遍历候选框列表中的下一个预测框,重复执行上述计算IOU和剔除高重叠预测框的过程,直到候选框列表中的所有预测框都被遍历完毕。

因此,我们需要先对预测框进行排序,假设预测框全都存放在vector类对象boxVec中,那么我们需要对boxVec内的全部预测框进行排序。

bool compare(Box b1, Box b2)
{
	return b1.score>b2.score? true:false;
}
vector<Box> boxVec;
sort(boxVec.begin(), boxVec.end(), compare);

随后编写一个计算两个预测框IOU的函数:

float IOU(Box b1, Box b2)
{  
    float x1 = max(b1.x, b2.x); 	//重叠框的四个坐标
    float x2 = min(b1.x + b1.w, b2.x + b2.w); 
    float y1 = max(b1.y, b2.y);
    float y2 = min(b1.y + b1.h, b2.y + b2.h);
  
    float overlap_area = max(0.0f, x2 - x1) * max(0.0f, y2 - y1); //重叠区域大小  
    if (overlap_area == 0) return 0.0f; // 如果没有重叠,IoU为0  
  
    float union_area = b1.w * b1.h + b2.w * b2.h - overlap_area; //联合区域大小
  
    // 使用更常见的分母  
    float iou = overlap_area / union_area ;  
    return iou;  
}  

在这里插入图片描述

最后,利用排序好的boxVec和IOU函数完成无效框滤除:

size_t i = 0;  
float nms_ratio = 0.5;  
while(i < boxVec.size())  
{  
    size_t j = i + 1;  
    while(j < boxVec.size())  
    {  
        if(IOU(boxVec[i], boxVec[j]) > nms_ratio)  
        {  
            // 删除元素,并且不增加 j 的值  
            boxVec.erase(boxVec.begin() + j);  
        }  
        else  
        {  
            // 如果没有删除元素,则增加 j  
            j++;  
        }  
    }  
    i++;  
}

至此,boxVec中重叠的预测框就被滤除了。


总结

本文基于C++编写了一个简化版的NMS代码,简单介绍了相关的设计思路,实际使用可能仍需优化或存在疏漏,具体需根据业务需求动态调整代码。

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

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

相关文章

细说STM32单片机通用定时器使用输出比较功能生成PWM波的方法

目录 一、本实例测试的目的 二、硬件和CubeMX项目配置 1、硬件开发板 2、项目配置 &#xff08;1&#xff09;定时器TIM2_CH1 &#xff08;2&#xff09;时钟和Debug 三、使用比较功能生成PWM 1、启动定时器 2、TIM2_CH1通道GPIO初始化 3、下载与测试 一、本实例测试…

一,掌心里的智慧:我的 TinyML 学习之旅

从云端到掌心&#xff1a;TinyML 的故事 想象一下&#xff0c;有一天你起床&#xff0c;伸手去关闭窗边的小闹钟&#xff0c;却发现这个小家伙已经提前预判到你的醒来时间——因为它能够“听到”你昨晚的呼吸变化&#xff0c;分析出你什么时候会醒。这个场景可能听起来像科幻小…

OrionX vGPU 研发测试场景下最佳实践之Jupyter模式

在上周的文章中&#xff0c;我们讲述了OrionX vGPU研发测试场景下最佳实践之SSH模式&#xff0c;今天&#xff0c;让我们走进 Jupyter模式下的最佳实践。 • Jupyter模式&#xff1a;Jupyter是最近几年算法人员使用比较多的一种工具&#xff0c;很多企业已经将其改造集成开发工…

[C++] 剖析多态的原理及实现

文章目录 多态的概念及定义编译时多态&#xff08;静态多态&#xff09;运行时多态&#xff08;动态多态&#xff09;动态多态的原理示例&#xff1a;运行时多态 两种多态的区别 多态的实现基本条件虚函数虚函数的重写与覆盖虚函数重写的其他问题协变析构函数的重写 C11 中的 o…

【数据结构】8——图3,十字链表,邻接多重表

数据结构8——图3&#xff0c;十字链表&#xff0c;邻接多重表 文章目录 数据结构8——图3&#xff0c;十字链表&#xff0c;邻接多重表前言一、十字链表结构例子 复杂例子 二、邻接多重表&#xff08;Adjacency Multilist&#xff09;例子 前言 除了之前的邻接矩阵和邻接表 …

Kubernetes部署及示例

目录 一、实验环境 二、部署 1、添加解析 2、安装docker&#xff0c;确保登录成功 3、所有禁用swap和本地解析 4、 安装K8S部署工具 5、集群初始化 6、安装flannel网络插件 7、节点扩容 三、kubernetes 中的资源 1、资源管理介绍 2、资源管理方式 &#xff08;…

【Kubernetes】服务账号 Service Account

《K8s 的安全认证》系列&#xff0c;共包含以下文章&#xff1a; K8s 的安全框架和用户认证K8s 的鉴权管理&#xff08;一&#xff09;&#xff1a;基于角色的访问控制&#xff08;RBAC 鉴权&#xff09;K8s 的鉴权管理&#xff08;二&#xff09;&#xff1a;基于属性 / 节点…

Mac导入iPhone的照片怎么删除?快速方法讲解

随着Apple生态系统的高度整合&#xff0c;Mac与iPhone之间的照片同步和导入变得异常便捷。但这种便利有时也会带来一些管理上的困扰&#xff0c;比如Mac导入iPhone的照片怎么删除&#xff1f; 从iPhone直接删除照片 Mac导入iPhone的照片怎么删除&#xff1f;如果你的照片是通…

思维商业篇(1)—如何判断商业效率

思维商业篇(1)—如何判断商业效率 我们评价一个公司&#xff0c;很大程度上其实就是看其商业效率高不高以及规模大不大。 规模是一个企业的大小&#xff0c;效率是一个企业的节奏。 一个小企业如果效率很高&#xff0c;在未来就会有很多的机会。只要其所在行业在&#xff0c…

深入理解Python中的魔法参数 *args 和 **kwargs

在Python编程中&#xff0c;函数的灵活性是其强大之处之一。其中&#xff0c;*args 和 **kwargs 是实现函数参数可变性的重要工具。 无论我们是Python初学者还是经验丰富的开发者&#xff0c;充分理解这两个概念都有助于编写更加灵活、高效的代码。 本文将深入探讨*args和**kw…

【JavaScript】数据结构之树

什么是树形结构&#xff1f; 一种分层数据的抽象模型&#xff0c;用来分层级关系的。虚拟dom它所组织的那个数据原理就是树形结构 深度优先搜索&#xff08;遍历&#xff09;- 递归 从根出发&#xff0c;尽可能深的搜索树的节点技巧 访问根节点对根节点的children挨个进行深…

三、(JS)JS中常见的表单事件

一、onfocus、onblur事件 这个很容易理解&#xff0c;就不解释啦。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"&…

【JS|第27期】网页文件传输:Blob与Base64的对决

日期&#xff1a;2024年9月12日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

【SQL】百题计划:SQL最基本的判断和查询。

[SQL]百题计划 Select product_id from Products where low_fats "Y" and recyclable "Y";

java重点学习-JVM组成

十二 JVM 12.1 JVM运行原理 Java Virtual Machine Java程序的运行环境(java二进制字节码的运行环境) 好处: 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收机制 12.2 什么是程序计数器? 程序计数器:线程私有的&#xff08;不存在线程安全问题&#xff09;&…

美团图床设置教程

大厂图床&#xff0c;CDN加速 项目地址&#xff1a;https://github.com/woniu336/mt-img 使用方法 在mt.php填上你的token即可&#xff0c;然后打开index.html上传图片 获取token方法 注册https://czz.meituan.com/发布视频&#xff0c;上传封面&#xff0c;注意在上传封面后…

java项目之企业级工位管理系统源码(springboot)

项目简介 企业级工位管理系统实现了以下功能&#xff1a; 企业级工位管理系统的主要使用者管理员功能有个人中心&#xff0c;部门信息管理&#xff0c;工位信息管理&#xff0c;使用情况管理&#xff0c;工位分配管理。员工可以查看个人中心&#xff0c;部门信息&#xff0c;…

linux第二课(docker的安装使用)

目录 一.关于docker (1)背景引入 (2)docker介绍 (3)功能 (4)Docker架构 二.docker的安装及相关的命令 (1)docker的安装 (2)docker的配置 (3)docker镜像命令 (4)容器命令 三.docker安装myaql ​编辑 四.数据卷挂载 1.数据卷挂载引入 2.数据卷挂载图解 3.数据卷的安装…

通用四期ARM架构银河麒麟桌面操作系统V10【安装、配置FTP服务端】

一、操作环境 服务端&#xff1a;银河麒麟桌面操作系统V10SP1 &#xff08;服务端包链接&#xff1a;https://download.csdn.net/download/AirIT/89747026&#xff09; 客户端&#xff1a;银河麒麟桌面操作系统V10SP1 &#xff08;客户端包链接&#xff1a;https://downloa…

List<Map<String, Object>>汇总统计排序

开发环境&#xff1a;jdk 1.8 需求一&#xff1a; 1、统计每个小时(升序)不同事件的产品产量 2、统计不同事件&#xff08;OK 、NG&#xff09;的总产量 public static void main(String[] args) {//数据源List<Map<String, Object>> list new ArrayList<Map…