c++调用实现yolov5转onnx介绍

目录
  • 介绍
    • 训练模型.pt转onnx
    • c++代码解析
    • main函数部分
    • 推理部分讲解
    • darpred部分
    • sigmod部分
  • 结尾

介绍

现在很多开发都是需要用c++做最后一步的移植部署,手写吧,先不说你会不会浪费时间,网上找吧,问题千奇百怪,所以给大家出这篇文章,做雷锋教学,话不多说,开始

训练模型.pt转onnx

训练部分根据呼声再决定要不要写一份博客吧!!
注意事项:
1.训练代码一定要选择yolov5 5.0版本
2. 进入models/exprort.py;

3.将红框区域换成你自己的训练完的模型

4.将版本换成12;

5.直接运行即可,会生成出onnx的模型出来。

c++代码解析

博主使用的是opencv4.5.3版本,已经编译好的,需要直接扫码加我发你

main函数部分

读取模型利用的是dnn::readNet,opencv其实挺强大的博主已经读过tf模型,torch模型后续都会出对应博客,这里总共有三点改,输入图片path,输入类别名class_names,net部分改成自己的模型

net.set这些参数都固定就好,有兴趣的同学可以研究研究DNN_TARGET_CPU这个地方,是可以使用gpu和cuda的,但是博主还没复现过

推理部分讲解

void postprocess(cv::Mat& cv_src, std::vector<cv::Mat>& outs, const std::vector<std::string>& classes, int net_size)
{
	float confThreshold = 0.1f;
	float nmsThreshold = 0.1f;
	std::vector<int> classIds;
	std::vector<float> confidences;
	std::vector<cv::Rect> boxes;
	int strides[] = { 8, 16, 32 };
	std::vector<std::vector<int> > anchors =
	{
		{ 10,13, 16,30, 33,23 },
		{ 30,61, 62,45, 59,119 },
		{ 116,90, 156,198, 373,326 }
	};
	for (size_t k = 0; k < outs.size(); k++)
	{
		float* data = outs[k].ptr<float>();
		int stride = strides[k];
		int num_classes = outs[k].size[4] - 5;
		for (int i = 0; i < outs[k].size[2]; i++)
		{
			for (int j = 0; j < outs[k].size[3]; j++)
			{
				for (int a = 0; a < outs[k].size[1]; ++a)
				{
					float* record = data + a * outs[k].size[2] * outs[k].size[3] * outs[k].size[4] +
						i * outs[k].size[3] * outs[k].size[4] + j * outs[k].size[4];
					float* cls_ptr = record + 5;
					for (int cls = 0; cls < num_classes; cls++)
					{
						float score = sigmoid(cls_ptr[cls]) * sigmoid(record[4]);
						if (score > confThreshold)
						{
							float cx = (sigmoid(record[0]) * 2.f - 0.5f + (float)j) * (float)stride;
							float cy = (sigmoid(record[1]) * 2.f - 0.5f + (float)i) * (float)stride;
							float w = pow(sigmoid(record[2]) * 2.f, 2) * anchors[k][2 * a];
							float h = pow(sigmoid(record[3]) * 2.f, 2) * anchors[k][2 * a + 1];
							float x1 = std::max(0, std::min(cv_src.cols, int((cx - w / 2.f) * (float)cv_src.cols / (float)net_size)));
							float y1 = std::max(0, std::min(cv_src.rows, int((cy - h / 2.f) * (float)cv_src.rows / (float)net_size)));
							float x2 = std::max(0, std::min(cv_src.cols, int((cx + w / 2.f) * (float)cv_src.cols / (float)net_size)));
							float y2 = std::max(0, std::min(cv_src.rows, int((cy + h / 2.f) * (float)cv_src.rows / (float)net_size)));
							classIds.push_back(cls);
							confidences.push_back(score);
							boxes.push_back(cv::Rect(cv::Point(x1, y1), cv::Point(x2, y2)));
						}
					}
				}
			}
		}
	}
	std::vector<int> indices;
	cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
	for (size_t i = 0; i < indices.size(); i++)
	{
		int idx = indices[i];
		cv::Rect box = boxes[idx];
		drawPred(classIds[idx], confidences[idx], box.x, box.y,
			box.x + box.width, box.y + box.height, cv_src, classes);
	}
}

