当前位置:   article > 正文

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

[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/

【部分实现代码】

  1. #include <CLI/CLI.hpp>
  2. #include <chrono>
  3. #include <filesystem>
  4. #include <fstream>
  5. #include <iostream>
  6. #include <memory>
  7. #include <opencv2/opencv.hpp>
  8. #include <random>
  9. #include <string>
  10. #include <algorithm>
  11. #include "deploy/utils/utils.hpp"
  12. #include "deploy/vision/detection.hpp"
  13. #include "deploy/vision/result.hpp"
  14. #include <opencv2/core/core.hpp>
  15. #include <opencv2/highgui/highgui.hpp>
  16. using namespace cv;
  17. using namespace std;
  18. namespace fs = std::filesystem;
  19. std::string getFileExtension(const std::string& filePath) {
  20. size_t dotPosition = filePath.rfind('.'); // 从右向左查找'.'的位置
  21. if (dotPosition == std::string::npos) {
  22. // 没有找到'.',返回空字符串
  23. return "";
  24. }
  25. return filePath.substr(dotPosition + 1); // 返回'.'之后的所有字符
  26. }
  27. // Get image files in a directory
  28. std::vector<std::string> getImagesInDirectory(const std::string &folderPath)
  29. {
  30. std::vector<std::string> imageFiles;
  31. for (const auto &entry : fs::directory_iterator(folderPath))
  32. {
  33. const auto extension = entry.path().extension().string();
  34. if (fs::is_regular_file(entry) && (extension == ".jpg" || extension == ".png" || extension == ".jpeg" || extension == ".bmp"))
  35. {
  36. imageFiles.push_back(entry.path().string());
  37. }
  38. }
  39. return imageFiles;
  40. }
  41. // Get file name from file path
  42. std::string getFileName(const std::string &filePath)
  43. {
  44. return fs::path(filePath).filename().string();
  45. }
  46. // Create output directory
  47. void createOutputDirectory(const std::string &outputPath)
  48. {
  49. if (!fs::exists(outputPath) && !fs::create_directories(outputPath))
  50. {
  51. std::cerr << "Failed to create output directory: " << outputPath << std::endl;
  52. exit(1);
  53. }
  54. else if (!fs::is_directory(outputPath))
  55. {
  56. std::cerr << "Output path exists but is not a directory: " << outputPath << std::endl;
  57. exit(1);
  58. }
  59. }
  60. // Generate label and color pairs
  61. std::vector<std::pair<std::string, cv::Scalar>> generateLabelColorPairs(const std::string &labelFile)
  62. {
  63. std::vector<std::pair<std::string, cv::Scalar>> labelColorPairs;
  64. std::ifstream file(labelFile);
  65. if (!file.is_open())
  66. {
  67. std::cerr << "Failed to open labels file: " << labelFile << std::endl;
  68. return labelColorPairs;
  69. }
  70. auto generateRandomColor = []()
  71. {
  72. std::random_device rd;
  73. std::mt19937 gen(rd());
  74. std::uniform_int_distribution<int> dis(0, 255);
  75. return cv::Scalar(dis(gen), dis(gen), dis(gen));
  76. };
  77. std::string label;
  78. while (std::getline(file, label))
  79. {
  80. labelColorPairs.emplace_back(label, generateRandomColor());
  81. }
  82. return labelColorPairs;
  83. }
  84. // Visualize detection results
  85. void visualize(cv::Mat &image, const deploy::DetectionResult &result, const std::vector<std::pair<std::string, cv::Scalar>> &labelColorPairs)
  86. {
  87. for (size_t i = 0; i < result.num; ++i)
  88. {
  89. const auto &box = result.boxes[i];
  90. int cls = result.classes[i];
  91. float score = result.scores[i];
  92. const auto &label = labelColorPairs[cls].first;
  93. const auto &color = labelColorPairs[cls].second;
  94. std::string labelText = label + " " + cv::format("%.2f", score);
  95. // Draw rectangle and label
  96. cv::rectangle(image, cv::Point(box.left, box.top), cv::Point(box.right, box.bottom), color, 2, cv::LINE_AA);
  97. int baseLine;
  98. cv::Size labelSize = cv::getTextSize(labelText, cv::FONT_HERSHEY_SIMPLEX, 0.6, 1, &baseLine);
  99. cv::rectangle(image, cv::Point(box.left, box.top - labelSize.height), cv::Point(box.left + labelSize.width, box.top), color, -1);
  100. cv::putText(image, labelText, cv::Point(box.left, box.top), cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(255, 255, 255), 1);
  101. }
  102. }
  103. // Process a single image
  104. 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)
  105. {
  106. cv::Mat cvimage = cv::imread(imagePath, cv::IMREAD_COLOR);
  107. if (cvimage.empty())
  108. {
  109. std::cerr << "Failed to read image: " << imagePath << std::endl;
  110. return;
  111. }
  112. // 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.
  113. deploy::Image image(cvimage.data, cvimage.cols, cvimage.rows);
  114. std::cout << "start inference\n";
  115. auto result = model->predict(image);
  116. std::cout << "inference over!\n";
  117. if (!outputPath.empty())
  118. {
  119. std::cout << "show result\n";
  120. // cv::cvtColor(cvimage, cvimage, cv::COLOR_RGB2BGR);
  121. visualize(cvimage, result, labels);
  122. cv::imwrite(outputPath + "/" + getFileName(imagePath), cvimage);
  123. }
  124. else
  125. {
  126. std::cout << "outputPath is empty\n";
  127. }
  128. }
  129. void processVideo(const std::string &videoPath, const std::shared_ptr<deploy::DeployDet> &model, const std::vector<std::pair<std::string, cv::Scalar>> &labels)
  130. {
  131. VideoCapture capture(videoPath);
  132. if (!capture.isOpened())
  133. return;
  134. double fps = capture.get(cv::CAP_PROP_FPS); // 帧率
  135. int width = capture.get(cv::CAP_PROP_FRAME_WIDTH); // 视频帧宽度
  136. int height = capture.get(cv::CAP_PROP_FRAME_HEIGHT); // 视频帧高度
  137. while (1)
  138. {
  139. Mat frame;
  140. capture >> frame; // 从相机读取新一帧
  141. if (frame.empty())
  142. {
  143. std::cout << "read over!\n";
  144. break;
  145. }
  146. deploy::Image image(frame.data, frame.cols, frame.rows);
  147. auto result = model->predict(image);
  148. // cv::cvtColor(cvimage, cvimage, cv::COLOR_RGB2BGR);
  149. visualize(frame, result, labels);
  150. cv::imshow("result", frame);
  151. if (char(waitKey(2)) == 'q')
  152. {
  153. break;
  154. }
  155. }
  156. capture.release();
  157. cv::destroyAllWindows();
  158. }
  159. // Process a batch of images
  160. 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)
  161. {
  162. const size_t batchSize = model->batch;
  163. deploy::GpuTimer gpuTimer;
  164. deploy::CpuTimer<std::chrono::high_resolution_clock> cpuTimer;
  165. int count = 0;
  166. for (size_t i = 0; i < imageFiles.size(); i += batchSize)
  167. {
  168. std::vector<cv::Mat> images;
  169. std::vector<std::string> imgNameBatch;
  170. for (size_t j = i; j < i + batchSize && j < imageFiles.size(); ++j)
  171. {
  172. cv::Mat image = cv::imread(imageFiles[j], cv::IMREAD_COLOR);
  173. if (image.empty())
  174. {
  175. std::cerr << "Failed to read image: " << imageFiles[j] << std::endl;
  176. continue;
  177. }
  178. // 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.
  179. images.push_back(image);
  180. imgNameBatch.push_back(getFileName(imageFiles[j]));
  181. }
  182. if (images.empty())
  183. continue;
  184. std::vector<deploy::Image> imgBatch;
  185. for (const auto &image : images)
  186. {
  187. imgBatch.emplace_back(image.data, image.cols, image.rows);
  188. }
  189. if (i > 5)
  190. {
  191. cpuTimer.start();
  192. gpuTimer.start();
  193. }
  194. auto results = model->predict(imgBatch);
  195. if (i > 5)
  196. {
  197. cpuTimer.stop();
  198. gpuTimer.stop();
  199. count++;
  200. }
  201. if (!outputPath.empty())
  202. {
  203. for (size_t j = 0; j < images.size(); ++j)
  204. {
  205. // cv::cvtColor(images[j], images[j], cv::COLOR_RGB2BGR);
  206. visualize(images[j], results[j], labels);
  207. cv::imwrite(outputPath + "/" + imgNameBatch[j], images[j]);
  208. }
  209. }
  210. }
  211. if (count > 0)
  212. {
  213. std::cout << "Average infer CPU elapsed time: " << cpuTimer.microseconds() / 1000 / count << " ms" << std::endl;
  214. std::cout << "Average infer GPU elapsed time: " << gpuTimer.microseconds() / 1000 / count << " ms" << std::endl;
  215. }
  216. }
  217. int main(int argc, char **argv)
  218. {
  219. CLI::App app{"YOLO Series Inference Script"};
  220. std::string enginePath, inputPath, outputPath, labelPath;
  221. app.add_option("-e,--engine", enginePath, "Serialized TensorRT engine")->required()->check(CLI::ExistingFile);
  222. app.add_option("-i,--input", inputPath, "Path to image or directory")->required()->check(CLI::ExistingPath);
  223. app.add_option("-o,--output", outputPath, "Directory to save results");
  224. app.add_option("-l,--labels", labelPath, "File to use for reading the class labels from")->check(CLI::ExistingFile);
  225. CLI11_PARSE(app, argc, argv);
  226. std::cout << "load engine...\n";
  227. auto model = std::make_shared<deploy::DeployDet>(enginePath);
  228. std::cout << "engine loaded!\n";
  229. std::vector<std::pair<std::string, cv::Scalar>> labels;
  230. if (!outputPath.empty())
  231. {
  232. labels = generateLabelColorPairs(labelPath);
  233. createOutputDirectory(outputPath);
  234. }
  235. if (fs::is_regular_file(inputPath))
  236. {
  237. if(getFileExtension(inputPath)=="mp4")
  238. {
  239. processVideo(inputPath, model, labels);
  240. }else{
  241. std::cout << "start process image file\n";
  242. processSingleImage(inputPath, model, outputPath, labels);
  243. }
  244. }
  245. else
  246. {
  247. std::cout << "start process image directory\n";
  248. auto imageFiles = getImagesInDirectory(inputPath);
  249. if (!imageFiles.empty())
  250. {
  251. processBatchImages(imageFiles, model, outputPath, labels);
  252. }
  253. else
  254. {
  255. std::cerr << "No images found in directory: " << inputPath << std::endl;
  256. return 1;
  257. }
  258. }
  259. std::cout << "Inference completed." << std::endl;
  260. return 0;
  261. }

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/728294
推荐阅读
相关标签
  

闽ICP备14008679号