当前位置: 首页 > news >正文

基于c++的yolov5推理之前处理详解及代码(一)

目录

一、前言:

二、关于环境安装:

三、首先记录下自己的几个问题

  问题:c++部署和python部署的区别?

四、正文开始

  4.1 图像预处理讲解

  1、BGR---->RBG

  2、等比例放缩图片(涉及到短边的填充)

  3、归一化

  4、HWC---->NCHW

  5、将图像转为一维向量格式并将整理为连续内存

  4.2图像内存开辟与传递


一、前言:

  之前实现了基于win环境中的python的加速部署过程,现在将c++实现过程进行记录,这次记录会非常详细。总的来说只要整个过程的思路捋清楚,保证思路是正确的,做起工作来就比较有方向性,开始记录。

二、关于环境安装:

  环境:wsl2+Ubuntu2004+cuda113+cudnn8.9.5.30+tensrort8.6.1.6+opencv4.2.0

  主要要安装的是cuda和cudnn和tensorrt。确定好版本,我本地cuda是11.7,cuda可以向下兼容,所以我wsl中使用11.3也是支持的。参考博客:【教程】Install NVIDIA TensorRT on WSL 在WSL上安装英伟达TensorRT_wsl tensorrt-CSDN博客,win11 WSL ubuntu安装CUDA、CUDNN、TensorRT最有效的方式-CSDN博客,这两个博客互补一下。

  tips:1、安装位置最好新建一个文件夹,放在一起,在设定环境变量的时候会方便些。

   2、opencv4版本会和libtorch1.10冲突,如果没有装libtorch之前opencv是好的,装了libtorch发现这两个库都用不了,大概率是版本冲突了(一踩坑,心态崩了一天时间,sad)但是不用libtorch也完全不影响推理。

三、首先记录下自己的几个问题

  问题:c++部署和python部署的区别?

    我最开始个人理解可能c++会更多设计自己手动开辟回收内存,在我实现c++部署之后,会过头看python实现过程,发现python也是手动开辟回收内存的,所以他们最重要的区别到底在哪里呢?

    回答:最重要的东西确实还是内存管理上,然后自然而然的会影响性能,还有系统集成中。      在内存管理方面:

        1、C++版本需要显式地管理所有资源的生命周期,包括内存分配和释放。

        2、Python版本虽然也进行了一些手动内存管理,但仍然依赖于Python的垃圾回收机制来处理大部分对象的清理。

        3、C++版本提供了更细粒度的控制,可以精确地控制何时分配和释放资源。

        4、Python版本在语法上更简洁,并且某些资源管理被抽象化,使得代码更容易编写和维护。

      性能方面:我理解在一些计算开销没有非常限制的情况下,或者执行次数不多的情况下两者区别不会拉太卡,但是涉及到性能的极致使用的情况下,肯定是c++性能要高出python。

        1、C++:通常能提供更高的性能,尤其是在低延迟场景中。直接编译为机器码,没有解释器开销。

        2、Python:有解释器开销,但在许多情况下,性能差异可能不明显,特别是当大部分计算都在GPU上进行时。

      生态集成方面:

        python更加依赖于python开发环境,而c++可以编译为动态库,限制更少一些。总的来说在工业应用中肯定吃c++更加方便些。

四、正文开始

  前处理主要分为两部分,第一部分是对image的格式的转换,即cv::imread读取上来的单张图片要转为符合深度学习torch中dataload中读取上来的nchw格式的数据。第二部分就是将这样格式的数据从cpu传输到GPU中。第二部分相对操作固定一些。

  Opencv读取图片格式转换为深度学习图片输入格式

  一般有两方面需要转换,第一方面是格式,第二方面是尺寸。一般来说应该是先进行格式转换,然后在进行尺寸变化,因为尺寸变化要是涉及到放缩的话,uint8的数据空间可能会一点,可能会有一些精度的损失。

  使用opencv中cv::imread读取上来的image一般保存在cv::Mat中,OpenCV 中的 cv::Mat 格式如下:

  1. 数据类型cv::Mat 默认使用 8 位无符号整数(CV_8U)存储图像数据。

  2. 通道顺序cv::Mat 默认使用 BGR 顺序存储图像通道。

  3. 形状cv::Mat 通常具有二维或三维矩阵结构,对应于 (height, width, channels)

  而深度学习一般需要的输入数据格式如下:

  1. 数据类型:深度学习模型通常使用 32 位浮点数(float32)存储图像数据。

  2. 通道顺序:深度学习模型通常使用 RGB 顺序存储图像通道。

  3. 形状:深度学习模型的输入形状通常为 (batch_size, channels, height, width),即 NCHW 格式。

  以上是格式方面的区别,往往还有尺寸方面的区别。yolov5一般要求输入尺寸大小为640*640大小。我们还需要将图片进行缩放。注意:是等比例缩放。

  前处理流程和代码

  4.1 图像预处理讲解

  首先创建处理图像的函数:

