赞
踩
yolov5 6.1同时支持Opencv dnn、TensorRT、Edge TPU和OpenVINO模块部署,在工程实现上就方便多了。
首先要将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++封装了一个类:
头文件:
- #include <fstream>
- #include <sstream>
- #include <iostream>
- #include <opencv2/dnn.hpp>
- #include <opencv2/imgproc.hpp>
- #include <opencv2/highgui.hpp>
- using namespace cv;
- using namespace dnn;
- using namespace std;
-
- class YOLO
- {
- public:
- struct Detection
- {
- int class_id;
- float confidence;
- Rect box;
- };
- public:
- YOLO();
- ~YOLO();
- void loadNet(bool is_cuda);
- Mat formatYolov5(const Mat &source);
- void detect(Mat &image,vector<Detection> &output);
- void drawRect(Mat &image,vector<Detection> &output);
- private:
- Net m_net;
- //修改为训练时自己模型Img大小
- float inputWidth = 320.0;
- float inputHeight = 320.0;
- //修改 dimensions = 类别数 + 5
- const int dimensions = 9;
- //修改 通过Netron可查看,图片大小320,rows为6300,图片大小640,rows为25200
- const int rows = 6300;
-
- float scoreThreshold = 0.2;
- float nmsThreshold = 0.4;
- float confThreshold = 0.4;
- public:
- //修改为自己的类别数
- const vector<string> m_classNames = { "class1","class2","class3","class4" };
-
- const vector<Scalar> colors = { Scalar(255, 255, 0), Scalar(0, 255, 0), Scalar(0, 255, 255), Scalar(255, 0, 0) };
- };
cpp文件:
- #include "yolov5.h"
-
- YOLO::YOLO()
- {
- loadNet(false);
- }
-
- YOLO::~YOLO()
- {
-
- }
-
- void YOLO::loadNet(bool is_cuda)
- {
- m_net = readNet("/home/yolov5.6.1/best.onnx");
- if (is_cuda)
- {
- cout << "Attempty to use CUDA\n";
- m_net.setPreferableBackend(DNN_BACKEND_CUDA);
- m_net.setPreferableTarget(DNN_TARGET_CUDA_FP16);
- }
- else
- {
- cout << "Running on CPU\n";
- m_net.setPreferableBackend(DNN_BACKEND_OPENCV);
- m_net.setPreferableTarget(DNN_TARGET_CPU);
- }
- }
-
- Mat YOLO::formatYolov5(const Mat &source)
- {
- int col = source.cols;
- int row = source.rows;
- int _max = MAX(col, row);
- Mat result(_max, _max, CV_8UC3, Scalar(255));
- source.copyTo(result(Rect(0, 0, col, row)));
- return result;
- }
-
- void YOLO::detect(Mat &image, vector<Detection> &output)
- {
- Mat blob;
- auto input_image = formatYolov5(image);
- blobFromImage(input_image, blob, 1. / 255., Size(inputWidth, inputHeight), Scalar(), true, false);
- m_net.setInput(blob);
- vector<Mat> outputs;
- vector<String> strs {m_net.getUnconnectedOutLayersNames().back()};
- m_net.forward(outputs, strs);
- float x_factor = float(input_image.cols) / inputWidth;
- float y_factor = float(input_image.rows) / inputHeight;
- float *data = (float *)outputs[0].data;
-
- vector<int> class_ids;
- vector<float> confidences;
- vector<Rect> boxes;
-
- for (int i = 0; i < rows; ++i)
- {
- float confidence = data[4];
- if (confidence >= confThreshold)
- {
- float * classes_scores = data + 5;
- Mat scores(1, m_classNames.size(), CV_32FC1, classes_scores);
- Point class_id;
- double max_class_score;
- minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
- if (max_class_score > scoreThreshold)
- {
- confidences.push_back(confidence);
- class_ids.push_back(class_id.x);
-
- float x = data[0];
- float y = data[1];
- float w = data[2];
- float h = data[3];
- int left = int((x - 0.5 * w) * x_factor);
- int top = int((y - 0.5 * h) * y_factor);
- int width = int(w * x_factor);
- int height = int(h * y_factor);
- boxes.push_back(Rect(left, top, width, height));
- }
- }
- data += dimensions;
- }
-
- vector<int> nms_result;
- NMSBoxes(boxes, confidences, scoreThreshold, nmsThreshold, nms_result);
- for (int i = 0; i < nms_result.size(); i++)
- {
- int idx = nms_result[i];
- Detection result;
- result.class_id = class_ids[idx];
- result.confidence = confidences[idx];
- result.box = boxes[idx];
- output.push_back(result);
- }
- }
-
- void YOLO::drawRect(Mat &image,vector<Detection> &output)
- {
- int detections = output.size();
- for (int i = 0; i < detections; ++i)
- {
- auto detection = output[i];
- auto box = detection.box;
- auto classId = detection.class_id;
- const auto color = colors[classId % colors.size()];
- rectangle(image, box, color, 3);
-
- rectangle(image, Point(box.x, box.y - 40), Point(box.x + box.width, box.y), color, FILLED);
- putText(image, m_classNames[classId].c_str(), Point(box.x, box.y - 5), FONT_HERSHEY_SIMPLEX, 1.5, Scalar(0, 0, 0), 2);
- }
-
- }
使用:
- #include "yolov5.h"
- #include <iomanip>
- int main(int argc, char **argv)
- {
- Mat frame;
- VideoCapture capture("/home/yolov5.6.1/1.mp4");
- if (!capture.isOpened())
- {
- std::cerr << "Error opening video file\n";
- return -1;
- }
-
- YOLO yolov5;
- int frame_count = 0;
- float fps = -1;
- int total_frames = 0;
- auto start = std::chrono::high_resolution_clock::now();
- while ( true )
- {
- capture.read(frame);
- if (frame.empty())
- {
- std::cout << "End of stream\n";
- break;
- }
- ++frame_count;
- std::vector<YOLO::Detection> output;
- yolov5.detect(frame, output);
- yolov5.drawRect(frame, output);
- if (frame_count >= 30)
- {
- auto end = std::chrono::high_resolution_clock::now();
- fps = frame_count * 1000.0 / std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
- start = std::chrono::high_resolution_clock::now();
- }
-
- if (fps > 0)
- {
- std::ostringstream fps_label;
- fps_label << std::fixed << setprecision(2);
- fps_label << "FPS: " << fps;
- std::string fps_label_str = fps_label.str();
- cv::putText(frame, fps_label_str.c_str(), cv::Point(20, 50), cv::FONT_HERSHEY_SIMPLEX, 2, cv::Scalar(0, 0, 255), 2);
- }
- namedWindow("output", WINDOW_NORMAL);
- imshow("output", frame);
-
- if (waitKey(1) != -1)
- {
- std::cout << "finished by user\n";
- break;
- }
- }
-
- std::cout << "Total frames: " << total_frames << "\n";
- return 0;
- }
运行结果:
同样是CPU,dnn速度反而没有原算法的快,不知道其他人是不是也是这样 ,想要C++运行一些神经网络算法,速度不能落下啊。
参考:
https://github.com/doleron/yolov5-opencv-cpp-python/blob/main/cpp/yolo.cpp
OpenVino实现yolov5.6:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。