抬头部分是两大目标检测的阈值设置,然后anchors这些都不建议动,除非你在训练的时候用了你自己生成的anchors的话,就改成你自己的,然后根据训练推理后,会生成我们所对应的坐标框以及分数,将分数和狂送到容器中,dnn中有nms等底层函数哦
cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
对应输入就可以了,然后得到我们的Box,index,和置信度,接下来就到了我们的画图环节。

darpred部分

void drawPred(int classId, float conf, int left, int top, int right, int bottom, cv::Mat& frame,
	const std::vector<std::string>& classes)
{
	cv::rectangle(frame, cv::Point(left, top), cv::Point(right, bottom), cv::Scalar(0, 255, 0), 3);
	std::string label = cv::format("%.2f", conf);
	if (!classes.empty()) {
		CV_Assert(classId < (int)classes.size());
		label = classes[classId] + ": " + label;
	}
	int baseLine;
	cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
	top = std::max(top, labelSize.height);
	cv::rectangle(frame, cv::Point(left, top - round(1.5 * labelSize.height)), cv::Point(left + round(1.5 * labelSize.width), top + baseLine), cv::Scalar(0, 255, 0), cv::FILLED);
	cv::putText(frame, label, cv::Point(left, top), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(), 2);
}

sigmod部分

inline float sigmoid(float x)
{
	return 1.f / (1.f + exp(-x));
}

结尾

