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

【测试通过环境】
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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

五、Nginx配置文件-server模块

目录 一、概述 二、虚拟主机设置的三种形式 1、基于端口号配置 2、基于域名配置 3、基于ip配置 三、常用参数 1、listen 2、server_name 3、location 3.1、常见的Nginx正则表达式 3.2、location正则&#xff1a; 3.3示例 4、root 5、index 6、error_page 7、deny…

长亭培训加复习安全产品类别

下面这个很重要参加hw时要问你用的安全产品就有这个 检测类型产品 偏审计 安全防御类型 EDR类似于杀毒软件 安全评估 任何东西都要经过这个机械勘察才能上线 安全管理平台 比较杂 比较集成 审计 漏扫 评估 合在这一个平台 也有可能只是管理 主机理解为一个电脑 安了终端插件…

LLM资料大全:文本多模态大模型、垂直领域微调模型、STF数据集、训练微调部署框架、提示词工程等

前言 自ChatGPT为代表的大语言模型&#xff08;Large Language Model, LLM&#xff09;出现以后&#xff0c;由于其惊人的类通用人工智能&#xff08;AGI&#xff09;的能力&#xff0c;掀起了新一轮[自然语言处理]领域的研究和应用的浪潮。尤其是以ChatGLM、LLaMA等平民玩家都…

SM5101 SOP-8 充电+触摸+发执丝控制多合一IC触摸打火机专用IC

SM5101 SOP-8 2.7V 涓流充电 具电池过充过放 触摸控制 发热丝电流控制多功能为一体专用芯片 昱灿-海川 SM5101 SOP-8 充电触摸发执丝控制多合一IC触摸打火机方案 &#xff01;&#xff01;&#xff01; 简介&#xff1a; SM5101是一款针对电子点烟器的专用芯片&#xff0c;具…

阻塞IO、非阻塞IO、IO复用的区别 ?(非常详细)零基础入门到精通,收藏这一篇就够了

前言 在《Unix网络编程》一书中提到了五种IO模型&#xff0c;分别是&#xff1a;阻塞IO、非阻塞IO、IO复用、信号驱动IO以及异步IO。本篇文章主要介绍IO的基本概念以及阻塞IO、非阻塞IO、IO复用三种模型&#xff0c;供大家参考学习。 一、什么是IO 计算机视角理解IO: 对于计…

苹果电脑装虚拟机和双系统的区别 苹果笔记本虚拟机和双系统哪个好 虚拟机能装MacOS吗 虚拟机类似的软件

Mac电脑用户在需要使用Windows操作系统的软件时&#xff0c;通常会面临两个选择&#xff1a;安装双系统或使用虚拟机。两种方式各有优缺点&#xff0c;适用于不同的使用场景。本文将详细分析和说明Mac电脑装双系统和虚拟机之间的区别&#xff0c;帮助用户选择最适合自己的方案。…

UnityAPI学习之协程原理与作用

