[C++]使用C++部署yolov10目标检测的tensorrt模型支持图片视频推理windows测试通过

news2025/2/24 7:12:26

【测试通过环境】
vs2019
cmake==3.24.3
cuda11.7.1+cudnn8.8.0
tensorrt==8.6.1.6
opencv==4.8.0

【部署步骤】
获取pt模型:https://github.com/THU-MIG/yolov10训练自己的模型或者直接使用yolov10官方预训练模型
下载源码:https://github.com/laugh12321/yolov10/tree/nms并安装到环境中
导出onnx:
yolo export model=yolov10n.pt format=onnx opset=13 simplify max_det=100 conf=0.25 iou=0.65 nms

注意导出模型和官方yolov10指令导出的onnx是不一样的,使用yolov10-nms导出模型结构如图

注意一定要是上面类似结构图才能用于这个C++项目
导出tensorrt:

等20分钟左右即可导出需要耐心等待一段时间视个人电脑性能决定,由于tensorrt依赖硬件不一样电脑可能无法共用tensorrt模型,所以必须要重新转换onnx模型到engine才可以运行。请勿直接使用提供的engine模型进行直接测试,否则可能无法正常运行
trtexec --onnx=yolov10n.onnx --saveEngine=yolov10n.engine --fp16

下载安装vs2019勾选桌面C++安装
git clone https://github.com/laugh12321/TensorRT-YOLO
cd TensorRT-YOLO
xmake f -k shared --tensorrt="C:/Program Files/NVIDIA GPU Computing Toolkit/TensorRT/v8.6.1.6"
xmake -P . -r
将编译好的deploy.dll和deploy.lib文件放到yolov10-tensorrt-cplus/lib文件夹
编译源码yolov10-tensorrt-cplus
运行命令:
推理图片:
yolov10.exe -e C:\Users\Administrator\Desktop\yolov10-tensorrt-cplus\yolov10n.engine -i C:\Users\Administrator\Desktop\yolov10-tensorrt-cplus\images\bus.jpg -o ./out -l C:\Users\Administrator\Desktop\yolov10-tensorrt-cplus\labels.txt

推理视频:
yolov10.exe -e C:\Users\Administrator\Desktop\yolov10-tensorrt-cplus\yolov10n.engine -i D:\car.mp4 -o ./out -l C:\Users\Administrator\Desktop\yolov10-tensorrt-cplus\labels.txt

【视频演示】

使用C++部署yolov10目标检测的tensorrt模型支持图片视频推理windows测试通过_哔哩哔哩_bilibili【测试通过环境】vs2019cmake==3.24.3cuda11.7.1+cudnn8.8.0tensorrt==8.6.1.6opencv==4.8.0更多信息参考博文:https://blog.csdn.net/FL1623863129/article/details/139693743, 视频播放量 3、弹幕量 0、点赞数 0、投硬币枚数 0、收藏人数 0、转发人数 0, 视频作者 未来自主研究中心, 作者简介 未来自主研究中心,相关视频:4060Ti 16G显卡安装Ollama+ChatTTS打造智能语音秘书(突破30秒限制),AI换脸最全面部细节演示:眨眼,捏眉毛,斗鸡眼,戳鼻子,做猪鼻子……认识ai换脸,警惕Ai换脸,Ai变声诈骗!,基于yolo的骑行速度检测,labelme json转yolo工具用于目标检测训练数据集使用教程,使用纯opencv部署yolov8目标检测模型onnx,rk3588 yolov5 目标检测推流rtsp,[深度学习][目标检测][面试提问]Batch Normalization批归一化,[数据集介绍][目标检测]城市街道垃圾数据集VOC格式5266张,GPT:可恶!我好不容易才建立的三观啊!,毕设项目—基于最新YOLOv10+ByteTrack+PaddleOCR实现交通状态分析 (功能:目标检测、轨迹跟踪、车牌检测、车牌号识别、单目测速及目标计数)icon-default.png?t=N7T8https://www.bilibili.com/video/BV13S411P7XL/

【部分实现代码】

#include <CLI/CLI.hpp>
#include <chrono>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <memory>
#include <opencv2/opencv.hpp>
#include <random>
#include <string>  
#include <algorithm> 
#include "deploy/utils/utils.hpp"
#include "deploy/vision/detection.hpp"
#include "deploy/vision/result.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;

