当前位置:   article > 正文

opencv dnn模块实现Yolov5_6.1_opencv加载yolov5

opencv加载yolov5

yolov5 6.1同时支持Opencv dnn、TensorRT、Edge TPU和OpenVINO模块部署,在工程实现上就方便多了。

Yolov5_6.1

首先要将pt文件导出为onnx模型文件

运行export.py,--weights参数后加pt模型文件路径,结束后得到.onnx后缀的文件。

python export.py --weights yolov5s.pt --include torchscript onnx

接下来就是opencv dnn的实现了,官方给了参考Github,不过如果是自己训练的模型,需要注意的是:

1、

将74行        const int dimensions = 85;

改为        const int dimensions = 5+类别数;

2、

将110行        data += 85;

改为         data += dimensions;

---------------------------------------------------------------------------

当模型的imgsz改变时,下面的值也要做相应改变

const float INPUT_WIDTH = 640.0;
const float INPUT_HEIGHT = 640.0;
const int rows = 25200;

Netron Viewer也可以看出来模型输出大小

下面自己C++封装了一个类:

头文件:

  1. #include <fstream>
  2. #include <sstream>
  3. #include <iostream>
  4. #include <opencv2/dnn.hpp>
  5. #include <opencv2/imgproc.hpp>
  6. #include <opencv2/highgui.hpp>
  7. using namespace cv;
  8. using namespace dnn;
  9. using namespace std;
  10. class YOLO
  11. {
  12. public:
  13. struct Detection
  14. {
  15. int class_id;
  16. float confidence;
  17. Rect box;
  18. };
  19. public:
  20. YOLO();
  21. ~YOLO();
  22. void loadNet(bool is_cuda);
  23. Mat formatYolov5(const Mat &source);
  24. void detect(Mat &image,vector<Detection> &output);
  25. void drawRect(Mat &image,vector<Detection> &output);
  26. private:
  27. Net m_net;
  28. //修改为训练时自己模型Img大小
  29. float inputWidth = 320.0;
  30. float inputHeight = 320.0;
  31. //修改 dimensions = 类别数 + 5
  32. const int dimensions = 9;
  33. //修改 通过Netron可查看,图片大小320,rows为6300,图片大小640,rows为25200
  34. const int rows = 6300;
  35. float scoreThreshold = 0.2;
  36. float nmsThreshold = 0.4;
  37. float confThreshold = 0.4;
  38. public:
  39. //修改为自己的类别数
  40. const vector<string> m_classNames = { "class1","class2","class3","class4" };
  41. const vector<Scalar> colors = { Scalar(255, 255, 0), Scalar(0, 255, 0), Scalar(0, 255, 255), Scalar(255, 0, 0) };
  42. };