协程的原理与作用 Unity 协程(Coroutine)原理与用法详解_unity coroutine-CSDN博客 using System.Collections; using System.Collections.Generic; using UnityEngine;public class NO14_coroutine : MonoBehaviour {Animator animator;// Start is called before the first…

Qt MaintenanceTool.exe使用镜像源更新Qt

环境&#xff1a;Windows11&#xff0c;Qt6.5&#xff0c;新版的MaintenanceTool.exe linux环境类似&#xff0c;mac环境可以看官方文档。 cmd命令窗口&#xff1a;切换到MaintenanceTool.exe所在目录&#xff0c;可以用“D:”切换到D盘&#xff0c;“cd xxxx”切换到xxxx目录…

护眼台灯哪个品牌更好?五款市面主流的护眼台灯款式分享

近年来&#xff0c;护眼台灯的研发和创新不断推进&#xff0c;一些台灯配备了智能化功能&#xff0c;如定时开关机、自动调节光线等&#xff0c;使孩子们能够更好地控制用眼时间和光线环境。护眼台灯哪个品牌更好&#xff1f;一些高端的护眼台灯还采用了纳米光滤镜技术&#xf…

深度学习实战P10车牌识别

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊](https://mtyjkh.blog.csdn.net/)** 引言 学习目标 一、前期准备 1.设置GPU …

强化RAG:微调Embedding还是LLM?

为什么我们需要微调&#xff1f; 微调有利于提高模型的效率和有效性。它可以减少训练时间和成本&#xff0c;因为它不需要从头开始。此外&#xff0c;微调可以通过利用预训练模型的功能和知识来提高性能和准确性。它还提供对原本无法访问的任务和领域的访问&#xff0c;因为它…

​​Vitis HLS 学习笔记--添加 RTL 黑盒函数

目录 1. 简介 2. 用法详解 2.1 需要的文件 2.1.1 RTL 函数签名 2.1.2 黑盒 JSON 描述文件 2.1.3 RTL IP 文件 2.2 操作步骤 3. 总结 1. 简介 Vitis HLS 工具可以将现有的 Verilog RTL IP&#xff08;即硬件描述语言编写的模块&#xff09;集成到 C/C HLS 项目中。通过…

短剧分销小程序:影视产业链中的新兴力量

一、引言 在数字化浪潮的推动下&#xff0c;影视产业正迎来一场深刻的变革。短剧分销小程序作为这场变革中的新兴力量&#xff0c;正以其独特的魅力和价值&#xff0c;逐渐在影视产业链中崭露头角。本文将探讨短剧分销小程序在影视产业链中的新兴地位、其带来的变革以及未来的…

Transformer系列:图文详解Decoder解码器原理

从本节开始本系列将对Transformer的Decoder解码器进行深入分析。 内容摘要 Encoder-Decoder框架简介shifted right移位训练解码器的并行训练和串行预测解码器自注意力层和掩码解码器交互注意力层和掩码解码器输出和损失函数 Encoder-Decoder框架简介 在原论文中Transformer用…

LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】

LeetCode-2779. 数组的最大美丽值【数组 二分查找 排序 滑动窗口】 题目描述&#xff1a;解题思路一&#xff1a;滑动窗口与排序解题思路二&#xff1a;0解题思路三&#xff1a;0 题目描述&#xff1a; 给你一个下标从 0 开始的整数数组 nums 和一个 非负 整数 k 。 在一步操…

【嵌入式】一种优雅的 bootloader 跳转APP 的方式

【嵌入式】一种优雅的 bootloader 跳转APP 的方式 0. 个人简介 && 授权须知1. 前言2. 干净的跳转3.程序的 noinit 段4. 利用noinit段实现优雅的跳转4.1 检查栈顶地址是否合法4.2 栈顶地址 44.3 __set_MSP 5.OTA 过后的运行逻辑 0. 个人简介 && 授权须知 &#…

MongoDB 多层级查询

多层级查询 注意&#xff1a;要注意代码顺序 查询层级数据代码放前面&#xff0c;查询条件放后面 if (StringUtils.isBlank(params.getDocType())) {params.setDocType(DOC_TDCTYPE);}String docName mapper.findByDocInfo(params.getDocType());List<ExpertApprovalOpin…

怎么把Rmvb改成mp4格式?把rmvb改成MP4格式的四种方法

怎么把Rmvb改成mp4格式&#xff1f;在当今的数字时代&#xff0c;视频文件格式的多样性给我们带来了巨大的便利&#xff0c;但也可能带来一些兼容性的问题。rmvb是一种曾经非常流行的视频文件格式&#xff0c;主要由于其较高的压缩效率和相对不错的画质。然而&#xff0c;随着技…

计算机组成原理学习 Part 1

计算机系统 组成 计算机系统 { 硬件 计算机的实体&#xff0c;如主机、外设等 软件 由具有各类特殊功能的信息&#xff08;程序&#xff09;组成 计算机系统 \begin{cases} 硬件 &\text 计算机的实体&#xff0c;如主机、外设等\\ 软件 &\text 由具有各类特殊功能的信…

把Vue项目从Window系统迁移到Mac系统的方案

不能启动vue ui 直接运行&#xff0c;会报错如下&#xff1a; failed to load config from /Users/xiaochen/IdeaProjects/ChatViewer-frontend/vite.config.tserror when starting dev server: Error: You installed esbuild for another platform than the one youre curre…