win10+TensorRT+OpenCV+Qt+YOLOV8模型部署教程

目录

一、部署环境说明:

二、基于yolov8在自定义数据集上进行训练

[三、基于TensorRT将onnx模型转为.engine 或者.trt格式的模型](#三、基于TensorRT将onnx模型转为.engine 或者.trt格式的模型)

四、基于VS2019生成动态链接库配置

[五、基于Qt creator调用yolov模型实现检测](#五、基于Qt creator调用yolov模型实现检测)


一、部署环境说明:

  1. 系统:win10专业版
  2. TensorRT版本:TensorRT-8.5.2.2
  3. OpneCV版本:OpenCV4.7.0
  4. ultralytics版本:ultralytics-8.3.88
  5. CUDA版本:11.7
  6. CUDNN版本:8.6.5
  7. QT Creator版本:16.0.1(QT 版本为6.8.3)

二、基于yolov8在自定义数据集上进行训练

(1)图像数据制作,标签制作

通常采用labelme标注工具进行数据标注,数据保存格式选择为yolo。

(2)模型训练

  1. 在Github上下载ultralytics,链接:GitHub - ultralytics/ultralytics: Ultralytics YOLO11 🚀
  2. 使用anaconda 安装python虚拟环境。
  3. 在python虚拟环境中安装GPU版本的torch。注意安装的时候需要VPN翻墙安装,不要使用清华源,因为清华源没有GPU版本的torch。torch环境配置如下:

4.使用pycharm 打开ultralytics工程文件,根目录下创建train,py文件,文件内容如下:

python 复制代码
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模型

转换代码如下:

python 复制代码
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格式的模型

  1. 下载tensorRT,下载链接:++TensorRT SDK | NVIDIA Developer++
  2. 将下载后的文件进行解压,在系统环境中配置,如下图所示。

3.进入tensorRT的bin目录下,并将onnx模型拷贝到bin目录下

4.输入命令行代码,即可获得best.engine。

cpp 复制代码
trtexec.exe --onnx=best.onnx --saveEngine=best.engine  --buildOnly --minShapes=images:1x3x640x640 --optShapes=images:4x3x640x640 --maxShapes=images:8x3x640x640

四、基于VS2019生成动态链接库配置

  1. 新建一个动态链接库的工程项目。

2.配置opencv,cuda, tenorRT的属性表

(1)TensorRT配置表如下:

附件依赖项:

nvinfer.lib

nvinfer_plugin.lib

nvonnxparser.lib

nvparsers.lib

(2)OpenCV配置表如下:

(3)CUDA配置表如下:

直接拷贝CUDA安装目录下现成的文件,一般在CUDA的默认安装地址:

cpp 复制代码
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.7\extras\visual_studio_integration\MSBuildExtensions\CUDA 11.7.props

(4)解决方案文件配置

  1. 下载TensorRT-Alpha,下载链接:TensorRT-alpha

2.下载后解压TensorRT-Alpha

  1. 按照下图进行文件配置

上图中红色圈中的为添加的现有文件,绿色圈的文件为新建的文件。其中utils中所有文件是从TensorRT-Alpha中直接拷贝过来,如图:

其中源文件中的红色圈中的文件为yolov8文件夹中直接拷贝,如图所示:

资源文件中文件为TensorRT-8.5.2.2文件夹中直接拷贝过来,如下图所示

4.源文件项中新建的fuelpinhole.h文件的内容如下:

cpp 复制代码
#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文件的内容如下:

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文件,如下:

cpp 复制代码
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

cpp 复制代码
#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中定义如下:

cpp 复制代码
private:

    Ui::MainWindow *ui;

    YOLOV8* model_pinhole;

(9)在mainwindow.cpp中添加代码

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博客++