cv::Mat preImage(cv::Mat& rawBGRImage,int inputH, int inputW)

  我们创建一个preImage的函数,返回类型是cv::Mat类型,参数输入是一个cv::Mat类型的rawBGRImage的引用,同时输入两个整数,代表深度学习输入的大小,这里为640*640。

  第一步:

  1、BGR---->RBG

// BGR --> RGBcv::cvtColor(oriImage,image,cv::COLOR_BGR2RGB);

  2、等比例放缩图片(涉及到短边的填充)

首先获得原始图像的h和w;假设1280*1920int ori_h = oriImage.rows;int ori_w = oriImage.cols;std::cout<<"原始图片的size是"<<oriImage.size<<std::endl;
两边不一样长的图片要保证长边缩小到640,短边进行填充操作。// 取最小的因子,以保证长的一边被正确缩放,短边过度缩放可在后面使用padding填充// 这两个结果肯定小于1,使用整除会将结果截断为0double r = std::min(static_cast<double>(inputH) / ori_h, static_cast<double>(inputW) / ori_w);  std::cout<<"缩放因子 r 是"<< r <<std::endl;int new_h = std::round(ori_h * r);//四舍五入int new_w = std::round(ori_w * r);std::cout<<"新图片的size是"<<new_h <<","<<new_w<<std::endl;
计算填充大小,640减去新图像的边长//计算padding的大小,int dh = inputH - new_h;int dw = inputW - new_w;std::cout<<"需要填充的size是"<<dh <<","<<dw<<std::endl;// 使用双线性插值将图像进行等比例缩放cv::resize(image,image,cv::Size(new_h,new_w),0, 0, cv::INTER_LINEAR);
此时得到了一幅(427,640)的图像,需要对h边进行填充 //判断是否需要填充   if(dh > 0 || dw > 0){cv::resize(image,image,cv::Size(new_h,new_w),0, 0, cv::INTER_LINEAR);
计算填充的像素// Pad the short side with (128,128,128)int top = dh / 2;int bottom = dh - top;int left = dw / 2;int right = dw - left;std::cout<<"方框是"<<top <<","<<bottom<<","<<left<<","<<right<<std::endl;
进行填充,其中top,bottom,left,right等代表填充到图像上下左右的像素行数//扩充边界cv::copyMakeBorder(image, image, left, right, top, bottom, cv::BORDER_CONSTANT, cv::Scalar(128, 128, 128));std::cout<<"扩充边界之后的图片的size是"<<image.size<<std::endl;}
得到一幅填充到640*640大小的图像

  3、归一化

image.convertTo(image, CV_32F); //自动转,如果原图是32f,只拷贝,不做转换。image /= 255.0; // 8u转32f之后,原始像素值还是不变的,只是可表示范围变大了。

  4、HWC---->NCHW

// HWC to CHW format:并处理成cv中的dnn多维格式数据,类似于tensor?cv::Mat imageCHW;cv::dnn::blobFromImage(image, imageCHW, 1.0, cv::Size(), cv::Scalar(), false, false);//这种缩放会影响图像精度//该函数默认bs维度=1。cv::dnn::blobFromImages函数可以自由设定bs维度的值std::cout << "NCHW shape: " << imageCHW.size << std::endl;

    函数介绍:

    cv::dnn::blobFromImage 函数是 OpenCV 中的一个实用工具,用于将图像转换为深度学习模型所需的多维格式(通常是 NCHW,即 batch size、channels、height、width)。这是深度学习中常用的数据格式。

cv::Mat blobFromImage(const cv::Mat& image, //输入图像double scalefactor = 1.0, //缩放因子,用于缩放图像的每个像素值。默认值是 1.0const cv::Size& size = cv::Size(),//目标图像的大小。cv::Size(width, height) 格式。如果为 Size(),则保持原始图像大小。const cv::Scalar& mean = cv::Scalar(),//用于减去的均值向量,cv::Scalar(mean_r, mean_g, mean_b) 格式。用于均值归一化。bool swapRB = false,//是否交换R和B通道bool crop = false,//是否在缩放后裁剪图像。如果设置为 true,则图像会被裁剪以适应目标大小int ddepth = CV_32F//默认32位
);

  5、将图像转为一维向量格式并将整理为连续内存

    //此处还待确认,是否一定需要转为一维向量。实际测试下来发现转或不转都可以识别。

    cv::Mat imageNCHW = imageCHW.reshape(1, 1);std::cout << "zuihou d  NCHW shape: " << imageNCHW.size << std::endl;// Convert the image to row-major order, also known as "C order":// 复制矩阵 转换位行主序(C order)存储。意味着数据在内存中是按行连续存储的// 某些深度学习框架或推理引擎可能要求输入数据是连续存储的cv::Mat imageRowMajor;imageNCHW.copyTo(imageRowMajor);

  4.2图像内存开辟与传递

    首先设定图像大小并计算数据缓存区,然后将数据从cpu复制到gpu。

