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

发布于:2025-06-08 ⋅ 阅读:(17) ⋅ 点赞:(0)

目录

一、部署环境说明:

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

三、基于TensorRT将onnx模型转为.engine 或者.trt格式的模型

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

五、基于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文件,文件内容如下:

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格式的模型

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

      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生成动态链接库配置

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

       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)解决方案文件配置

    1. 下载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博客