YOLOv8目标检测 opencv模型部署保姆级教程(包含opencv环境配置)

C++模型部署通常指的是将训练好的机器学习模型应用于生产环境中。以下是使用C++进行模型部署的一些优势:

  1. 性能:C++代码通常比Python等解释性语言运行速度更快,这使得C++成为部署模型的一种高性能选择。

  2. 平台兼容性:C++代码可以在不同的操作系统上编译,并且可以被编译成本地代码,这使得部署变得跨平台和设备容易。

  3. 低维护成本:C++代码通常维护成本较低,因为它的抽象级别较低,相比动态类型语言,修改和扩展代码更为直观和安全。

  4. 安全性:C++提供了内存安全性的控制,可以防止某些类型的安全漏洞。

一、导出为onnx格式

首先需要将训练好的yolov8模型转换成onnx格式的模型。在yolov8工程中找到default.yaml文件,该文件即训练时的通用配置文件,具体位置如下:

首先修改其Train settings,如下:

📌model: 此处为训练后模型权重的路径。

📌batch:此处的batch一定修改为1,否则后面导出的onnx模型的输入不为1。

📌imgsz:输入图片的尺寸大小与训练时保持一致即可。

接下来继续修改Export settings(在default.yaml文件的后半部分),如下:

📌format: 此处为onnx格式。

📌opset:此处为onnx的对应版本,修改为12即可。

📌nms:非极大抑制保持关闭。

最后在yolov8工程中找到exporter.py文件,其具体位置如下:

右键,运行该文件,耐心等待即可

出现

export success ✅ 5.5s

Export complete (37.0s)

表明导出成功,其导出的onnx模型保存在与yolo训练模型相同的文件夹下。

二、基于opencv 推理onnx

本文使用opencv4.7.0版本,其在Linux和windows下均可运行,下面以windows为例子,使用Visual Studio 2022作为开发环境。

首先需要对新建的c++工程进行opencv的环境配置

1.添加环境变量

电脑左上角找到“我的电脑”,点击鼠标右键,依次选择“属性”、“高级系统设置”、“环境变量”、“Path”。添加如下环境变量

❗❗❗路径中的版本要与自己的opencv版本对应

E:\OpenCV\build\bin
E:\OpenCV\build\x64\vc16\bin

2.添加OpenCV包含目录,库目录和附加依赖项

该项目中我使用的是x64,Release模式,如果需要使用Debug模式下面会略有变化,我会一并给出。

首先在VS中新建一个工程,我这里命名为DetectionV8,可根据自己需求更改,新建完成后找到属性管理器,如图所示

如果右侧栏中没有显示属性管理器可以通过,在Visual Studio左上角菜单栏,依次选择“视图”、“其他窗口”、“属性管理器”进行显示。

然后右键属性管理器中的DetectionV8,选择属性,下面我们依次添加包含目录,库目录和附加依赖项。

①包含目录

在【配置属性】-->【VC++目录】-->【包含目录】中, 点击最右侧的倒三角按钮,选择<编辑>

选择“包含目录”,进入“包含目录”页面,添加OpenCV包含目录路径:

❗❗❗路径中的版本要与自己的opencv版本对应,不要手动输入,点击...去浏览添加

D:\Program Files\opencv\opencv470\build\include
D:\Program Files\opencv\opencv470\build\include\opencv2

库目录

在【配置属性】-->【VC++目录】-->【库目录】中, 点击最右侧的倒三角按钮,选择<编辑> 

选择“库目录”,进入“库目录”页面,添加库目录(lib文件夹)路径:

D:\Program Files\opencv\opencv470\build\x64\vc16\lib

❗❗❗路径中的版本要与自己的opencv版本对应,不要手动输入,点击...去浏览添加

③ 附加依赖项

添加附加依赖项就是添加所有的lib文件路径,这些lib文件都是在前面那个库目录里面保存的。

