当前位置:   article > 正文

c++读取yolov5模型进行目标检测(读取摄像头实时监测)_yolov5 c++视频检测

yolov5 c++视频检测

文章介绍

本文是篇基于yolov5模型的一个工程,主要是利用c++将yolov5模型进行调用并测试,从而实现目标检测任务 任务过程中主要重点有两个,第一 版本问题,第二配置问题

一,所需软件及版本

      训练部分 pytorch==1.13.0  opencv==3.4.1   其他的直接pip即可

      c++部署 

       vs2019或者vs2022    

        libtorch-1.13.0

        opencv==3.4.1    链接:https://pan.baidu.com/s/1XPWUNfS7PTFiDkHTG8yvcQ 
提取码:d9g4

        有的可能需要cmake反正我没用    链接:https://pan.baidu.com/s/1-eLo7ecgQg94Mjtw-pQcXw 
提取码:rg0x

二,安装vs

官网地址:
Visual Studio 较旧的下载 - 2019、2017、2015 和以前的版本

 上诉链接可能为2017推荐安装 Visual Studio Installer  2019或者2022

环境配置以及任务准备可以借鉴我上一篇文章

libtorch-yolov5部署pytorch版本_该醒醒了~的博客-CSDN博客

好的屁话不多说,正文开始

首先在vs中创建新文件

在源文件中新建一个cpp文件,在头文件新建一个.h 头文件

下载yolov5 libtorch

文件链接:https://pan.baidu.com/s/1oIP1btJd10gQddxAHijg7w 
提取码:lntf

  • 粘贴 src/YoloV5.cpp 中的代码到上面的 YoloV5.cpp 文件中
  • 粘贴 nclude/YoloV5.h 中的代码到上面的 YoloV5.h 文件中
  • 更改 YoloV5.cpp 中头文件引入方式为 "YoloV5.h
  • "

改为

 在源文件里新建一个main.cpp 文件 此文件是用来调用yolov5的

将代码复制到main.cpp中

这是读取摄像头实时监测的

  1. #include "YoloV5.h"
  2. int main()
  3. {
  4. // 第二个参数为是否启用 cuda 详细用法可以参考 YoloV5.h 文件
  5. YoloV5 yolo("C:/Users/hwx/Documents/Github/YoloV5-LibTorch/test/yolov5s.cuda.pt", true);
  6. // 读取分类标签(我们用的官方的所以这里是 coco 中的分类)
  7. // 其实这些代码无所谓哪 只是后面预测出来的框没有标签罢了
  8. std::ifstream f("C:/Users/hwx/Documents/Github/YoloV5-LibTorch/test/coco.txt");
  9. std::string name = "";
  10. int i = 0;
  11. std::map<int, std::string> labels;
  12. while (std::getline(f, name))
  13. {
  14. labels.insert(std::pair<int, std::string>(i, name));
  15. i++;
  16. }
  17. // 用 OpenCV 打开摄像头读取文件(你随便咋样获取图片都OK哪)
  18. cv::VideoCapture cap = cv::VideoCapture(0);
  19. // 设置宽高 无所谓多宽多高后面都会通过一个算法转换为固定宽高的
  20. // 固定宽高值应该是你通过YoloV5训练得到的模型所需要的
  21. // 传入方式是构造 YoloV5 对象时传入 width 默认值为 640,height 默认值为 640
  22. cap.set(cv::CAP_PROP_FRAME_WIDTH, 1000);
  23. cap.set(cv::CAP_PROP_FRAME_HEIGHT, 800);
  24. cv::Mat frame;
  25. while (cap.isOpened())
  26. {
  27. // 读取一帧
  28. cap.read(frame);
  29. if (frame.empty())
  30. {
  31. std::cout << "Read frame failed!" << std::endl;
  32. break;
  33. }
  34. // 预测
  35. // 简单吧,两行代码预测结果就出来了,封装的还可以吧 嘚瑟
  36. std::vector<torch::Tensor> r = yolo.prediction(frame);
  37. // 画框根据你自己的项目调用相应的方法,也可以不画框自己处理
  38. frame = yolo.drawRectangle(frame, r[0], labels);
  39. // show 图片
  40. cv::imshow("", frame);
  41. if (cv::waitKey(1) == 27) break;
  42. }
  43. return 0;
  44. }