namespace fs = std::filesystem;
std::string getFileExtension(const std::string& filePath) {  
    size_t dotPosition = filePath.rfind('.'); // 从右向左查找'.'的位置  
    if (dotPosition == std::string::npos) {  
        // 没有找到'.',返回空字符串  
        return "";  
    }  
    return filePath.substr(dotPosition + 1); // 返回'.'之后的所有字符  
}  
// Get image files in a directory
std::vector<std::string> getImagesInDirectory(const std::string &folderPath)
{
    std::vector<std::string> imageFiles;
    for (const auto &entry : fs::directory_iterator(folderPath))
    {
        const auto extension = entry.path().extension().string();
        if (fs::is_regular_file(entry) && (extension == ".jpg" || extension == ".png" || extension == ".jpeg" || extension == ".bmp"))
        {
            imageFiles.push_back(entry.path().string());
        }
    }
    return imageFiles;
}

// Get file name from file path
std::string getFileName(const std::string &filePath)
{
    return fs::path(filePath).filename().string();
}

// Create output directory
void createOutputDirectory(const std::string &outputPath)
{
    if (!fs::exists(outputPath) && !fs::create_directories(outputPath))
    {
        std::cerr << "Failed to create output directory: " << outputPath << std::endl;
        exit(1);
    }
    else if (!fs::is_directory(outputPath))
    {
        std::cerr << "Output path exists but is not a directory: " << outputPath << std::endl;
        exit(1);
    }
}

// Generate label and color pairs
std::vector<std::pair<std::string, cv::Scalar>> generateLabelColorPairs(const std::string &labelFile)
{
    std::vector<std::pair<std::string, cv::Scalar>> labelColorPairs;
    std::ifstream file(labelFile);
    if (!file.is_open())
    {
        std::cerr << "Failed to open labels file: " << labelFile << std::endl;
        return labelColorPairs;
    }

    auto generateRandomColor = []()
    {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<int> dis(0, 255);
        return cv::Scalar(dis(gen), dis(gen), dis(gen));
    };

    std::string label;
    while (std::getline(file, label))
    {
        labelColorPairs.emplace_back(label, generateRandomColor());
    }
    return labelColorPairs;
}

// Visualize detection results
void visualize(cv::Mat &image, const deploy::DetectionResult &result, const std::vector<std::pair<std::string, cv::Scalar>> &labelColorPairs)
{
    for (size_t i = 0; i < result.num; ++i)
    {
        const auto &box = result.boxes[i];
        int cls = result.classes[i];
        float score = result.scores[i];
        const auto &label = labelColorPairs[cls].first;
        const auto &color = labelColorPairs[cls].second;
        std::string labelText = label + " " + cv::format("%.2f", score);

        // Draw rectangle and label
        cv::rectangle(image, cv::Point(box.left, box.top), cv::Point(box.right, box.bottom), color, 2, cv::LINE_AA);
        int baseLine;
        cv::Size labelSize = cv::getTextSize(labelText, cv::FONT_HERSHEY_SIMPLEX, 0.6, 1, &baseLine);
        cv::rectangle(image, cv::Point(box.left, box.top - labelSize.height), cv::Point(box.left + labelSize.width, box.top), color, -1);
        cv::putText(image, labelText, cv::Point(box.left, box.top), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(255, 255, 255), 1);
    }
}

// Process a single image
void processSingleImage(const std::string &imagePath, const std::shared_ptr<deploy::DeployDet> &model, const std::string &outputPath, const std::vector<std::pair<std::string, cv::Scalar>> &labels)
{
    cv::Mat cvimage = cv::imread(imagePath, cv::IMREAD_COLOR);
    if (cvimage.empty())
    {
        std::cerr << "Failed to read image: " << imagePath << std::endl;
        return;
    }
    // cv::cvtColor(cvimage, cvimage, cv::COLOR_BGR2RGB);  // It is better to use RGB images, but the impact of using BGR on the results is not significant.
    deploy::Image image(cvimage.data, cvimage.cols, cvimage.rows);
    std::cout << "start inference\n";
    auto result = model->predict(image);
    std::cout << "inference over!\n";
    if (!outputPath.empty())
    {
        std::cout << "show result\n";
        // cv::cvtColor(cvimage, cvimage, cv::COLOR_RGB2BGR);
        visualize(cvimage, result, labels);
        cv::imwrite(outputPath + "/" + getFileName(imagePath), cvimage);
    }
    else
    {
        std::cout << "outputPath is empty\n";
    }
}