// 图像前处理函数实现
void YoLov5TRT::preprocessImage(const cv::Mat& image, float* gpu_input) {cv::Mat Image = image;// preImage函数中对图片进行详细前处理cv::Mat risezed_image = preImage(Image, H, W);size_t image_size = risezed_image.total() * risezed_image.channels(); // 计算输入大小,用来分配缓存区std::vector<float> input_data(image_size); // 分配输入数据缓冲区// 5. 使用 memcpy 复制数据std::memcpy(input_data.data(), risezed_image.data, image_size * sizeof(float));// 6. 异步复制数据到 GPUcudaMemcpyAsync(gpu_input, input_data.data(), image_size * sizeof(float), cudaMemcpyHostToDevice, stream_);
}

相关文章:

基于c++的yolov5推理之前处理详解及代码(一)

目录 一、前言&#xff1a; 二、关于环境安装&#xff1a; 三、首先记录下自己的几个问题 问题&#xff1a;c部署和python部署的区别&#xff1f; 四、正文开始 4.1 图像预处理讲解 1、BGR---->RBG 2、等比例放缩图片&#xff08;涉及到短边的填充&#xff09; 3、归一化…...

Oracle(55)什么是并行查询(Parallel Query)?

并行查询&#xff08;Parallel Query&#xff09;是数据库管理系统中的一种查询优化技术&#xff0c;它允许数据库引擎同时使用多个处理器或线程来执行查询操作。通过将查询任务分解为多个子任务&#xff0c;并在多个处理器上同时执行这些子任务&#xff0c;可以显著提高查询的…...

关于 Lora中 Chirp Spread Spectrum(CSS)调制解调、发射接收以及同步估计的分析

本文结合相关论文对CSS信号的数学形式、调制解调、发射接收以及同步估计做了全面分析&#xff0c;希望有助于更好地理解lora信号 long-range (LoRa) modulation, also known as chirp spread spectrum (CSS) modulation, in LoRaWAN to ensure robust transmission over long d…...

Java - API

API全称"Application Programming Interface"&#xff0c;指应用程序编程接口 API&#xff08;JDK17.0&#xff09;链接如下 : Overview (Java SE 17 & JDK 17) (oracle.com)https://docs.oracle.com/en/java/javase/17/docs/api/中文版&#xff1a; Java17中…...

力扣 3152. 特殊数字Ⅱ

题目描述 queries二维数组是nums数组待判断的索引区间&#xff08;左闭右闭&#xff09;。需要判断每个索引区间中的nums相邻元素奇偶性是否不同&#xff0c;如果都不同则该索引区间的搜索结果为True&#xff0c;否则为False。 暴力推演&#xff1a;也是我最开始的思路 遍历q…...

识别和缓解软件安全威胁的最佳工具

软件安全威胁会给企业带来重大损失&#xff0c;从经济损失到声誉受损。 企业必须主动识别和缓解这些威胁&#xff0c;防止它们造成危害。 幸运的是&#xff0c;有许多工具可以帮助企业识别和缓解软件安全威胁。 在本博客中&#xff0c;我们将探讨识别和缓解软件安全威胁的顶…...

Linux下的压缩与解压:掌握核心命令行工具

目录 一.前言 二.压缩文件概述 三.tar&#xff1a;Linux 的通用归档工具 常用 tar 命令 四.gzip&#xff1a;强大的压缩程序 常用 gzip 命令 五.zip 和 unzip&#xff1a;处理 ZIP 压缩文件 常用 zip 和 unzip 命令 实用技巧和最佳实践 六.结语 一.前言 在 Linux …...

BGP选路实验

要求&#xff1a; 1.如图连接网络&#xff0c;合理规格IP地址&#xff0c;AS200内IGP协议为OSPF&#xff1b; 2.R1属于AS 100&#xff1b;R2-R3-R4小AS234、R5-R6-R7小AS567&#xff0c;同时声明大AS 200&#xff0c;R8属于AS300&#xff1b; 3.R2-R5、R4-R7之间为联邦EBGP邻居…...