cpp文件:

  1. #include "yolov5.h"
  2. YOLO::YOLO()
  3. {
  4. loadNet(false);
  5. }
  6. YOLO::~YOLO()
  7. {
  8. }
  9. void YOLO::loadNet(bool is_cuda)
  10. {
  11. m_net = readNet("/home/yolov5.6.1/best.onnx");
  12. if (is_cuda)
  13. {
  14. cout << "Attempty to use CUDA\n";
  15. m_net.setPreferableBackend(DNN_BACKEND_CUDA);
  16. m_net.setPreferableTarget(DNN_TARGET_CUDA_FP16);
  17. }
  18. else
  19. {
  20. cout << "Running on CPU\n";
  21. m_net.setPreferableBackend(DNN_BACKEND_OPENCV);
  22. m_net.setPreferableTarget(DNN_TARGET_CPU);
  23. }
  24. }
  25. Mat YOLO::formatYolov5(const Mat &source)
  26. {
  27. int col = source.cols;
  28. int row = source.rows;
  29. int _max = MAX(col, row);
  30. Mat result(_max, _max, CV_8UC3, Scalar(255));
  31. source.copyTo(result(Rect(0, 0, col, row)));
  32. return result;
  33. }
  34. void YOLO::detect(Mat &image, vector<Detection> &output)
  35. {
  36. Mat blob;
  37. auto input_image = formatYolov5(image);
  38. blobFromImage(input_image, blob, 1. / 255., Size(inputWidth, inputHeight), Scalar(), true, false);
  39. m_net.setInput(blob);
  40. vector<Mat> outputs;
  41. vector<String> strs {m_net.getUnconnectedOutLayersNames().back()};
  42. m_net.forward(outputs, strs);
  43. float x_factor = float(input_image.cols) / inputWidth;
  44. float y_factor = float(input_image.rows) / inputHeight;
  45. float *data = (float *)outputs[0].data;
  46. vector<int> class_ids;
  47. vector<float> confidences;
  48. vector<Rect> boxes;
  49. for (int i = 0; i < rows; ++i)
  50. {
  51. float confidence = data[4];
  52. if (confidence >= confThreshold)
  53. {
  54. float * classes_scores = data + 5;
  55. Mat scores(1, m_classNames.size(), CV_32FC1, classes_scores);
  56. Point class_id;
  57. double max_class_score;
  58. minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
  59. if (max_class_score > scoreThreshold)
  60. {
  61. confidences.push_back(confidence);
  62. class_ids.push_back(class_id.x);
  63. float x = data[0];
  64. float y = data[1];
  65. float w = data[2];
  66. float h = data[3];
  67. int left = int((x - 0.5 * w) * x_factor);
  68. int top = int((y - 0.5 * h) * y_factor);
  69. int width = int(w * x_factor);
  70. int height = int(h * y_factor);
  71. boxes.push_back(Rect(left, top, width, height));
  72. }
  73. }
  74. data += dimensions;
  75. }
  76. vector<int> nms_result;
  77. NMSBoxes(boxes, confidences, scoreThreshold, nmsThreshold, nms_result);
  78. for (int i = 0; i < nms_result.size(); i++)
  79. {
  80. int idx = nms_result[i];
  81. Detection result;
  82. result.class_id = class_ids[idx];
  83. result.confidence = confidences[idx];
  84. result.box = boxes[idx];
  85. output.push_back(result);
  86. }
  87. }
  88. void YOLO::drawRect(Mat &image,vector<Detection> &output)
  89. {
  90. int detections = output.size();
  91. for (int i = 0; i < detections; ++i)
  92. {
  93. auto detection = output[i];
  94. auto box = detection.box;
  95. auto classId = detection.class_id;
  96. const auto color = colors[classId % colors.size()];
  97. rectangle(image, box, color, 3);
  98. rectangle(image, Point(box.x, box.y - 40), Point(box.x + box.width, box.y), color, FILLED);
  99. putText(image, m_classNames[classId].c_str(), Point(box.x, box.y - 5), FONT_HERSHEY_SIMPLEX, 1.5, Scalar(0, 0, 0), 2);
  100. }
  101. }

使用:

  1. #include "yolov5.h"
  2. #include <iomanip>
  3. int main(int argc, char **argv)
  4. {
  5. Mat frame;
  6. VideoCapture capture("/home/yolov5.6.1/1.mp4");
  7. if (!capture.isOpened())
  8. {
  9. std::cerr << "Error opening video file\n";
  10. return -1;
  11. }
  12. YOLO yolov5;
  13. int frame_count = 0;
  14. float fps = -1;
  15. int total_frames = 0;
  16. auto start = std::chrono::high_resolution_clock::now();
  17. while ( true )
  18. {
  19. capture.read(frame);
  20. if (frame.empty())
  21. {
  22. std::cout << "End of stream\n";
  23. break;
  24. }
  25. ++frame_count;
  26. std::vector<YOLO::Detection> output;
  27. yolov5.detect(frame, output);
  28. yolov5.drawRect(frame, output);
  29. if (frame_count >= 30)
  30. {
  31. auto end = std::chrono::high_resolution_clock::now();
  32. fps = frame_count * 1000.0 / std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
  33. start = std::chrono::high_resolution_clock::now();
  34. }
  35. if (fps > 0)
  36. {
  37. std::ostringstream fps_label;
  38. fps_label << std::fixed << setprecision(2);
  39. fps_label << "FPS: " << fps;
  40. std::string fps_label_str = fps_label.str();
  41. cv::putText(frame, fps_label_str.c_str(), cv::Point(20, 50), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 0, 255), 2);
  42. }
  43. namedWindow("output", WINDOW_NORMAL);
  44. imshow("output", frame);
  45. if (waitKey(1) != -1)
  46. {
  47. std::cout << "finished by user\n";
  48. break;
  49. }
  50. }
  51. std::cout << "Total frames: " << total_frames << "\n";
  52. return 0;
  53. }

运行结果:

同样是CPU,dnn速度反而没有原算法的快,不知道其他人是不是也是这样 ,想要C++运行一些神经网络算法,速度不能落下啊。

参考:

https://github.com/doleron/yolov5-opencv-cpp-python/blob/main/cpp/yolo.cpp

 OpenVino实现yolov5.6:

OpenVINO实现yolov5 6.1版本(基于NCS2加速,C++)

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

闽ICP备14008679号