void processVideo(const std::string &videoPath, const std::shared_ptr<deploy::DeployDet> &model, const std::vector<std::pair<std::string, cv::Scalar>> &labels)
{

    VideoCapture capture(videoPath);
    if (!capture.isOpened())
        return;
    double fps = capture.get(cv::CAP_PROP_FPS);          // 帧率
    int width = capture.get(cv::CAP_PROP_FRAME_WIDTH);   // 视频帧宽度
    int height = capture.get(cv::CAP_PROP_FRAME_HEIGHT); // 视频帧高度
    while (1)
    {
        Mat frame;
        capture >> frame; // 从相机读取新一帧
        if (frame.empty())
        {
            std::cout << "read over!\n";
            break;
        }
        deploy::Image image(frame.data, frame.cols, frame.rows);
        auto result = model->predict(image);
        // cv::cvtColor(cvimage, cvimage, cv::COLOR_RGB2BGR);
        visualize(frame, result, labels);
        cv::imshow("result", frame);
        if (char(waitKey(2)) == 'q')
        {

            break;
        }
    }
    capture.release();
    cv::destroyAllWindows();
}

// Process a batch of images
void processBatchImages(const std::vector<std::string> &imageFiles, const std::shared_ptr<deploy::DeployDet> &model, const std::string &outputPath, const std::vector<std::pair<std::string, cv::Scalar>> &labels)
{
    const size_t batchSize = model->batch;
    deploy::GpuTimer gpuTimer;
    deploy::CpuTimer<std::chrono::high_resolution_clock> cpuTimer;
    int count = 0;

    for (size_t i = 0; i < imageFiles.size(); i += batchSize)
    {
        std::vector<cv::Mat> images;
        std::vector<std::string> imgNameBatch;

        for (size_t j = i; j < i + batchSize && j < imageFiles.size(); ++j)
        {
            cv::Mat image = cv::imread(imageFiles[j], cv::IMREAD_COLOR);
            if (image.empty())
            {
                std::cerr << "Failed to read image: " << imageFiles[j] << std::endl;
                continue;
            }
            // cv::cvtColor(image, image, cv::COLOR_BGR2RGB); // It is better to use RGB images, but the impact of using BGR on the results is not significant.
            images.push_back(image);
            imgNameBatch.push_back(getFileName(imageFiles[j]));
        }

        if (images.empty())
            continue;

        std::vector<deploy::Image> imgBatch;
        for (const auto &image : images)
        {
            imgBatch.emplace_back(image.data, image.cols, image.rows);
        }

        if (i > 5)
        {
            cpuTimer.start();
            gpuTimer.start();
        }

        auto results = model->predict(imgBatch);

        if (i > 5)
        {
            cpuTimer.stop();
            gpuTimer.stop();
            count++;
        }

        if (!outputPath.empty())
        {
            for (size_t j = 0; j < images.size(); ++j)
            {
                // cv::cvtColor(images[j], images[j], cv::COLOR_RGB2BGR);
                visualize(images[j], results[j], labels);
                cv::imwrite(outputPath + "/" + imgNameBatch[j], images[j]);
            }
        }
    }

    if (count > 0)
    {
        std::cout << "Average infer CPU elapsed time: " << cpuTimer.microseconds() / 1000 / count << " ms" << std::endl;
        std::cout << "Average infer GPU elapsed time: " << gpuTimer.microseconds() / 1000 / count << " ms" << std::endl;
    }
}