注意有两种lib文件,一种带d的是Debug模式,不带d的是Release模式,OpenCV版本不同,前面的序号也不同,需要做相应的修改,两种模式的lib最好不要放一起,否则有可能会导致其中一个模式出问题

在【配置属性】-->【链接器】-->【输入】-->【附加依赖项】中, 点击最右侧的倒三角按钮,选择<编辑> 

 选择“附加依赖项”,进入“附加依赖项”页面,开始添加lib文件路径

# Release模式下添加
opencv_world470.lib
# Debug模式下添加
opencv_world470d.lib 

❗❗❗需要与自己的opencv版本对应

3.添加cpp文件与头文件

 以下是主函数文件DetectionV8.cpp

#include "yoloV8.h"
#include <iostream>
#include<opencv2//opencv.hpp>
#include<math.h>

#define USE_CUDA false //use opencv-cuda

using namespace std;
using namespace cv;
using namespace dnn;


int main()
{
	// 修改为自己测试图片与onnx权重对应的路径
    string img_path = "../test.jpg";
	string model_path3 = "../best.onnx";
	Mat img = imread(img_path);


	vector<Scalar> color;
	srand(time(0));
	for (int i = 0; i < 80; i++) {
		int b = rand() % 256;
		int g = rand() % 256;
		int r = rand() % 256;
		color.push_back(Scalar(b, g, r));
	}


	Yolov8 yolov8; Net net3;
	Mat img3 = img.clone();
	bool isOK = yolov8.readModel(net3, model_path3, USE_CUDA);
	if (isOK) {
		cout << "read net ok!" << endl;
	}
	else {
		cout << "read onnx model failed!";
		return -1;
	}
	vector<Detection> result3 = yolov8.Detect(img3, net3);
	yolov8.drawPred(img3, result3, color);
	Mat dst = img3({ 0, 0, img.cols, img.rows });
	cv::imshow("aaa", dst);
	imwrite("../result.jpg", dst);
	cv::waitKey(0);


	return 0;
}

 以下是yolov8头文件yoloV8.h

#pragma once
#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
using namespace cv::dnn;
struct Detection
{
	int class_id{ 0 };//结果类别id
	float confidence{ 0.0 };//结果置信度
	cv::Rect box{};//矩形框
};
class Yolo {
public:
	bool readModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
	void drawPred(cv::Mat& img, std::vector<Detection> result, std::vector<cv::Scalar> color);
	virtual	vector<Detection> Detect(cv::Mat& SrcImg, cv::dnn::Net& net) = 0;
	float sigmoid_x(float x) { return static_cast<float>(1.f / (1.f + exp(-x))); }
	Mat formatToSquare(const cv::Mat& source)
	{
		int col = source.cols;
		int row = source.rows;
		int _max = MAX(col, row);
		cv::Mat result = cv::Mat::zeros(source.rows, source.cols, CV_8UC3);
		source.copyTo(result(cv::Rect(0, 0, col, row)));
		return result;
	}
	const int netWidth = 1600;   //ONNX图片输入宽度
	const int netHeight = 1600;  //ONNX图片输入高度


	float modelConfidenceThreshold{ 0.0 };
	float modelScoreThreshold{ 0.0 };
	float modelNMSThreshold{ 0.0 };

	std::vector<std::string> classes = { "dislocation" };  //类别,需要修改为自己对应的类别
};

class Yolov8 :public Yolo {
public:
	vector<Detection> Detect(Mat& SrcImg, Net& net);
private:
	float confidenceThreshold{ 0.25 };
	float nmsIoUThreshold{ 0.70 };
};

  以下是yolov8的cpp文件yoloV8.cpp

#include"yoloV8.h"

bool Yolo::readModel(Net& net, string& netPath, bool isCuda = false) {
	try {
		net = readNetFromONNX(netPath);
	}
	catch (const std::exception&) {
		return false;
	}
	if (isCuda) {
		net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);
		net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
	}
	else {
		net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);
		net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);
	}
	return true;
}