白骑士的C#教学高级篇 3.3 网络编程

网络编程是现代应用程序开发中至关重要的一部分。C# 提供了一套丰富的 API 来处理基本网络通信、Web请求与响应。在本节中&#xff0c;我们将深入探讨这些内容&#xff0c;帮助您掌握如何在 C# 中进行网络编程。 基本网络通信 基本网络通信通常涉及套接字&#xff08;Socket&a…...

AI大模型赋能游戏:更智能、更个性化的NPC

参考论文&#xff1a;https://arxiv.org/abs/2403.10249 在传统游戏中&#xff0c;NPC&#xff08;非玩家角色&#xff09;的行为往往是预先设定好的&#xff0c;缺乏灵活性和变化性。然而&#xff0c;基于大模型的NPC可以利用其强大的推理和学习能力&#xff0c;实时生成对话…...

pymysql的上下文管理器:简化数据库操作

pymysql的上下文管理器&#xff1a;简化数据库操作 当我们使用 pymysql 操作数据库时&#xff0c;管理数据库连接和游标的生命周期是一项重要的任务。Python 的上下文管理器提供了一种优雅的方式来处理资源的获取和释放。在本文中&#xff0c;我们将探索如何创建一个简单的 py…...

AI秘境-墨小黑奇遇记 - 修炼成神经(二)

在解开了感知机和门电路的谜题后&#xff0c;墨小黑对人工智能的世界渐渐产生了浓厚的兴趣。他开始意识到&#xff0c;自己不仅是在学习一门复杂的技术&#xff0c;更是在探索一个充满未知与挑战的神秘领域。 入夜&#xff0c;墨小黑一脸无奈地盯着电脑屏幕&#xff0c;思考着自…...

计算机网络之分组交换时延的计算

一.类型 分组交换的时延包括一下几种&#xff1a; 1.1发送时延 发送时延&#xff0c;也叫传输时延&#xff0c;结点将分组的所有比特推向链路所需要的时间&#xff0c;即从发送分组的第一个比特算起&#xff0c;到该分组的最后一个比特发送完为止。 发送时延 分组长度 / 发…...

虚幻5|入门AI行为树,建立敌人

本章分成两块部分一块是第一点的制作一个简单的AI&#xff0c;后面第二点之后是第二部分建立ai行为树。这两个部分是一个衔接&#xff0c;最好不要跳看 一&#xff0c;制作一个简单的AI 1.首先&#xff0c;我们创建一个敌人的角色蓝图&#xff0c;添加一个场景组件widget用于…...

ARM处理架构中的PMU(Performance Monitoring Unit)和 AMU(Activity Monitors Unit)简介

在 ARM 架构中,PMU(Performance Monitoring Unit)和 AMU(Activity Monitors Unit)是用于性能分析和监控的硬件单元,但它们的功能和应用场景有所不同。以下是它们的主要区别: 1. PMU (Performance Monitoring Unit) 功能:PMU 是一种用于监控处理器性能的硬件单元。它可…...

Service服务在Android中的使用

目录 一&#xff0c;Service简介 二&#xff0c;Service的两种启动方式 1&#xff0c;非绑定式启动Service 2&#xff0c;绑定式启动Service 三&#xff0c;Service的生命周期 1&#xff0c;非绑定式Service的生命周期 2&#xff0c;绑定式Service的生命周期 四&#xf…...

浅谈C语言位段

1、位段的定义 百度百科中是这样解释位段的: 位段&#xff0c;C语言允许在一个结构体中以位为单位来指定其成员所占内存长度&#xff0c;这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。 以下&#xff0c;我们均在VS2022的…...

arcgisserver登陆信息不正确

密码明明对&#xff0c;但是登录提示登录信息不正确 Arcgis server 9.3.1 无法登录ArcGIS Manager 提示Incorrect Login Information 操作系统windows 2008 x64server 解决办法&#xff1a; 关闭window防火墙解决。 如果防火墙已经关闭&#xff1a; 通过修改用户口令后就可以重…...

KOLA: CAREFULLY BENCHMARKING WORLD KNOWLEDGE OF LARGE LANGUAGE MODELS

文章目录 题目摘要简介KOLA 基准实验评估结论和未来工作道德声明 题目 KOLA&#xff1a;仔细对大型语言模型的世界知识进行基准测试 论文地址:https://arxiv.org/abs/2306.09296 项目地址:https://github.com/ranahaani/GNews 摘要 大型语言模型 (LLM) 的卓越性能要求评估方法…...

Robot Operating System——机器人关节的角度、速度和力矩

