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
#include
#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
#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)
{
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 netOutputImg;
net.forward(netOutputImg, net.getUnconnectedOutLayersNames());
vector classIds;
vector confidences;
vector 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 nms_result;
NMSBoxes(boxes,confidences,_classThreshold,_nmsThreshold,nms_result);
for(size_t i =0; i result, vector color)
{
for (size_t i=0; i
#include "yolo.h"
#include
#include
using namespace std;
using namespace cv;
using namespace cv::dnn;
#include "yolo.h"
#include
//#include
#include
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 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 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 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!"<
我用摄像头直接读取处理,发现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博客
!