void Yolo::drawPred(Mat& img, vector<Detection> result, vector<Scalar> colors) {

	for (int i = 0; i < result.size(); ++i)
	{
		Detection detection = result[i];

		cv::Rect box = detection.box;
		cv::Scalar color = colors[detection.class_id];

		// Detection box
		cv::rectangle(img, box, color, 2);

		// Detection box text
		std::string classString = classes[detection.class_id] + ' ' + std::to_string(detection.confidence).substr(0, 4);
		cv::Size textSize = cv::getTextSize(classString, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);
		cv::Rect textBox(box.x, box.y - 40, textSize.width + 10, textSize.height + 20);

		cv::rectangle(img, textBox, color, cv::FILLED);
		cv::putText(img, classString, cv::Point(box.x + 5, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);
	}
}

vector<Detection> Yolov8::Detect(Mat& modelInput, Net& net) {
	modelInput = formatToSquare(modelInput);
	cv::Mat blob;
	cv::dnn::blobFromImage(modelInput, blob, 1.0 / 255.0, Size(netWidth, netHeight), cv::Scalar(), true, false);
	将图片(blob)输入到DNN网络中
	net.setInput(blob);//输入经过blobFromImage处理的图像信息(支持CV_32F和CV_8U位深度)

	std::vector<cv::Mat> outputs;
	net.forward(outputs, net.getUnconnectedOutLayersNames());


	// yolov8 has an output of shape (batchSize, 84,  8400) (Num classes + box[x,y,w,h])
	int rows = outputs[0].size[2];
	int dimensions = outputs[0].size[1];

	outputs[0] = outputs[0].reshape(1, dimensions);
	cv::transpose(outputs[0], outputs[0]);

	float* data = (float*)outputs[0].data;
	// Mat detect_output(8400, 84, CV_32FC1, data);// 8400 = 80*80+40*40+20*20
	float x_factor = (float)modelInput.cols / netWidth;
	float y_factor = (float)modelInput.rows / netHeight;

	std::vector<int> class_ids;
	std::vector<float> confidences;
	std::vector<cv::Rect> boxes;

	for (int i = 0; i < rows; ++i)
	{
		cv::Mat scores(1, classes.size(), CV_32FC1, data + 4);
		cv::Point class_id;
		double maxClassScore;

		minMaxLoc(scores, 0, &maxClassScore, 0, &class_id);
		if (maxClassScore > modelConfidenceThreshold)
		{
			confidences.push_back(maxClassScore);
			class_ids.push_back(class_id.x);

			float x = data[0];
			float y = data[1];
			float w = data[2];
			float h = data[3];

			int left = int((x - 0.5 * w) * x_factor);
			int top = int((y - 0.5 * h) * y_factor);

			int width = int(w * x_factor);
			int height = int(h * y_factor);

			boxes.push_back(cv::Rect(left, top, width, height));
		}
		data += dimensions;
	}

	//执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)
	vector<int> nms_result;
	NMSBoxes(boxes, confidences, confidenceThreshold, nmsIoUThreshold, nms_result);
	vector<Detection> detections{};
	for (unsigned long i = 0; i < nms_result.size(); ++i) {
		int idx = nms_result[i];
		Detection result;
		result.class_id = class_ids[idx];
		result.confidence = confidences[idx];
		result.box = boxes[idx];
		detections.push_back(result);
	}
	return detections;
}

 模型部署完毕,运行程序即可!

另外,在此推荐一个小工具,对深度学习的模型理解与查看非常的友好,相信大家也不陌生,就是Netron。Netron是一种用于神经网络、深度学习和机器学习模型的可视化工具,它可以为模型的架构生成具有描述性的可视化(descriptive visualization)。

下载链接放在下面了

https://download.youkuaiyun.com/download/m0_57010556/88942926?spm=1001.2014.3001.5501icon-default.png?t=O83Ahttps://download.youkuaiyun.com/download/m0_57010556/88942926?spm=1001.2014.3001.5501

另外,如果有想了解yolov8目标检测数据集制作以及yolov8实例分割数据集制作的小伙伴可以移步我的其他文章

YOLOv8制作自己的实例分割数据集保姆级教程(包含json转txt)icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/m0_57010556/article/details/139150198?spm=1001.2014.3001.5501YOLOv8制作自己的目标检测数据集保姆级教程(包含json转xml转txt)icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/m0_57010556/article/details/135460191?spm=1001.2014.3001.5502

<think>好的,用户的问题是关于如何使用YOLOv8的exporter.py文件导出模型教程或示例。我需要先理解用户的需求。用户可能已经知道YOLOv8的基本用法,但现在需要将训练好的模型导出为其他格式,比如ONNX或TensorRT,以便在不同环境中部署。 首先,我应该回忆YOLOv8的文档结构,特别是exporter.py的作用。根据用户提供的引用内容,exporter.py用于导出模型到其他格式。接下来,我需要确认YOLOv8的导出支持哪些格式,常见的包括ONNX、TensorRT、CoreML等。 用户可能需要具体的命令行示例和参数说明。例如,使用yolo export命令,指定模型格式和参数。此外,用户可能想知道导出后的模型如何验证和使用,比如在PythonC++中加载。 还要考虑用户可能遇到的问题,比如环境依赖,例如安装onnx或tensorrt的库。需要提醒用户确保相关依赖已安装,否则导出可能会失败。另外,导出时的输入尺寸和动态维度设置也是常见的问题点,应该给出示例说明。 用户提供的引用中提到了predictor.py和validator.py,可能导出后的模型需要这些模块进行验证。因此,在教程中应该包含验证步骤,比如使用导出的ONNX模型进行推理,并检查输出是否正确。 还需要注意代码示例的正确性,比如使用正确的模型路径和参数。如果有常见的错误,比如缺少导出格式的支持,应该提示用户安装必要的包,如onnx。 最后,生成相关问题时要围绕导出模型的不同方面,比如支持的格式、参数调整、验证方法、部署示例等,帮助用户进一步了解相关内容。</think>### 如何使用 YOLOv8 exporter.py 导出模型 #### 1. 环境准备 确保已安装最新版 `ultralytics` 库: ```bash pip install ultralytics ``` #### 2. 导出模型的基本命令 YOLOv8 的 `exporter.py` 通过 `yolo export` 命令行工具实现模型格式转换[^1]: ```bash yolo export model=yolov8n.pt format=onnx # 导出为ONNX格式 ``` 支持格式包括 ONNX、TensorRT、CoreML、OpenVINO 等,通过 `format` 参数指定。 #### 3. 关键参数说明 - `imgsz`: 输入图像尺寸(默认640),例如 `imgsz=320` - `half`: 半精度导出(FP16),提升推理速度 - `dynamic`: 允许动态输入维度(适用于可变尺寸推理) - `opset`: ONNX 算子集版本(默认12) 示例(带动态维度和半精度): ```bash yolo export model=yolov8n.pt format=onnx dynamic=True half=True opset=13 ``` #### 4. 导出后验证 使用 `predictor.py` 或 `validator.py` 验证导出模型: ```python from ultralytics import YOLO # 加载导出的ONNX模型 model = YOLO('yolov8n.onnx') results = model.predict('image.jpg') results[0].show() ``` #### 5. 进阶用法:自定义导出 若需修改导出逻辑,可直接调用 `exporter.py` 的底层函数: ```python from ultralytics.engine.exporter import export export(model='yolov8n.pt', format='engine', device=0) # 导出为TensorRT引擎 ``` #### 6. 常见问题 - **ONNX 导出失败**:安装 `onnx` 和 `onnxsim` 包 - **TensorRT 支持**:需提前配置CUDA和TensorRT环境 - **动态维度限制**:部分格式(如TensorRT)需固定部分维度 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI小小怪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值