这个是读取文件夹内所有的图片

  1. #if 0
  2. #include "YOLOv5.h"
  3. #include"Ex.h"
  4. #include<opencv2\opencv.hpp>
  5. #include<io.h>
  6. #include<iostream>
  7. int main()
  8. {
  9. YoloV5 yolo("D:\\Besktop\\best.torchscript.pt", true);
  10. // 读取分类标签
  11. std::ifstream f("D:\\Besktop\\voc.txt");
  12. std::string name = "";
  13. int i = 0;
  14. std::map<int, std::string> labels;
  15. while (std::getline(f, name))
  16. {
  17. labels.insert(std::pair<int, std::string>(i, name));
  18. std::cout << labels << std::endl;
  19. i++;
  20. }
  21. //cv::Mat frame = cv::imread("D:\\Besktop\\000\\划伤_2023032218553818.bmp");
  22. string path = "D:\\Besktop\\000\\";
  23. String dest = "D:\\Besktop\\1\\";
  24. String savedfilename;
  25. int len = path.length();
  26. vector<cv::String> filenames;
  27. cv::glob(path, filenames);
  28. for (int i = 0; i < filenames.size(); i++)
  29. {
  30. Mat frame;
  31. frame = imread(filenames[i], i);
  32. //frame = 255 - frame; //对每一张图片取反
  33. savedfilename = dest + filenames[i].substr(len);
  34. cout << savedfilename << endl;
  35. // 预测
  36. std::vector<torch::Tensor> r = yolo.prediction(frame);
  37. std::cout << r << std::endl;
  38. // 画框
  39. frame = yolo.drawRectangle(frame, r[0], labels);
  40. //bool is = yolo.existencePrediction(r);
  41. //std::cout << is << std::endl;
  42. // show 图片
  43. //cv::imshow("", frame);
  44. //imwrite(fileName, frame);
  45. imwrite(savedfilename, frame);
  46. cv::waitKey(0);
  47. //if (cv::waitKey(1) == 27);
  48. }
  49. return 0;
  50. }
  51. #endif // 0

读取一张图片

  1. #if 1
  2. #include "YoloV5.h"
  3. int main()
  4. {
  5. YoloV5 yolo("../dataset/best.torchscript.pt", true);
  6. // 读取分类标签
  7. std::ifstream f("../dataset/voc.txt");
  8. std::string name = "";
  9. int i = 0;
  10. std::map<int, std::string> labels;
  11. while (std::getline(f, name))
  12. {
  13. labels.insert(std::pair<int, std::string>(i, name));
  14. i++;
  15. }
  16. // 用 OpenCV 打开摄像头读取文件
  17. //cv::VideoCapture cap = cv::VideoCapture(0);
  18. //cap.set(cv::CAP_PROP_FRAME_WIDTH, 1000);
  19. //cap.set(cv::CAP_PROP_FRAME_HEIGHT, 800);
  20. //cv::Mat frame;
  21. //while (cap.isOpened())
  22. //{
  23. // // 读取一帧
  24. // cap.read(frame);
  25. // if (frame.empty())
  26. // {
  27. // std::cout << "Read frame failed!" << std::endl;
  28. // break;
  29. // }
  30. cv::Mat frame = cv::imread("D:\\Besktop\\000\\断栅_2.bmp");
  31. // 预测
  32. std::vector<torch::Tensor> r = yolo.prediction(frame);
  33. std::cout << r << std::endl;
  34. // 画框处理
  35. frame = yolo.drawRectangle(frame, r[0], labels);
  36. // show 图片
  37. cv::imshow("", frame);
  38. cv::waitKey(0);
  39. //if (cv::waitKey(1) == 27) break;
  40. return 0;
  41. }
  42. #endif // 1

在 VC++目录/包含目录 中添加头文件

 

在 VC++目录/库目录 中添加 .lib 库 有就添加没有就不添加

在 输入/附加依赖项 中添加 lib 库名称 有就添加,没有就不添加

路径在你libtorch和opencv文件中的lib文件夹内

  1. torch.lib
  2. torch_cuda.lib
  3. torch_cuda_cu.lib
  4. torch_cuda_cpp.lib
  5. torch_cpu.lib
  6. c10_cuda.lib
  7. caffe2_nvrtc.lib
  8. c10.lib
  9. kineto.lib
  10. dnnl.lib
  11. fbgemm.lib
  12. asmjit.lib
  13. XNNPACK.lib
  14. cpuinfo.lib
  15. clog.lib
  16. libprotoc.lib
  17. pthreadpool.lib
  18. libprotobuf.lib
  19. libprotobuf-lite.lib
  20. opencv_world341.lib

注意   将此libtorch和opencv文件夹下的.dll 文件复制到 你项目文件下的环境内

libtorch   .dll文件打开就可以看到

opencv 的藏得比较深  .......opencv3.4.1\opencv\build\x64\vc15\lib

我的项目文件添加路劲为.......active2\x64\Release

 /INCLUDE:"?ignore_this_library_placeholder@@YAHXZ" 

然后修改main函数中的模型路径和下方的标签路径最后运行就好了

最后我们再来核对一下

程序中将会有这些文件其中 只需要看main.cpp tesst.cpp YOLOV5.h Yolov5.cpp

这些文件

main.cpp在上面有这里就不粘贴了