int main(int argc, char **argv)
{
    CLI::App app{"YOLO Series Inference Script"};

    std::string enginePath, inputPath, outputPath, labelPath;
    app.add_option("-e,--engine", enginePath, "Serialized TensorRT engine")->required()->check(CLI::ExistingFile);
    app.add_option("-i,--input", inputPath, "Path to image or directory")->required()->check(CLI::ExistingPath);
    app.add_option("-o,--output", outputPath, "Directory to save results");
    app.add_option("-l,--labels", labelPath, "File to use for reading the class labels from")->check(CLI::ExistingFile);

    CLI11_PARSE(app, argc, argv);
    std::cout << "load engine...\n";
    auto model = std::make_shared<deploy::DeployDet>(enginePath);
    std::cout << "engine loaded!\n";
    std::vector<std::pair<std::string, cv::Scalar>> labels;
    if (!outputPath.empty())
    {
        labels = generateLabelColorPairs(labelPath);
        createOutputDirectory(outputPath);
    }

    if (fs::is_regular_file(inputPath))
    {
        if(getFileExtension(inputPath)=="mp4")
        {
         processVideo(inputPath, model, labels);
        }else{
        std::cout << "start process image file\n";
        processSingleImage(inputPath, model, outputPath, labels);
        }
      
    }
    else
    {
        std::cout << "start process image directory\n";
        auto imageFiles = getImagesInDirectory(inputPath);
        if (!imageFiles.empty())
        {
            processBatchImages(imageFiles, model, outputPath, labels);
        }
        else
        {
            std::cerr << "No images found in directory: " << inputPath << std::endl;
            return 1;
        }
    }

    std::cout << "Inference completed." << std::endl;
    return 0;
}

【源码下载】https://download.csdn.net/download/FL1623863129/89436042

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1824330.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WinForm之TCP客户端通讯

