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

news/2024/9/19 0:30:29 标签: 人工智能, c++, YOLO

文章目录

  • 前言
  • 一、为什么需要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.niftyadmin.cn/n/5664765.html

相关文章

通过Java设计模式提高业务流程灵活性的策略

引言 在软件开发中&#xff0c;随着业务需求的不断变化&#xff0c;系统的灵活性成为了一个重要的考量因素。Java设计模式作为一种经过验证的解决方案&#xff0c;可以有效地提高系统的可维护性、扩展性和灵活性。本文将探讨几种关键的设计模式&#xff0c;以及它们如何帮助我…

本地连线上Redis访问不通

可能原因&#xff1a; 1、服务器没有开放 Redis的默认端口&#xff1a;6379 2、在服务器中添加访问规则 3、修改Redis的配置 修改宝塔中Redis的配置文件&#xff1a; redis配置修改: 1、requirepass是用来设置访问密码的 2、注释bind 127.0.0.1&#xff1a;改为 bind 0.0.0.0…

如何在微信小程序中实现WebSocket连接

微信小程序作为一种全新的应用形态&#xff0c;凭借其便捷性、易用性受到了广大用户的喜爱。在实际开发过程中&#xff0c;实时通信功能是很多小程序必备的需求。WebSocket作为一种在单个TCP连接上进行全双工通信的协议&#xff0c;能够实现客户端与服务器之间的实时通信。本文…

FP6296XR-G1 10A电流模式非同步PWM升压转换器芯片IC

一般说明 F1 6296是目前最先进的直流一直流转换器。是一个带有内置15mΩ功率MOSFET使此稳压器具有高功率效率。误差放大器的非逆变输入端连接到1.2V的精密基准电压。电流模式控制和外部补偿网络使系统稳定容易灵活。FP6296采用SOP-8L(EP)封装&#xff0c;可用于应用领域…

路由原理介绍

定义与过程 定义&#xff1a;是指导IP报文发送的路径信息 过程&#xff1a; 检查数据包的目的地确定信息源发现可能的路径选择最佳路径验证和维护路由信息 路由来源 直连路由&#xff1a;不需配置&#xff0c;路由器配置IP后自动生效 静态路由&#xff1a;手动配置 ip r…

A股上市公司企业创新能力、质量、效率-原始数据+dofile+结果(2006-2023年)

上市公司的创新能力体现在其不断研发新技术、新产品和服务的能力上&#xff0c;这是企业保持竞争优势的关键&#xff1b;质量则是指公司所提供的产品或服务达到高标准的程度&#xff0c;高质量是赢得客户信任和市场份额的基础&#xff1b;效率则涵盖了生产运营中的资源利用程度…

浅谈人工智能之基于ollama本地大模型结合本地知识库搭建智能客服

浅谈人工智能之基于ollama本地大模型结合本地知识库搭建智能客服 摘要 随着人工智能技术的飞速发展,基于大型语言模型(LLMs)的智能客服系统逐渐成为提升企业服务质量和效率的关键工具。然而,对于注重数据隐私和安全的企业而言,使用云服务可能会引发数据泄露的风险。因此…

【QGC】把QGroundControl地面站添加到Ubuntu侧边菜单栏启动

把QGroundControl地面站添加到Ubuntu侧边菜单栏启动 简介准备工作步骤 1: 创建 Desktop Entry 文件步骤 2: 编辑 Desktop Entry 文件步骤 3: 刷新应用程序菜单步骤 4: 将 QGroundControl 固定到侧边栏 环境&#xff1a; Ubuntu &#xff1a;20.04 LTS 简介 QGroundControl 是…