tesst.cpp

  1. #if 0
  2. #include "YOLOv5.h"
  3. #include"Ex.h"
  4. #include<opencv2\opencv.hpp>
  5. #include<io.h>
  6. #include<iostream>
  7. int main()
  8. {
  9. YoloV5 yolo("D:\\Besktop\\best.torchscript.pt", true);
  10. // 读取分类标签
  11. std::ifstream f("D:\\Besktop\\voc.txt");
  12. std::string name = "";
  13. int i = 0;
  14. std::map<int, std::string> labels;
  15. while (std::getline(f, name))
  16. {
  17. labels.insert(std::pair<int, std::string>(i, name));
  18. std::cout << labels << std::endl;
  19. i++;
  20. }
  21. //cv::Mat frame = cv::imread("D:\\Besktop\\000\\划伤_2023032218553818.bmp");
  22. string path = "D:\\Besktop\\000\\";
  23. String dest = "D:\\Besktop\\1\\";
  24. String savedfilename;
  25. int len = path.length();
  26. vector<cv::String> filenames;
  27. cv::glob(path, filenames);
  28. for (int i = 0; i < filenames.size(); i++)
  29. {
  30. Mat frame;
  31. frame = imread(filenames[i], i);
  32. //frame = 255 - frame; //对每一张图片取反
  33. savedfilename = dest + filenames[i].substr(len);
  34. cout << savedfilename << endl;
  35. // 预测
  36. std::vector<torch::Tensor> r = yolo.prediction(frame);
  37. std::cout << r << std::endl;
  38. // 画框
  39. frame = yolo.drawRectangle(frame, r[0], labels);
  40. //bool is = yolo.existencePrediction(r);
  41. //std::cout << is << std::endl;
  42. // show 图片
  43. //cv::imshow("", frame);
  44. //imwrite(fileName, frame);
  45. imwrite(savedfilename, frame);
  46. cv::waitKey(0);
  47. //if (cv::waitKey(1) == 27);
  48. }
  49. return 0;
  50. }
  51. #endif // 0