大纲 应用场景定义字段解释 案例 sensor_msgs::msg::JointState 是 ROS (Robot Operating System) 中的一个消息类型&#xff0c;用于表示机器人关节的状态信息。它通常用于传输和处理机器人关节的角度、速度和力矩等信息。 应用场景 机器人控制 关节控制&#xff1a;在机器人…...

基于MCP协议的Shopify数据AI分析:自动化广告优化实战指南

1. 项目概述&#xff1a;用AI打通Shopify数据与广告投放的任督二脉 如果你在运营一个Shopify独立站&#xff0c;并且正在为Google、Meta&#xff08;Facebook/Instagram&#xff09;或TikTok广告投放而头疼&#xff0c;那么你很可能正经历着所有电商卖家的共同困境&#xff1a;…...

ensp关闭完美世界运行时显示权限不够

Windows PowerShell 版权所有&#xff08;C&#xff09; Microsoft Corporation。保留所有权利。安装最新的 PowerShell&#xff0c;了解新功能和改进&#xff01;https://aka.ms/PSWindowsPS C:\Users\Administrator> net stop MessageTransfer 发生系统错误 5。拒绝访问。…...

XT2055 双灯显示微型线性电池充电管理芯片

■ 产品概述 XT2055 是一款完善的单节锂电池恒流/恒压线性充电管理芯片。较薄的尺寸和较小的封装使它适用于便携式产品的应用&#xff0c;XT2055 也适用于 USB 的供电电路。得益于内部的MOSFET 结构&#xff0c;在应用上不需要外部电阻和阻塞二极管。在高能量运行和外围温度较高…...

深入解析Arm架构TLB维护机制与A64指令集

1. TLB维护机制基础解析在处理器架构中&#xff0c;TLB&#xff08;Translation Lookaside Buffer&#xff09;是内存管理单元&#xff08;MMU&#xff09;的核心组件&#xff0c;负责缓存虚拟地址到物理地址的转换结果。当CPU需要访问内存时&#xff0c;首先会查询TLB获取地址…...

Casbin Talent 2026:高校开发者开源进阶与工业级项目实战指南

1. 项目概述&#xff1a;Casbin Talent 2026&#xff0c;一个为高校开发者量身定制的开源进阶通道如果你是一名在校大学生&#xff0c;对开源世界充满好奇&#xff0c;渴望在真实的工业级项目中打磨技术&#xff0c;但又觉得像Google Summer of Code&#xff08;GSoC&#xff0…...

C语言核心知识体系总结

C语言核心知识体系总结本文旨在系统梳理C语言的基础与进阶知识点&#xff0c;帮助读者建立清晰的知识框架。内容涵盖&#xff1a;程序编译过程、数据类型与变量、运算符与表达式、控制结构、函数、指针、结构体与共用体、动态内存分配、文件操作等。适合复习巩固或查漏补缺。第…...

技能图谱探索器:从数据建模到交互可视化的全栈实现

1. 项目概述&#xff1a;一个技能图谱的探索工具最近在GitHub上看到一个挺有意思的项目&#xff0c;叫nitzzzu/openclaw-skills-explorer。光看名字&#xff0c;openclaw和skills-explorer这两个词就挺有画面感的。我第一反应是&#xff0c;这应该是一个用来探索、梳理或可视化…...

自动驾驶人机交接:DMS与安全验证如何破解控制权转移困局

1. 自动驾驶人机交接的核心困境与行业分野最近几年&#xff0c;自动驾驶&#xff08;AV&#xff09;和高级驾驶辅助系统&#xff08;ADAS&#xff09;无疑是汽车科技领域最炙手可热的话题。无论是传统车企的“新四化”转型&#xff0c;还是科技公司的颠覆性入局&#xff0c;大家…...

YouTube 转 MP3 工具里,为什么预览要放在下载前

很多转换工具看起来解决的是“我要一个 MP3 文件”&#xff0c;但真正影响体验的&#xff0c;往往不是页面上有没有下载按钮。 用户真正想确认的是&#xff1a;这个链接是不是被正确识别了&#xff0c;转换任务是不是还在进行&#xff0c;最后得到的音频是不是值得保存。对 Yo…...

Go 里什么时候可以“panic”?

“Don’t panic.” —— Go 谚语 但……如果我真的想 panic 呢&#xff1f;在 Go 的世界里&#xff0c;panic() 就像厨房里的灭火器&#xff1a;平时你不会用它炒菜&#xff0c;但如果油锅着火了&#xff0c;你肯定得拉它一把。今天我们就来聊聊&#xff1a;Go 里什么时候 pani…...