服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - c++调用实现yolov5转onnx介绍

c++调用实现yolov5转onnx介绍

2022-07-22 10:31小军军军军军军 C/C++

大家好,本篇文章主要讲的是c++调用实现yolov5转onnx介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览

介绍

现在很多开发都是需要用c++做最后一步的移植部署,手写吧,先不说你会不会浪费时间,网上找吧,问题千奇百怪,所以给大家出这篇文章,做雷锋教学,话不多说,开始

训练模型.pt转onnx

训练部分根据呼声再决定要不要写一份博客吧!!
注意事项:
1.训练代码一定要选择yolov5 5.0版本
2. 进入models/exprort.py;

c++调用实现yolov5转onnx介绍

3.将红框区域换成你自己的训练完的模型

c++调用实现yolov5转onnx介绍

4.将版本换成12;

c++调用实现yolov5转onnx介绍

5.直接运行即可,会生成出onnx的模型出来。

c++代码解析

博主使用的是opencv4.5.3版本,已经编译好的,需要直接扫码加我发你

main函数部分

c++调用实现yolov5转onnx介绍

读取模型利用的是dnn::readnet,opencv其实挺强大的博主已经读过tf模型,torch模型后续都会出对应博客,这里总共有三点改,输入图片path,输入类别名class_names,net部分改成自己的模型

net.set这些参数都固定就好,有兴趣的同学可以研究研究dnn_target_cpu这个地方,是可以使用gpu和cuda的,但是博主还没复现过

推理部分讲解

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
void postprocess(cv::mat& cv_src, std::vector<cv::mat>& outs, const std::vector<std::string>& classes, int net_size)
{
    float confthreshold = 0.1f;
    float nmsthreshold = 0.1f;
    std::vector<int> classids;
    std::vector<float> confidences;
    std::vector<cv::rect> boxes;
    int strides[] = { 8, 16, 32 };
    std::vector<std::vector<int> > anchors =
    {
        { 10,13, 16,30, 33,23 },
        { 30,61, 62,45, 59,119 },
        { 116,90, 156,198, 373,326 }
    };
    for (size_t k = 0; k < outs.size(); k++)
    {
        float* data = outs[k].ptr<float>();
        int stride = strides[k];
        int num_classes = outs[k].size[4] - 5;
        for (int i = 0; i < outs[k].size[2]; i++)
        {
            for (int j = 0; j < outs[k].size[3]; j++)
            {
                for (int a = 0; a < outs[k].size[1]; ++a)
                {
                    float* record = data + a * outs[k].size[2] * outs[k].size[3] * outs[k].size[4] +
                        i * outs[k].size[3] * outs[k].size[4] + j * outs[k].size[4];
                    float* cls_ptr = record + 5;
                    for (int cls = 0; cls < num_classes; cls++)
                    {
                        float score = sigmoid(cls_ptr[cls]) * sigmoid(record[4]);
                        if (score > confthreshold)
                        {
                            float cx = (sigmoid(record[0]) * 2.f - 0.5f + (float)j) * (float)stride;
                            float cy = (sigmoid(record[1]) * 2.f - 0.5f + (float)i) * (float)stride;
                            float w = pow(sigmoid(record[2]) * 2.f, 2) * anchors[k][2 * a];
                            float h = pow(sigmoid(record[3]) * 2.f, 2) * anchors[k][2 * a + 1];
                            float x1 = std::max(0, std::min(cv_src.cols, int((cx - w / 2.f) * (float)cv_src.cols / (float)net_size)));
                            float y1 = std::max(0, std::min(cv_src.rows, int((cy - h / 2.f) * (float)cv_src.rows / (float)net_size)));
                            float x2 = std::max(0, std::min(cv_src.cols, int((cx + w / 2.f) * (float)cv_src.cols / (float)net_size)));
                            float y2 = std::max(0, std::min(cv_src.rows, int((cy + h / 2.f) * (float)cv_src.rows / (float)net_size)));
                            classids.push_back(cls);
                            confidences.push_back(score);
                            boxes.push_back(cv::rect(cv::point(x1, y1), cv::point(x2, y2)));
                        }
                    }
                }
            }
        }
    }
    std::vector<int> indices;
    cv::dnn::nmsboxes(boxes, confidences, confthreshold, nmsthreshold, indices);
    for (size_t i = 0; i < indices.size(); i++)
    {
        int idx = indices[i];
        cv::rect box = boxes[idx];
        drawpred(classids[idx], confidences[idx], box.x, box.y,
            box.x + box.width, box.y + box.height, cv_src, classes);
    }
}

抬头部分是两大目标检测的阈值设置,然后anchors这些都不建议动,除非你在训练的时候用了你自己生成的anchors的话,就改成你自己的,然后根据训练推理后,会生成我们所对应的坐标框以及分数,将分数和狂送到容器中,dnn中有nms等底层函数哦
cv::dnn::nmsboxes(boxes, confidences, confthreshold, nmsthreshold, indices);
对应输入就可以了,然后得到我们的box,index,和置信度,接下来就到了我们的画图环节。

darpred部分

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void drawpred(int classid, float conf, int left, int top, int right, int bottom, cv::mat& frame,
    const std::vector<std::string>& classes)
{
    cv::rectangle(frame, cv::point(left, top), cv::point(right, bottom), cv::scalar(0, 255, 0), 3);
    std::string label = cv::format("%.2f", conf);
    if (!classes.empty()) {
        cv_assert(classid < (int)classes.size());
        label = classes[classid] + ": " + label;
    }
    int baseline;
    cv::size labelsize = cv::gettextsize(label, cv::font_hershey_simplex, 0.5, 1, &baseline);
    top = std::max(top, labelsize.height);
    cv::rectangle(frame, cv::point(left, top - round(1.5 * labelsize.height)), cv::point(left + round(1.5 * labelsize.width), top + baseline), cv::scalar(0, 255, 0), cv::filled);
    cv::puttext(frame, label, cv::point(left, top), cv::font_hershey_simplex, 0.75, cv::scalar(), 2);
}

sigmod部分

?
1
2
3
4
inline float sigmoid(float x)
{
    return 1.f / (1.f + exp(-x));
}

结尾

到此这篇关于c++调用实现yolov5转onnx介绍的文章就介绍到这了,更多相关c++ yolov5转onnx内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/xiaojunjun200211/article/details/121784214

延伸 · 阅读

精彩推荐