yolov5.h

  1. #pragma once
  2. #include <torch/torch.h>
  3. #include <torch/script.h>
  4. #include <opencv2/opencv.hpp>
  5. #include <iostream>
  6. #include <ctime>
  7. /**
  8. * ImageResizeData 图片处理过后保存图片的数据结构
  9. */
  10. class ImageResizeData
  11. {
  12. public:
  13. // 添加处理过后的图片
  14. void setImg(cv::Mat img);
  15. // 获取处理过后的图片
  16. cv::Mat getImg();
  17. // 当原始图片宽高比大于处理过后图片宽高比时此函数返回 true
  18. bool isW();
  19. // 当原始图片高宽比大于处理过后图片高宽比时此函数返回 true
  20. bool isH();
  21. // 添加处理之后图片的宽
  22. void setWidth(int width);
  23. // 获取处理之后图片的宽
  24. int getWidth();
  25. // 添加处理之后图片的高
  26. void setHeight(int height);
  27. // 获取处理之后图片的高
  28. int getHeight();
  29. // 添加原始图片的宽
  30. void setW(int w);
  31. // 获取原始图片的宽
  32. int getW();
  33. // 添加原始图片的高
  34. void setH(int h);
  35. // 获取原始图片的高
  36. int getH();
  37. // 添加从原始图片到处理过后图片所添加黑边大小
  38. void setBorder(int border);
  39. // 获取从原始图片到处理过后图片所添加黑边大小
  40. int getBorder();
  41. private:
  42. // 处理过后图片高
  43. int height;
  44. // 处理过后图片宽
  45. int width;
  46. // 原始图片宽
  47. int w;
  48. // 原始图片高
  49. int h;
  50. // 从原始图片到处理图片所添加的黑边大小
  51. int border;
  52. // 处理过后的图片
  53. cv::Mat img;
  54. };
  55. /**
  56. * YoloV5 的实现类
  57. */
  58. class YoloV5
  59. {
  60. public:
  61. /**
  62. * 构造函数
  63. * @param ptFile yoloV5 pt文件路径
  64. * @param isCuda 是否使用 cuda 默认不起用
  65. * @param height yoloV5 训练时图片的高
  66. * @param width yoloV5 训练时图片的宽
  67. * @param confThres 非极大值抑制中的 scoreThresh
  68. * @param iouThres 非极大值抑制中的 iouThresh
  69. */
  70. YoloV5(std::string ptFile, bool isCuda = false, bool isHalf = false, int height = 640, int width = 640, float confThres = 0.25, float iouThres = 0.45);
  71. /**
  72. * 预测函数
  73. * @param data 语言预测的数据格式 (batch, rgb, height, width)
  74. */
  75. std::vector<torch::Tensor> prediction(torch::Tensor data);
  76. /**
  77. * 预测函数
  78. * @param filePath 需要预测的图片路径
  79. */
  80. std::vector<torch::Tensor> prediction(std::string filePath);
  81. /**
  82. * 预测函数
  83. * @param img 需要预测的图片
  84. */
  85. std::vector<torch::Tensor> prediction(cv::Mat img);
  86. /**
  87. * 预测函数
  88. * @param imgs 需要预测的图片集合
  89. */
  90. std::vector<torch::Tensor> prediction(std::vector <cv::Mat> imgs);
  91. /**
  92. * 改变图片大小的函数
  93. * @param img 原始图片
  94. * @param height 要处理成的图片的高
  95. * @param width 要处理成的图片的宽
  96. * @return 封装好的处理过后图片数据结构
  97. */
  98. static ImageResizeData resize(cv::Mat img, int height, int width);
  99. /**
  100. * 改变图片大小的函数
  101. * @param img 原始图片
  102. * @return 封装好的处理过后图片数据结构
  103. */
  104. ImageResizeData resize(cv::Mat img);
  105. /**
  106. * 改变图片大小的函数
  107. * @param imgs 原始图片集合
  108. * @param height 要处理成的图片的高
  109. * @param width 要处理成的图片的宽
  110. * @return 封装好的处理过后图片数据结构
  111. */
  112. static std::vector<ImageResizeData> resize(std::vector <cv::Mat> imgs, int height, int width);
  113. /**
  114. * 改变图片大小的函数
  115. * @param imgs 原始图片集合
  116. * @return 封装好的处理过后图片数据结构
  117. */
  118. std::vector<ImageResizeData> resize(std::vector <cv::Mat> imgs);
  119. /**
  120. * 根据输出结果在给定图片中画出框
  121. * @param imgs 原始图片集合
  122. * @param rectangles 通过预测函数处理好的结果
  123. * @param labels 类别标签
  124. * @param thickness 线宽
  125. * @return 画好框的图片
  126. */
  127. std::vector<cv::Mat> drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, std::map<int, std::string> labels, int thickness = 2);
  128. /**
  129. * 根据输出结果在给定图片中画出框
  130. * @param imgs 原始图片集合
  131. * @param rectangles 通过预测函数处理好的结果
  132. * @param thickness 线宽
  133. * @return 画好框的图片
  134. */
  135. std::vector<cv::Mat> drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, int thickness = 2);
  136. /**
  137. * 根据输出结果在给定图片中画出框
  138. * @param imgs 原始图片集合
  139. * @param rectangles 通过预测函数处理好的结果
  140. * @param colors 每种类型对应颜色
  141. * @param labels 类别标签
  142. * @return 画好框的图片
  143. */
  144. std::vector<cv::Mat> drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, std::map<int, cv::Scalar> colors, std::map<int, std::string> labels, int thickness = 2);
  145. /**
  146. * 根据输出结果在给定图片中画出框
  147. * @param img 原始图片
  148. * @param rectangle 通过预测函数处理好的结果
  149. * @param thickness 线宽
  150. * @return 画好框的图片
  151. */
  152. cv::Mat drawRectangle(cv::Mat img, torch::Tensor rectangle, int thickness = 2);
  153. /**
  154. * 根据输出结果在给定图片中画出框
  155. * @param img 原始图片
  156. * @param rectangle 通过预测函数处理好的结果
  157. * @param labels 类别标签
  158. * @param thickness 线宽
  159. * @return 画好框的图片
  160. */
  161. cv::Mat drawRectangle(cv::Mat img, torch::Tensor rectangle, std::map<int, std::string> labels, int thickness = 2);
  162. /**
  163. * 根据输出结果在给定图片中画出框
  164. * @param img 原始图片
  165. * @param rectangle 通过预测函数处理好的结果
  166. * @param colos 每种类型对应颜色
  167. * @param labels 类别标签
  168. * @param thickness 线宽
  169. * @return 画好框的图片
  170. */
  171. cv::Mat drawRectangle(cv::Mat img, torch::Tensor rectangle, std::map<int, cv::Scalar> colors, std::map<int, std::string> labels, int thickness = 2);
  172. /**
  173. * 用于判断给定数据是否存在预测
  174. * @param clazz 通过预测函数处理好的结果
  175. * @return 如果图片中存在给定某一种分类返回 true
  176. */
  177. bool existencePrediction(torch::Tensor clazz);
  178. /**
  179. * 用于判断给定数据是否存在预测
  180. * @param classs 通过预测函数处理好的结果
  181. * @return 如果图片集合中存在给定某一种分类返回 true
  182. */
  183. bool existencePrediction(std::vector<torch::Tensor> classs);
  184. private:
  185. // 是否启用 cuda
  186. bool isCuda;
  187. // 是否使用半精度
  188. bool isHalf;
  189. // 非极大值抑制中的第一步数据清理
  190. float confThres;
  191. // 非极大值抑制中 iou
  192. float iouThres;
  193. // 模型所需要的图片的高
  194. float height;
  195. // 模型所需要的图片的宽
  196. float width;
  197. // 画框颜色 map
  198. std::map<int, cv::Scalar> mainColors;
  199. // 模型
  200. torch::jit::script::Module model;
  201. // 随机获取一种颜色
  202. cv::Scalar getRandScalar();
  203. // 图片通道转换为 rgb
  204. cv::Mat img2RGB(cv::Mat img);
  205. // 图片变为 Tensor
  206. torch::Tensor img2Tensor(cv::Mat img);
  207. // (center_x center_y w h) to (left, top, right, bottom)
  208. torch::Tensor xywh2xyxy(torch::Tensor x);
  209. // 非极大值抑制算法
  210. torch::Tensor nms(torch::Tensor bboxes, torch::Tensor scores, float thresh);
  211. // 预测出来的框根据原始图片还原算法
  212. std::vector<torch::Tensor> sizeOriginal(std::vector<torch::Tensor> result, std::vector<ImageResizeData> imgRDs);
  213. // 非极大值抑制算法整体
  214. std::vector<torch::Tensor> non_max_suppression(torch::Tensor preds, float confThres = 0.25, float iouThres = 0.45);
  215. };

 yolov5.cpp

  1. #include "YoloV5.h"
  2. YoloV5::YoloV5(std::string ptFile, bool isCuda, bool isHalf, int height, int width, float confThres, float iouThres)
  3. {
  4. model = torch::jit::load(ptFile);
  5. if (isCuda)
  6. {
  7. model.to(torch::kCUDA);
  8. }
  9. if (isHalf)
  10. {
  11. model.to(torch::kHalf);
  12. }
  13. this->height = height;
  14. this->width = width;
  15. this->isCuda = isCuda;
  16. this->iouThres = iouThres;
  17. this->confThres = confThres;
  18. this->isHalf = isHalf;
  19. model.eval();
  20. unsigned seed = time(0);
  21. std::srand(seed);
  22. }
  23. std::vector<torch::Tensor> YoloV5::non_max_suppression(torch::Tensor prediction, float confThres, float iouThres)
  24. {
  25. torch::Tensor xc = prediction.select(2, 4) > confThres;
  26. int maxWh = 4096;
  27. int maxNms = 30000;
  28. std::vector<torch::Tensor> output;
  29. for (int i = 0; i < prediction.size(0); i++)
  30. {
  31. output.push_back(torch::zeros({ 0, 6 }));
  32. }
  33. for (int i = 0; i < prediction.size(0); i++)
  34. {
  35. torch::Tensor x = prediction[i];
  36. x = x.index_select(0, torch::nonzero(xc[i]).select(1, 0));
  37. if (x.size(0) == 0) continue;
  38. x.slice(1, 5, x.size(1)).mul_(x.slice(1, 4, 5));
  39. torch::Tensor box = xywh2xyxy(x.slice(1, 0, 4));
  40. std::tuple<torch::Tensor, torch::Tensor> max_tuple = torch::max(x.slice(1, 5, x.size(1)), 1, true);
  41. x = torch::cat({ box, std::get<0>(max_tuple), std::get<1>(max_tuple) }, 1);
  42. x = x.index_select(0, torch::nonzero(std::get<0>(max_tuple) > confThres).select(1, 0));
  43. int n = x.size(0);
  44. if (n == 0)
  45. {
  46. continue;
  47. }
  48. else if (n > maxNms)
  49. {
  50. x = x.index_select(0, x.select(1, 4).argsort(0, true).slice(0, 0, maxNms));
  51. }
  52. torch::Tensor c = x.slice(1, 5, 6) * maxWh;
  53. torch::Tensor boxes = x.slice(1, 0, 4) + c, scores = x.select(1, 4);
  54. torch::Tensor ix = nms(boxes, scores, iouThres).to(x.device());
  55. output[i] = x.index_select(0, ix).cpu();
  56. }
  57. return output;
  58. }
  59. cv::Scalar YoloV5::getRandScalar()
  60. {
  61. return cv::Scalar(std::rand() % 256, std::rand() % 256, std::rand() % 256);
  62. }
  63. cv::Mat YoloV5::img2RGB(cv::Mat img)
  64. {
  65. int imgC = img.channels();
  66. if (imgC == 1)
  67. {
  68. cv::cvtColor(img, img, cv::COLOR_GRAY2RGB);
  69. }
  70. else
  71. {
  72. cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
  73. }
  74. return img;
  75. }
  76. torch::Tensor YoloV5::img2Tensor(cv::Mat img)
  77. {
  78. torch::Tensor data = torch::from_blob(img.data, { (int)height, (int)width, 3 }, torch::kByte);
  79. data = data.permute({ 2, 0, 1 });
  80. data = data.toType(torch::kFloat);
  81. data = data.div(255);
  82. data = data.unsqueeze(0);
  83. return data;
  84. }
  85. torch::Tensor YoloV5::xywh2xyxy(torch::Tensor x)
  86. {
  87. torch::Tensor y = x.clone();
  88. y.select(1, 0) = x.select(1, 0) - x.select(1, 2) / 2;
  89. y.select(1, 1) = x.select(1, 1) - x.select(1, 3) / 2;
  90. y.select(1, 2) = x.select(1, 0) + x.select(1, 2) / 2;
  91. y.select(1, 3) = x.select(1, 1) + x.select(1, 3) / 2;
  92. return y;
  93. }
  94. torch::Tensor YoloV5::nms(torch::Tensor bboxes, torch::Tensor scores, float thresh)
  95. {
  96. auto x1 = bboxes.select(1, 0);
  97. auto y1 = bboxes.select(1, 1);
  98. auto x2 = bboxes.select(1, 2);
  99. auto y2 = bboxes.select(1, 3);
  100. auto areas = (x2 - x1) * (y2 - y1);
  101. auto tuple_sorted = scores.sort(0, true);
  102. auto order = std::get<1>(tuple_sorted);
  103. std::vector<int> keep;
  104. while (order.numel() > 0)
  105. {
  106. if (order.numel() == 1)
  107. {
  108. auto i = order.item();
  109. keep.push_back(i.toInt());
  110. break;
  111. }
  112. else
  113. {
  114. auto i = order[0].item();
  115. keep.push_back(i.toInt());
  116. }
  117. auto order_mask = order.narrow(0, 1, order.size(-1) - 1);
  118. auto xx1 = x1.index({ order_mask }).clamp(x1[keep.back()].item().toFloat(), 1e10);
  119. auto yy1 = y1.index({ order_mask }).clamp(y1[keep.back()].item().toFloat(), 1e10);
  120. auto xx2 = x2.index({ order_mask }).clamp(0, x2[keep.back()].item().toFloat());
  121. auto yy2 = y2.index({ order_mask }).clamp(0, y2[keep.back()].item().toFloat());
  122. auto inter = (xx2 - xx1).clamp(0, 1e10) * (yy2 - yy1).clamp(0, 1e10);
  123. auto iou = inter / (areas[keep.back()] + areas.index({ order.narrow(0,1,order.size(-1) - 1) }) - inter);
  124. auto idx = (iou <= thresh).nonzero().squeeze();
  125. if (idx.numel() == 0)
  126. {
  127. break;
  128. }
  129. order = order.index({ idx + 1 });
  130. }
  131. return torch::tensor(keep);
  132. }
  133. std::vector<torch::Tensor> YoloV5::sizeOriginal(std::vector<torch::Tensor> result, std::vector<ImageResizeData> imgRDs)
  134. {
  135. std::vector<torch::Tensor> resultOrg;
  136. for (int i = 0; i < result.size(); i++)
  137. {
  138. torch::Tensor data = result[i];
  139. ImageResizeData imgRD = imgRDs[i];
  140. for (int j = 0; j < data.size(0); j++)
  141. {
  142. torch::Tensor tensor = data.select(0, j);
  143. // (left, top, right, bottom)
  144. if (imgRD.isW())
  145. {
  146. tensor[1] -= imgRD.getBorder();
  147. tensor[3] -= imgRD.getBorder();
  148. tensor[0] *= (float)imgRD.getW() / (float)imgRD.getWidth();
  149. tensor[2] *= (float)imgRD.getW() / (float)imgRD.getWidth();
  150. tensor[1] *= (float)imgRD.getH() / (float)(imgRD.getHeight() - 2 * imgRD.getBorder());
  151. tensor[3] *= (float)imgRD.getH() / (float)(imgRD.getHeight() - 2 * imgRD.getBorder());
  152. }
  153. else
  154. {
  155. tensor[0] -= imgRD.getBorder();
  156. tensor[2] -= imgRD.getBorder();
  157. tensor[1] *= (float)imgRD.getH() / (float)imgRD.getHeight();
  158. tensor[3] *= (float)imgRD.getH() / (float)imgRD.getHeight();
  159. tensor[0] *= (float)imgRD.getW() / (float)(imgRD.getWidth() - 2 * imgRD.getBorder());
  160. tensor[2] *= (float)imgRD.getW() / (float)(imgRD.getWidth() - 2 * imgRD.getBorder());
  161. }
  162. // 加了黑边之后预测结果可能在黑边上,就会造成结果为负数
  163. for (int k = 0; k < 4; k++)
  164. {
  165. if (tensor[k].item().toFloat() < 0)
  166. {
  167. tensor[k] = 0;
  168. }
  169. }
  170. }
  171. resultOrg.push_back(data);
  172. }
  173. return resultOrg;
  174. }
  175. std::vector<torch::Tensor> YoloV5::prediction(torch::Tensor data)
  176. {
  177. if (!data.is_cuda() && this->isCuda)
  178. {
  179. data = data.cuda();
  180. }
  181. if (data.is_cuda() && !this->isCuda)
  182. {
  183. data = data.cpu();
  184. }
  185. if (this->isHalf)
  186. {
  187. data = data.to(torch::kHalf);
  188. }
  189. torch::Tensor pred = model.forward({ data }).toTuple()->elements()[0].toTensor();
  190. return non_max_suppression(pred, confThres, iouThres);
  191. }
  192. std::vector<torch::Tensor> YoloV5::prediction(std::string filePath)
  193. {
  194. cv::Mat img = cv::imread(filePath);
  195. return prediction(img);
  196. }
  197. std::vector<torch::Tensor> YoloV5::prediction(cv::Mat img)
  198. {
  199. ImageResizeData imgRD = resize(img);
  200. cv::Mat reImg = img2RGB(imgRD.getImg());
  201. torch::Tensor data = img2Tensor(reImg);
  202. std::vector<torch::Tensor> result = prediction(data);
  203. std::vector<ImageResizeData> imgRDs;
  204. imgRDs.push_back(imgRD);
  205. return sizeOriginal(result, imgRDs);
  206. }
  207. std::vector<torch::Tensor> YoloV5::prediction(std::vector<cv::Mat> imgs)
  208. {
  209. std::vector<ImageResizeData> imageRDs;
  210. std::vector<torch::Tensor> datas;
  211. for (int i = 0; i < imgs.size(); i++)
  212. {
  213. ImageResizeData imgRD = resize(imgs[i]);
  214. imageRDs.push_back(imgRD);
  215. cv::Mat img = img2RGB(imgRD.getImg());
  216. datas.push_back(img2Tensor(img));
  217. }
  218. torch::Tensor data = torch::cat(datas, 0);
  219. std::vector<torch::Tensor> result = prediction(data);
  220. return sizeOriginal(result, imageRDs);
  221. }
  222. ImageResizeData YoloV5::resize(cv::Mat img, int height, int width)
  223. {
  224. ImageResizeData imgResizeData;
  225. int w = img.cols, h = img.rows;
  226. imgResizeData.setH(h);
  227. imgResizeData.setW(w);
  228. imgResizeData.setHeight(height);
  229. imgResizeData.setWidth(width);
  230. bool isW = (float)w / (float)h > (float)width / (float)height;
  231. cv::resize(img, img, cv::Size(
  232. isW ? width : (int)((float)height / (float)h * w),
  233. isW ? (int)((float)width / (float)w * h) : height));
  234. w = img.cols, h = img.rows;
  235. if (isW)
  236. {
  237. imgResizeData.setBorder((height - h) / 2);
  238. cv::copyMakeBorder(img, img, (height - h) / 2, height - h - (height - h) / 2, 0, 0, cv::BORDER_CONSTANT);
  239. }
  240. else
  241. {
  242. imgResizeData.setBorder((width - w) / 2);
  243. cv::copyMakeBorder(img, img, 0, 0, (width - w) / 2, width - w - (width - w) / 2, cv::BORDER_CONSTANT);
  244. }
  245. imgResizeData.setImg(img);
  246. return imgResizeData;
  247. }
  248. ImageResizeData YoloV5::resize(cv::Mat img)
  249. {
  250. return YoloV5::resize(img, height, width);
  251. }
  252. std::vector<ImageResizeData> YoloV5::resize(std::vector<cv::Mat> imgs, int height, int width)
  253. {
  254. std::vector<ImageResizeData> imgRDs;
  255. for (int i = 0; i < imgs.size(); i++)
  256. {
  257. imgRDs.push_back(YoloV5::resize(imgs[i], height, width));
  258. }
  259. return imgRDs;
  260. }
  261. std::vector<ImageResizeData> YoloV5::resize(std::vector<cv::Mat> imgs)
  262. {
  263. return YoloV5::resize(imgs, height, width);
  264. }
  265. std::vector<cv::Mat> YoloV5::drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, std::map<int, std::string> labels, int thickness)
  266. {
  267. std::map<int, cv::Scalar> colors;
  268. return drawRectangle(imgs, rectangles, colors, labels, thickness);
  269. }
  270. std::vector<cv::Mat> YoloV5::drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, int thickness)
  271. {
  272. std::map<int, cv::Scalar> colors;
  273. std::map<int, std::string> labels;
  274. return drawRectangle(imgs, rectangles, colors, labels, thickness);
  275. }
  276. std::vector<cv::Mat> YoloV5::drawRectangle(std::vector<cv::Mat> imgs, std::vector<torch::Tensor> rectangles, std::map<int, cv::Scalar> colors, std::map<int, std::string> labels, int thickness)
  277. {
  278. std::vector<cv::Mat> results;
  279. for (int i = 0; i < imgs.size(); i++)
  280. {
  281. results.push_back(drawRectangle(imgs[i], rectangles[i], colors, labels, thickness));
  282. }
  283. return results;
  284. }
  285. cv::Mat YoloV5::drawRectangle(cv::Mat img, torch::Tensor rectangle, int thickness)
  286. {
  287. std::map<int, cv::Scalar> colors;
  288. std::map<int, std::string> labels;
  289. return drawRectangle(img, rectangle, colors, labels, thickness);
  290. }
  291. cv::Mat YoloV5::drawRectangle(cv::Mat img, torch::Tensor rectangle, std::map<int, std::string> labels, int thickness)
  292. {
  293. std::map<int, cv::Scalar> colors;
  294. return drawRectangle(img, rectangle, colors, labels, thickness);
  295. }
  296. cv::Mat YoloV5::drawRectangle(cv::Mat img, torch::Tensor rectangle, std::map<int, cv::Scalar> colors, std::map<int, std::string> labels, int thickness)
  297. {
  298. std::map<int, cv::Scalar>::iterator it;
  299. std::map<int, std::string>::iterator labelIt;
  300. for (int i = 0; i < rectangle.size(0); i++)
  301. {
  302. int clazz = rectangle[i][5].item().toInt();
  303. it = colors.find(clazz);
  304. cv::Scalar color = NULL;
  305. if (it == colors.end())
  306. {
  307. it = mainColors.find(clazz);
  308. if (it == mainColors.end())
  309. {
  310. color = getRandScalar();
  311. mainColors.insert(std::pair<int, cv::Scalar>(clazz, color));
  312. }
  313. else
  314. {
  315. color = it->second;
  316. }
  317. }
  318. else
  319. {
  320. color = it->second;
  321. }
  322. cv::rectangle(img, cv::Point(rectangle[i][0].item().toInt(), rectangle[i][1].item().toInt()), cv::Point(rectangle[i][2].item().toInt(), rectangle[i][3].item().toInt()), color, thickness);
  323. labelIt = labels.find(clazz);
  324. std::ostringstream oss;
  325. if (labelIt != labels.end())
  326. {
  327. oss << labelIt->second << " ";
  328. }
  329. oss << rectangle[i][4].item().toFloat();
  330. std::string label = oss.str();
  331. cv::putText(img, label, cv::Point(rectangle[i][0].item().toInt(), rectangle[i][1].item().toInt()), cv::FONT_HERSHEY_PLAIN, 1, color, thickness);
  332. }
  333. return img;
  334. }
  335. bool YoloV5::existencePrediction(torch::Tensor clazz)
  336. {
  337. return clazz.size(0) > 0 ? true : false;
  338. }
  339. bool YoloV5::existencePrediction(std::vector<torch::Tensor> classs)
  340. {
  341. for (int i = 0; i < classs.size(); i++)
  342. {
  343. if (existencePrediction(classs[i]))
  344. {
  345. return true;
  346. }
  347. }
  348. return false;
  349. }
  350. void ImageResizeData::setImg(cv::Mat img)
  351. {
  352. this->img = img;
  353. }
  354. cv::Mat ImageResizeData::getImg()
  355. {
  356. return img;
  357. }
  358. bool ImageResizeData::isW()
  359. {
  360. return (float)w / (float)h > (float)width / (float)height;
  361. }
  362. bool ImageResizeData::isH()
  363. {
  364. return (float)h / (float)w > (float)height / (float)width;
  365. }
  366. void ImageResizeData::setWidth(int width)
  367. {
  368. this->width = width;
  369. }
  370. int ImageResizeData::getWidth()
  371. {
  372. return width;
  373. }
  374. void ImageResizeData::setHeight(int height)
  375. {
  376. this->height = height;
  377. }
  378. int ImageResizeData::getHeight()
  379. {
  380. return height;
  381. }
  382. void ImageResizeData::setW(int w)
  383. {
  384. this->w = w;
  385. }
  386. int ImageResizeData::getW()
  387. {
  388. return w;
  389. }
  390. void ImageResizeData::setH(int h)
  391. {
  392. this->h = h;
  393. }
  394. int ImageResizeData::getH()
  395. {
  396. return h;
  397. }
  398. void ImageResizeData::setBorder(int border)
  399. {
  400. this->border = border;
  401. }
  402. int ImageResizeData::getBorder()
  403. {
  404. return border;
  405. }

 这个效果是读取摄像图进行试试检测博文中有将摄像头替换为图片进行检测的案例

 

看得懂就看,看不懂的评论区问我

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

闽ICP备14008679号