目录 一 设计界面 二 后台代码 一 设计界面 二 后台代码 using System.Net.Sockets; using System.Text;namespace TCP网络客户端通讯 {public partial class Form1 : Form{public Form1(){InitializeComponent();}TcpClient tcpClient new TcpClient();private void conne…

前端面试项目细节重难点(已工作|做分享)(九)

面试官&#xff1a;请你讲讲你在工作中如何开发一个新需求&#xff0c;你的整个开发过程是什么样的&#xff1f; 答&#xff1a;仔细想想&#xff0c;我开发新需求的过程如下&#xff1a; &#xff08;1&#xff09;第一步&#xff1a;理解需求文档&#xff1a; 首先&#x…

Java核心(四)反射

这篇内容叫反射也不够准确&#xff0c;其实它更像是java类加载的一个延申。 Java类加载过程 之前解释过一个Java的类的加载过程&#xff0c;现在回顾一下类的加载&#xff1a; 类的加载指的是将类的字节码文件&#xff08;.class文件&#xff09;中数据读入到内存中&#xff…

AI办公自动化:kimi批量搜索提取PDF文档中特定文本内容

工作任务&#xff1a;PDF文档中有资料来源这一行&#xff0c;比如&#xff1a; 资料来源&#xff1a;moomoo tech、The Information、Bloomberg、Reuters&#xff0c;浙商证券研究所 数据来源&#xff1a;CSDN、浙商证券研究所 数据来源&#xff1a;CSDN、arXiv、浙商证券研…

精品丨PowerBI迁移到SSAS

业务场景&#xff1a; 企业初期在进行 BI 可视化路线的时候&#xff0c;往往不会选择方案较为完整的SSAS&#xff0c;而是会选择轻量的 PowerBI 方案&#xff0c;究其根本还是软件成本的问题。 但是随着模型越来越臃肿&#xff0c;维护成本越来越高&#xff0c;有很多模型需要进…

VictoriaMetrics的高可用二进制方式部署

参考文章实现&#xff1a;Prometheus联邦集群VictoriaMetrics集群搭建部署 1.基本信息 涉及机器列表&#xff0c;机器均为本地虚拟机 192.168.56.108 192.168.56.109方案实现如下 涉及模块介绍 vmstorage: 数据存储节点&#xff0c;负责存储时序数据vmselect: 数据查询节点…

智慧公安指挥中心大数据信息化两中心两基地系统方案

1.1 系统建设目标 本系统是一个汇接全市的报警求助的大型通信指挥系统&#xff0c;技术难度较高、可靠性要求高&#xff0c;技术路线的选择至关重要。 在充分考虑XX市公安局的业务需要&#xff0c;利用现代通信及计算机网络技术的基础上&#xff0c;最大程度地实现资源整合、…

HO-VMD-TCN:西储大学轴承故障诊断全流程详解

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原理详解 1.数据预处理 2.特征提取 3.故障…

AI Agent学习系列:微信搭配Agent,让微信秒变特工

在之前的文章里介绍了如何把微信变成高考志愿填报小助手&#xff0c;我已经把这个bot发布到了公众号&#xff0c;大家可以直接在公众号消息输入框里提问即可直接使用&#xff0c;如图&#xff1a; 上面说的bot就是智能体&#xff0c;也叫Agent&#xff0c;和英文里特工是一个单…

AMSR-MODIS 边界层水汽 L3 每日 1 度 x 1 度 V1、V2 版本数据集

AMSR-MODIS Boundary Layer Water Vapor L3 Daily 1 degree x 1 degree V1 (AMDBLWV) at GES DISC AMSR-MODIS Boundary Layer Water Vapor L3 Daily 1 degree x 1 degree V2 (AMDBLWV) at GES DISC 简介 该数据集可估算均匀云层下的海洋边界层水汽。AMSR-E 和 AMSR-2 的微波…

2024 年最新基于 LLOneBot NT 框架搭建 QQ 机器人详细教程(更新中)

LLOneBot 概述 llonebot&#xff08;LLOneBot&#xff09;是一个与OneBot&#xff08;也称为CQHTTP&#xff09;协议兼容的机器人框架&#xff0c;它允许开发者使用不同的编程语言&#xff08;如Python、Go、JavaScript等&#xff09;编写机器人应用&#xff0c;并与各种支持 …

观察 jvm 运行时数据区内存大小(native memory tracking)

jvm 运行时数据区 jvm 运行时数据区包括且不限于以下几个部分: 堆(heap): 用于存储对象实例和数组。堆内存的分配和释放由垃圾回收器进行管理。方法区(method area): 用于存储类的信息、静态变量、常量等。jdk 8 后方法区位于 metaspace。虚拟机栈(vm stack): 用于存储方法的…

Mysql之不使用部署在k8s集群的Mysql而是选择单独部署的Mysql的原因

测试准备&#xff1a; 线程组&#xff1a;并发数100&#xff0c;持续时间2min 两个请求&#xff1a;使用k8s集群中的mysql的wordpress对应端口30011 使用单独部署的mysql的wordpress的对应端口为30022 访问同一个博客 测试结果&#xff1a; 汇总报告&#xff1a; 响应时间图&…

16.番外_模拟c语言文件流

16.番外:模拟c语言文件流 一&#xff0c;前言 先来看一下Struct _IO_FILE的定义。 grep -rnw /usr/include/ -e struct _IO_FILE今天我们要做的就是模拟实现FILE及C语言文件操作相关函数 二&#xff0c;开始&#xff01;做吧&#xff01;我们&#xff01; 1.FILE的缓冲区及…

「小爱同学」接入豆包大模型;华为鸿蒙 OS 成为中国第二大操作系统丨 RTE 开发者日报 Vol.224

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

【Android面试八股文】你知道如何实现非阻塞式生产者消费者模式吗?

文章目录 这道题想考察什么 ?考察的知识点日常生活中的生产者消费者模式生产者消费者模式简介为什么需要缓冲区?阻塞与非堵塞非阻塞式生产者消费者模式的实现非阻塞式生产者消费者模式的实现阻塞式生产者消费者模式实现特点这道题想考察什么 ? 是否了解非阻塞式生产者消费者…

R可视化:ggpubr包学习

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者 Xiao hong书&#xff1a;生信学习者 知hu&#xff1a;生信学习者 CDSN&#xff1a;生信学习者2 介绍 ggpubr是我经常会用到的R包&#xff0c;它傻瓜式的画图方式对很多初次接触R绘图的人来…

GO RACE 测试在低版本GCC上报错误 exit status 0xc0000139

windows机器环境&#xff0c;go程序使用race定位时一运行就报错&#xff0c;写了个example如&#xff1a; 能看到加了race之后就不行了&#xff0c; 搜了一下&#xff0c;git上有个issue&#xff1a; runtime: Race detector causes exit status 0xc0000139 on Windows 11 wi…

高考志愿填报选专业,兴趣爱好和就业前景哪个优先?

每个人都有自己的兴趣与爱好&#xff0c;而高考志愿填报是在为自己选择职业方向。最理想的状态就是把自己的兴趣和爱好与自己的职业统一起来&#xff0c;让兴趣和爱好促进职业的发展&#xff0c;为职业增添动力。但现实生活中&#xff0c;这种理想的状态并不是每个人都能达到的…

Java多线程面试重点-2

16.Synchronized关键字加在静态方法和实例方法的区别? 修饰静态方法&#xff0c;是对类进行加锁&#xff08;Class对象&#xff09;&#xff0c;如果该类中有methodA和methodB都是被Synch修饰的静态方法&#xff0c;此时有两个线程T1、T2分别调用methodA()和methodB()&#x…