目录
三、基于TensorRT将onnx模型转为.engine 或者.trt格式的模型
一、部署环境说明:
- 系统:win10专业版
- TensorRT版本:TensorRT-8.5.2.2
- OpneCV版本:OpenCV4.7.0
- ultralytics版本:ultralytics-8.3.88
- CUDA版本:11.7
- CUDNN版本:8.6.5
- QT Creator版本:16.0.1(QT 版本为6.8.3)
二、基于yolov8在自定义数据集上进行训练
(1)图像数据制作,标签制作
通常采用labelme标注工具进行数据标注,数据保存格式选择为yolo。
(2)模型训练
- 在Github上下载ultralytics,链接:GitHub - ultralytics/ultralytics: Ultralytics YOLO11 🚀
- 使用anaconda 安装python虚拟环境。
- 在python虚拟环境中安装GPU版本的torch。注意安装的时候需要VPN翻墙安装,不要使用清华源,因为清华源没有GPU版本的torch。torch环境配置如下:
4.使用pycharm 打开ultralytics工程文件,根目录下创建train,py文件,文件内容如下:
from ultralytics import YOLO
if __name__ == '__main__':
# Load a COCO-pretrained YOLOv8n model
model = YOLO("yolov8s.pt")
results = model.train(data="Number.yaml", epochs=100, imgsz=640)#增加随机旋转
5.训练模型的配置文件.yaml需要根据实际路径设置图像路径。
(3)模型转onnx模型
转换代码如下:
from ultralytics import YOLO
# Load a YOLOv8 model
model = YOLO("D:\\ultralytics-8.3.88\\runs\detect\\train1\\weights\\best.pt")
model.export(format="onnx", opset=12, dynamic=True, imgsz=640)
三、基于TensorRT将onnx模型转为.engine 或者.trt格式的模型
- 下载tensorRT,下载链接:TensorRT SDK | NVIDIA Developer
- 将下载后的文件进行解压,在系统环境中配置,如下图所示。
3.进入tensorRT的bin目录下,并将onnx模型拷贝到bin目录下
4.输入命令行代码,即可获得best.engine。
trtexec.exe --onnx=best.onnx --saveEngine=best.engine --buildOnly --minShapes=images:1x3x640x640 --optShapes=images:4x3x640x640 --maxShapes=images:8x3x640x640
四、基于VS2019生成动态链接库配置
- 新建一个动态链接库的工程项目。
2.配置opencv,cuda, tenorRT的属性表
(1)TensorRT配置表如下:
附件依赖项:
nvinfer.lib
nvinfer_plugin.lib
nvonnxparser.lib
nvparsers.lib
(2)OpenCV配置表如下:
(3)CUDA配置表如下:
直接拷贝CUDA安装目录下现成的文件,一般在CUDA的默认安装地址:
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.7\extras\visual_studio_integration\MSBuildExtensions\CUDA 11.7.props
(4)解决方案文件配置
- 下载TensorRT-Alpha,下载链接:TensorRT-alpha
2.下载后解压TensorRT-Alpha
3. 按照下图进行文件配置
上图中红色圈中的为添加的现有文件,绿色圈的文件为新建的文件。其中utils中所有文件是从TensorRT-Alpha中直接拷贝过来,如图:
其中源文件中的红色圈中的文件为yolov8文件夹中直接拷贝,如图所示:
资源文件中文件为TensorRT-8.5.2.2文件夹中直接拷贝过来,如下图所示
4.源文件项中新建的fuelpinhole.h文件的内容如下:
#pragma once
#define FUELPINHOLEINSP_API _declspec(dllexport)
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <random>
#include <opencv2/opencv.hpp> //opencv header file
#include <chrono>
#include"../utils/yolo.h"
#include"yolov8.h"
// 定义输出结构体
typedef struct {
float prob;
cv::Rect rect;
int classid;
}Object;
enum InputType {
IMAGE,
VIDEO,
CAMERA
};
int total_batches = 0;
int delay_time = 1;
bool is_show = false;
bool is_save = false;
extern "C"
{
utils::InitParameter param;
FUELPINHOLEINSP_API YOLOV8* LoadDetectPinHoleModel(const std::string& model_path, const std::string& file_path, const int& type, const int& cameraID);
FUELPINHOLEINSP_API YOLOV8* LoadDetectPinHoleModel_v1(const std::string& model_path, int src_h, int src_w);
FUELPINHOLEINSP_API bool YoloDetectPinHoleInfer(const cv::Mat& src, std::vector<Object>& vecObj, YOLOV8* model,bool isShow);
void _setParameters(utils::InitParameter& initParameters);
void _task(YOLOV8* yolo, const utils::InitParameter& param, std::vector<cv::Mat>& imgsBatch, const int& delayTime, const int& batchi,
const bool& isShow, const bool& isSave, std::vector<Object>& vecObj);
}
5.源文件项中新建的fuelpinhole.cpp文件的内容如下:
#include "../pch.h"
#include "fuelpinholeinsp.h"
void _setParameters(utils::InitParameter& initParameters)
{
initParameters.class_names = utils::dataSets::fuelpinhole;
initParameters.num_class = 1; //!!!!
initParameters.batch_size = 1;
initParameters.dst_h = 640;
initParameters.dst_w = 640;
initParameters.input_output_names = { "images", "output0" };
initParameters.conf_thresh = 0.25f;
initParameters.iou_thresh = 0.45f;
initParameters.save_path = "";
}
void _task(YOLOV8* yolo, const utils::InitParameter& param, std::vector<cv::Mat>& imgsBatch,
const int& delayTime, const int& batchi, const bool& isShow, const bool& isSave, std::vector<utils::Box>& box)
{
auto beforeTime = std::chrono::steady_clock::now();
utils::DeviceTimer d_t0; yolo->copy(imgsBatch); float t0 = d_t0.getUsedTime();
utils::DeviceTimer d_t1; yolo->preprocess(imgsBatch); float t1 = d_t1.getUsedTime();
utils::DeviceTimer d_t2; yolo->infer(); float t2 = d_t2.getUsedTime();
utils::DeviceTimer d_t3; yolo->postprocess(imgsBatch); float t3 = d_t3.getUsedTime();
//sample::gLogInfo <<
// //"copy time = " << t0 / param.batch_size << "; "
// "preprocess time = " << t1 / param.batch_size << "; "
// "infer time = " << t2 / param.batch_size << "; "
// "postprocess time = " << t3 / param.batch_size << std::endl;
std::vector<std::vector<utils::Box>> objectss = yolo->getObjectss();
box = objectss[0];
if (isShow) {
utils::show(objectss, param.class_names, delayTime, imgsBatch, beforeTime);
}
if (isSave)
utils::save(yolo->getObjectss(), param.class_names, param.save_path, imgsBatch, param.batch_size, batchi);
yolo->reset();
}
YOLOV8* LoadDetectPinHoleModel_v1(const std::string& model_path,int src_h,int src_w)
{
// set utils params //
_setParameters(param);
param.src_h = src_h;//应该是需要原始图像大小进行坐标转换
param.src_w = src_w;
YOLOV8* model = new YOLOV8(param);
std::vector<unsigned char> trt_file = utils::loadModel(model_path);
if (trt_file.empty())
{
sample::gLogError << "trt_file is empty!" << std::endl;
return nullptr;
}
// init model
if (!model->init(trt_file))
{
sample::gLogError << "initEngine() ocur errors!" << std::endl;
return nullptr;
}
model->check();
return model;
}
YOLOV8* LoadDetectPinHoleModel(const std::string& model_path, const std::string& file_path, const int& type, const int& cameraID)
{
// set utils params //
_setParameters(param);
// source
utils::InputStream source;
// path
std::string video_path;
std::string image_path;
// camera' id
int camera_id = 0;
switch (type)
{
case InputType::IMAGE:
source = utils::InputStream::IMAGE;
image_path = file_path;
break;
case InputType::VIDEO:
source = utils::InputStream::VIDEO;
video_path = file_path;
break;
case InputType::CAMERA:
source = utils::InputStream::CAMERA;
camera_id = 0;
break;
default:
break;
}
// input params
int delay_time = 1; // w or h
int total_batches = 1;
cv::VideoCapture capture, capture1;
// set input params
if (!utils::setInputStream(source, image_path, video_path,
camera_id, capture, total_batches, delay_time, param))
{
sample::gLogError << "read the input data errors!" << std::endl;
return nullptr;
}
// build and read model
YOLOV8* model = new YOLOV8(param);
std::vector<unsigned char> trt_file = utils::loadModel(model_path);
if (trt_file.empty())
{
sample::gLogError << "trt_file is empty!" << std::endl;
return nullptr;
}
// init model
if (!model->init(trt_file))
{
sample::gLogError << "initEngine() ocur errors!" << std::endl;
return nullptr;
}
model->check();
return model;
}
bool YoloDetectPinHoleInfer(const cv::Mat& src, std::vector<Object>& vecObj, YOLOV8* model,bool isShow)
{
std::vector<cv::Mat> imgs_batch;
imgs_batch.reserve(param.batch_size);
imgs_batch.emplace_back(src.clone());
std::vector<utils::Box> box;
_task(model, param, imgs_batch, delay_time, 0, isShow, is_save, box);
for (auto b : box)
{
Object tmp;
tmp.classid = b.label;
tmp.prob = b.confidence;
int x = (int)(b.left + b.right) / 2.;
int y = (int)(b.top + b.bottom) / 2.;
int w = (int)(b.right - b.left);
int h = (int)(b.bottom - b.top);
tmp.rect = cv::Rect(x, y, w, h);
vecObj.emplace_back(tmp);
}
return true;
}
6.通过utils.cpp和utils.h中可以修改模型的类别名称,类别数量,显示颜色配置
7.通过项目的生成依赖项->生成自定义 选择CUDA ,如下图所示
8.选择.cu文件,右键选择属性,项类型选CUDA C/C++
9.设置预编译头
10.建议禁用代码安全检查
11.最后点击生成解决方案,在debug中生成dll,和lib库文件。
五、基于Qt creator调用yolov模型实现检测
(1)使用QT creator创建工程项目
(2)创建include文件夹,将动态链接库中属性表中的包含头文件(tensorRT,CUDA)的内容全部拷贝进来。创建lib库,同样将动态链接库中属性表中的库文件拷贝进来。
(3)将配置动态链接库时的添加的utils,yolo文件都拷贝到这个工程里面。
(4)将生成的.engine模型文件拷贝到qt工程目录下。
(5)配置QT的pro文件,如下:
INCLUDEPATH += D:/opencv/build/include
DEPENDPATH += D:/opencv/build/include
INCLUDEPATH += $$PWD/include
DEPENDPATH += $$PWD/include
win32:CONFIG(release, debug|release): LIBS += -LD:/opencv/build/x64/vc16/lib/ -lopencv_world470
else:win32:CONFIG(debug, debug|release): LIBS += -LD:/opencv/build/x64/vc16/lib/ -lopencv_world470d
LIBS += -L$$PWD/lib/ -lfuelpinholeInsp
LIBS += -L$$PWD/lib/ -lcudadevrt
LIBS += -L$$PWD/lib/ -lcudart
LIBS += -L$$PWD/lib/ -lnvinfer
LIBS += -L$$PWD/lib/ -lnvinfer_plugin
LIBS += -L$$PWD/lib/ -lnvonnxparser
LIBS += -L$$PWD/lib/ -lnvparsers
(6)添加动态链接库的头文件fuelpinholeinsp.h
#pragma once
#define FUELNOZZLEINSP_API _declspec(dllexport)
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <random>
#include <opencv2/opencv.hpp> //opencv header file
#include <utils/yolo.h>
#include <src/yolov8.h>
using namespace cv;
using namespace std;
// 定义输出结构体
typedef struct {
float prob;
cv::Rect rect;
int classid;
}Object_nozzle;
extern "C"
{
FUELNOZZLEINSP_API YOLOV8* LoadDetectNozzleModel(const std::string& model_path, const std::string& file_path, const int& type, const int& cameraID);
FUELNOZZLEINSP_API YOLOV8* LoadDetectNozzleModel_v1(const std::string& model_path,int src_h,int src_w);
FUELNOZZLEINSP_API bool YoloDetectNozzleInfer(const cv::Mat& src, std::vector<Object_nozzle>& vecObj, YOLOV8* model,bool isShow);
}
头文件名称不重要,重要的是头文件中的#define FUELNOZZLEINSP_API _declspec(dllexport)声明。
(7)将生成的动态链接库lib放在lib中,将dll放在exe的同目录下。
(8)编写mainwindow.h文件
在mainwindow.h中定义如下:
private:
Ui::MainWindow *ui;
YOLOV8* model_pinhole;
(9)在mainwindow.cpp中添加代码
//初始化模型,图像大小
string eName_Detect_pinhole =”d:\\best.engine”;
model_pinhole = LoadDetectPinHoleModel_v1(eName_Detect_pinhole,975,892);//指定输入图像的大小,h,w,注意设置的图像大小,和用来测试的图像大小必须保持一致。
//调用模型进行识别
vector<Object_pinhole> vecObj = {};
cv::Mat frame = cv::imread("D:\\data\\test.png");
bool InferDetectflag = YoloDetectPinHoleInfer(frame, vecObj, model_pinhole,true);
//最后一个标志位可设置是否显示弹窗画面
(10)qmake编译,后运行程序,即可看到弹出的识别结果。注意初始化设置的图像大小,和用来测试的图像大小必须保持一致。
参考链接如下:
YOLOV8+TensorRT8.6.1.6+Win10+QT5.9.9推理部署(打包为dll)_yolov8的tensorrt推理封装为dll-CSDN博客
部署实战 | 手把手教你在Windows下用TensorRT部署YOLOv8_yolov8 tensorrt部署-CSDN博客