到此这篇关于c++调用实现yolov5转onnx介绍的文章就介绍到这了,更多相关c++ yolov5转onnx内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解c++实现信号槽

    目录 用c++实现信号槽机制(signal-slot) 总结 用c++实现信号槽机制(signal-slot) 信号槽机制的个人理解:信号槽是在两个c++类对象之间建立联系的通道,其中一个对象可称之为信号发送者(sender),另一个对象可称之为信号接收者(recver),sender通过信号槽发出信号后,recver就可以执行函数进行某些操作.也就是说应用程序通过信号槽可以在两个互不相关的对象之间建立起逻辑关系,使程序开发变得简洁.方便. 信号槽本质是由c++定义的类组成,分为两个部分:槽类和

  • C++之const限定符详解

    const限定符:把变量定义成一个常量 1.使用const对变量的类型加以限定,变量的值不能被改变 const int bufSize=512;//输入缓冲区大小 bufSize=512;//错误 因为有等号试图向const对象写值 2.const对象必须初始化(其他时候不能出现在等号左边) const int i=get_size();//正确 运行时初始化 const int j=33;//正确 编译时初始化 const int k;//错误 没有初始化 const int bb=0; vo

  • c++调用实现yolov5转onnx介绍

    目录 介绍 训练模型.pt转onnx c++代码解析 main函数部分 推理部分讲解 darpred部分 sigmod部分 结尾 介绍 现在很多开发都是需要用c++做最后一步的移植部署,手写吧,先不说你会不会浪费时间,网上找吧,问题千奇百怪,所以给大家出这篇文章,做雷锋教学,话不多说,开始 训练模型.pt转onnx 训练部分根据呼声再决定要不要写一份博客吧!! 注意事项: 1.训练代码一定要选择yolov5 5.0版本 2. 进入models/exprort.py: 3.将红框区域换成你自己的训

  • YOLOV5超参数介绍以及优化策略

    目录 yaml文件 超参数 优化策略 总结 yaml文件 模型深度&宽度 nc: 3 # 类别数量 depth_multiple: 0.33 # model depth multiple width_multiple: 0.50 # layer channel multiple depth_multiple:控制子模块数量=int(number*depth) width_multiple:控制卷积核的数量=int(number*width) Anchor anchors: - [10,13, 1

  • GoLang调用链可视化go-callvis使用介绍

    本文介绍一款工具 go-callvis,它能够将 Go 代码的调用关系可视化出来,并提供了可交互式的 web 服务. go get -u github.com/ofabry/go-callvis在windows系统上并没有自动安装,需要进入下载的目录go install在linux系统上自动安装了 > go-callvis go-callvis: visualize call graph of a Go program. Usage: go-callvis [flags] package Pac

  • php调用c接口无错版介绍

    1.首先是要安装好PHP 2.进入PHP的下载解压目录下的ext目录#cd /root/php-5.3.6/ext#./ext_skel --extname=hmc 说明:./ext_skel --extname=module_namemodule_name是你自己可以选择的扩展模块的名字,例如我选择的hmc.执行工具后会自动在ext目录下建立你选择的module_name名字的目录,里面已经生成了相关的代码,这些代码中只需要调整config.m4文件中的三行注释就可以正常的编译带这个自定义扩展

  • JavaScript四种调用模式和this示例介绍

    JavaScript调用时除了声明时定义的形参外,每个函数接受两个附加参数:this 和arguments,this在面向对象编程中非常重要,它取决于调用模式. JavaScript有四种调用模式,方法调用模式,函数调用模式,构造器调用模式和apply调用模式.这些模式在初始化关键参数this上存在差异. 方法调用模式:当一个函数被保存为对象的一个属性时,我们称它为一个方法,当一个方法被调用时,this被绑定到该对象上.如果调用表达式包含一个属性取表达式(即一个.点表达式或[script]下标表

  • C#调用Java代码的方法介绍

    c#直接调用java代码,需要ikvmbin-0.44.0.5.zip.下载地址: http://pan.baidu.com/s/17moxX 1.下载并解压 2.配置环境变量: 在path中添加%IKVM_HOME%\bin,IKVM_HOME为解压后的IKVM的主目录.在dos界面,输入"ikvm"命令,测试是否配置成功 3.编写java代码(java代码,要放在指定的package下,不要放在默认包下): 复制代码 代码如下: package com.xyy.csharp; im

  • jquery ajax 调用失败的原因示例介绍

    下面是一个完事的函数: 复制代码 代码如下: function ReLoadPromotion() { var A = parseFloat($("#pNormalTotal").html()) + parseFloat($("#pBarginTotal").html()); jQuery.ajax( { url: "/ajax/OrderRedemption.aspx?vf=getlist", type: "POST", d

  • PyTorch 模型 onnx 文件导出及调用详情

    目录 前言 基本用法 高级 API 前言 Open Neural Network Exchange (ONNX,开放神经网络交换) 格式,是一个用于表示深度学习模型的标准,可使模型在不同框架之间进行转移 PyTorch 所定义的模型为动态图,其前向传播是由类方法定义和实现的 但是 Python 代码的效率是比较底下的,试想把动态图转化为静态图,模型的推理速度应当有所提升 PyTorch 框架中,torch.onnx.export 可以将父类为 nn.Module 的模型导出到 onnx 文件中,

  • C#调用WebService的方法介绍

    一.前言 在日常工作中,如果涉及到与第三方进行接口对接,有的会使用WebService的方式,这篇文章主要讲解在.NET Framework中如何调用WebService.首先我们创建一个WebService,里面有两个方法:一个无参的方法,一个有参的方法: 创建好了WebService以后,把WebService部署到IIS上,并确保可以访问 二.静态引用 这种方式是通过添加静态引用的方式调用WebService.首先创建一个Winform程序,界面上有一个按钮,点击按钮调用WebServic

  • C#调用接口的四种方式介绍

    在用C#调用接口的时候,遇到需要通过调用登录接口才能调用其他的接口,因为在其他的接口需要在登录的状态下保存Cookie值才能有权限调用,所以首先需要通过调用登录接口来保存cookie值,再进行其他接口的调用 1.通过Get方式 #region get方式 public string HttpGet(string url) { Encoding encoding = Encoding.UTF8; HttpWebRequest request = (HttpWebRequest)WebRequest

随机推荐