赞
踩
yolov5-6.2版本可以用export.py导出onnx格式的模型:
python export.py --weights yolov5n.pt yolov5n.onnx
yolov5n.pt我是直接在这里下载的:https://github.com/ultralytics/yolov5/releases/tag/v6.2
- // https://github.com/UNeedCryDear/yolov5-opencv-dnn-cpp
-
- #pragma once
- #include<iostream>
- #include<opencv2/opencv.hpp>
-
- #define YOLO_P6 false //是否使用P6模型
-
- struct Output {
- int id; //结果类别id
- float confidence; //结果置信度
- cv::Rect box; //矩形框
- };
-
- class Yolov5 {
- public:
- Yolov5() {
- }
- ~Yolov5() {}
- bool readModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);
- bool Detect(cv::Mat& SrcImg, cv::dnn::Net& net, std::vector<Output>& output);
- void drawPred(cv::Mat& img, std::vector<Output> result, std::vector<cv::Scalar> color);
-
- private:
-
- void LetterBox(const cv::Mat& image, cv::Mat& outImage,
- cv::Vec4d& params, //[ratio_x,ratio_y,dw,dh]
- const cv::Size& newShape = cv::Size(640, 640),
- bool autoShape = false,
- bool scaleFill = false,
- bool scaleUp = true,
- int stride = 32,
- const cv::Scalar& color = cv::Scalar(114, 114, 114));
-
-
-
- const int _netWidth = 640; //ONNX图片输入宽度
- const int _netHeight = 640; //ONNX图片输入高度
-
-
- float _classThreshold = 0.25;
- float _nmsThreshold = 0.45;
-
- std::vector<std::string> _className = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
- "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
- "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
- "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
- "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
- "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
- "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
- "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
- "hair drier", "toothbrush" };
- };
- #include "yolo.h"
- using namespace std;
- using namespace cv;
- using namespace cv::dnn;
-
-
- void Yolov5::LetterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,
- bool autoShape, bool scaleFill, bool scaleUp, int stride, const cv::Scalar& color)
- {
- Size shape = image.size();
- float r = std::min((float)newShape.width / (float)shape.width,
- (float)newShape.height / (float)shape.height); // 选出较小的缩放比,否则会超过
-
- float ratio[2]{r, r};
-
- int new_up_pad[2] ={(int)round((float)shape.width * r),
- (int)round((float)shape.height * r)}; // 缩放后与目标长宽可能还差一点
-
- auto dw = (float)(newShape.width - new_up_pad[0]);// 算出与目标长宽差多少
- auto dh = (float)(newShape.height - new_up_pad[1]);
- dw /= 2.0f;
- dh /= 2.0f;
-
- if (shape.width != new_up_pad[0] && shape.height != new_up_pad[1])//等比例缩放
- {
- resize(image, outImage, Size(new_up_pad[0], new_up_pad[1]));
- }
- else {
- outImage = image.clone();
- }
-
- int top = int(round(dh - 0.1f)); // 四周用0来填充
- int bottom = int(round(dh + 0.1f));
- int left = int(round(dw - 0.1f));
- int right = int(round(dw + 0.1f));
- params[0] = ratio[0];
- params[1] = ratio[1];
- params[2] = left;
- params[3] = top;
- copyMakeBorder(outImage, outImage, top, bottom, left, right,BORDER_CONSTANT,color);
- }
-
-
- bool Yolov5::readModel(Net &net, string &netPath, bool isCuda)
- {
- try {
- // net = readNet(netPath);
- net = readNetFromONNX(netPath);
-
- } catch (const std::exception&) {
- return false;
-
- }
-
- if (isCuda)
- {
- net.setPreferableBackend(DNN_BACKEND_CUDA);
- net.setPreferableTarget(DNN_TARGET_CUDA);
- }
- else
- {
- net.setPreferableBackend(DNN_BACKEND_OPENCV);
- net.setPreferableTarget(DNN_TARGET_CPU);
- }
- return true;
- }
-
- bool Yolov5::Detect(Mat &SrcImg, Net &net, vector<Output> &output)
- {
-
- Mat blob;
- int col = SrcImg.cols;
- int row = SrcImg.rows;
- int maxLen = MAX(col, row);
- Mat netinputImg = SrcImg.clone();
- Vec4d params;
- LetterBox(SrcImg, netinputImg, params, Size(_netWidth, _netHeight));
-
- blobFromImage(netinputImg, blob, 1/255.0, Size(_netWidth, _netHeight),Scalar(0,0,0), true, false);
- //如果在其他设置没有问题的情况下但是结果偏差很大,可以尝试下用下面两句语句
- //blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(104, 117, 123), true, false);
- //blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(114, 114,114), true, false);
-
- net.setInput(blob);
- vector<Mat> netOutputImg;
- net.forward(netOutputImg, net.getUnconnectedOutLayersNames());
-
-
- vector<int> classIds;
- vector<float> confidences;
- vector<Rect> boxes;
-
- float ratio_h = (float)netinputImg.rows / _netWidth; // 此时为1
- float ratio_w = (float)netinputImg.cols / _netWidth;
- int net_width = _className.size() + 5;
- int net_out_width = netOutputImg[0].size[2];
- CV_Assert(net_out_width == net_width);
-
- float* pdata = (float*)netOutputImg[0].data;
- int net_height = netOutputImg[0].size[1];
- for (int r = 0; r < net_height; ++r) // 下一个框)
- {
- float box_score = pdata[4];
- if (box_score >= _classThreshold)
- {
- Mat scores(1, _className.size(), CV_32FC1, pdata+5);
- Point classIdPoint;
- double max_class_score;
-
- minMaxLoc(scores, 0, &max_class_score,0, &classIdPoint);
- max_class_score = max_class_score * box_score;
- if(max_class_score > _classThreshold)
- {
- float x = (pdata[0] - params[2]) / params[0]; // 缩放、padding后,-》原图
- float y = (pdata[1] - params[3]) / params[1]; // params: out // in
- float w = pdata[2] / params[0];
- float h = pdata[3] / params[1];
- int left = MAX(round(x - 0.5 * w), 0);
- int top = MAX(round(y - 0.5*h), 0);
-
- classIds.push_back(classIdPoint.x);
- confidences.push_back(max_class_score);
- boxes.push_back(Rect(left, top, round( w * ratio_w), round(h * ratio_h)));// ??
- }
- }
- pdata += net_width;
-
- }
-
-
- // 执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)
- vector<int> nms_result;
- NMSBoxes(boxes,confidences,_classThreshold,_nmsThreshold,nms_result);
-
- for(size_t i =0; i<nms_result.size(); i++)
- {
- int idx = nms_result[i];
- Output result;
- result.id = classIds[idx];
- result.confidence = confidences[idx];
- result.box = boxes[idx];
- output.push_back(result);
- }
- if (output.size())
- return true;
- else
- return false;
-
-
- }
-
- void Yolov5::drawPred(Mat &img, vector<Output> result, vector<Scalar> color)
- {
- for (size_t i=0; i<result.size(); i++)
- {
- int left, top;
- left = result[i].box.x;
- top = result[i].box.y;
- int color_num = i;
- rectangle(img, result[i].box, color[result[i].id],2,8);
-
- string label = _className[result[i].id] + ":" + to_string(result[i].confidence);
-
- int baseLine;
- Size labeSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
- top = top - labeSize.height;
- putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 1, color[result[i].id], 2);
- }
-
-
-
-
- // imshow("1", img);
-
-
- // waitKey();
-
- }
-
- #include "yolo.h"
- #include<math.h>
- #include<iostream>
-
- using namespace std;
- using namespace cv;
- using namespace cv::dnn;
-
-
-
- #include "yolo.h"
- #include <iostream>
- //#include<opencv2//opencv.hpp>
- #include<math.h>
-
- using namespace std;
- using namespace cv;
- using namespace dnn;
-
- int main()
- {
- string img_path = "/home/jason/work/01-img/dog2.png";
- string model_path = "/home/jason/PycharmProjects/pytorch_learn/yolov5-6.2/yolov5n.onnx";
- //int num_devices = cv::cuda::getCudaEnabledDeviceCount();
- //if (num_devices <= 0) {
- //cerr << "There is no cuda." << endl;
- //return -1;
- //}
- //else {
- //cout << num_devices << endl;
- //}
-
- Yolov5 test;
- Net net;
- if (test.readModel(net, model_path, false)) {
- cout << "read net ok!" << endl;
- }
- else {
- return -1;
- }
-
- //生成随机颜色
- vector<Scalar> color;
- srand(time(0));
- for (int i = 0; i < 80; i++) {
- int b = rand() % 256;
- int g = rand() % 256;
- int r = rand() % 256;
- color.push_back(Scalar(b, g, r));
- }
- vector<Output> result;
- // Mat img = imread(img_path);
-
- VideoCapture capture(2);
- Mat img;
-
- while (1)
- {
- capture >>img;
- test.Detect(img, net, result);
- // if (test.Detect(img, net, result))
- {
- test.drawPred(img, result, color);
- result.erase(result.begin(), result.end());
-
- vector<double> layersTimes;
- double freq = getTickFrequency() / 1000; // https://blog.csdn.net/chaipp0607/article/details/71056580
- double t = net.getPerfProfile(layersTimes) / freq;
- string label = format("%s Inference time : %.2f ms", "yolov5n", t);
- putText(img, label, Point(0, 30), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255),2);
-
- // }
- // else
- // {
- // cout << "Detect Failed!"<<endl;
- // }
- imshow("1", img);
-
- if (waitKey(1) == 27) break;
-
- }
-
-
-
- // system("pause");
- return 0;
- }
我用摄像头直接读取处理,发现yolov5n 运行起来有点卡,AMD R5300H CPU 的耗时是150ms左右,而 同样设备Pytorch Python 推理 只有几十ms耗时!!
欢迎留言、欢迎交流!!
参考:
GitHub - UNeedCryDear/yolov5-opencv-dnn-cpp: 使用opencv模块部署yolov5-6.0版本
2021.11.01 c++下 opencv部署yolov5-6.0版本 (四)_怎么查看yolov5版本_爱晚乏客游的博客-CSDN博客
!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。