yolov5-onnx + opencv-DNN

 直接用yolov5-yolov5s转onnx,在OpenCV-DNN上使用

#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;

struct Net_config
{
    float confThreshold; // class Confidence threshold
    float nmsThreshold;  // Non-maximum suppression threshold
    float objThreshold;  //Object Confidence threshold
    string netname;
};

class YOLO
{
public:
    YOLO(Net_config config);
    void detect(Mat& frame);
private:
    const float anchors[3][6] = { {10.0, 13.0, 16.0, 30.0, 33.0, 23.0}, {30.0, 61.0, 62.0, 45.0, 59.0, 119.0},{116.0, 90.0, 156.0, 198.0, 373.0, 326.0} };
    const float stride[3] = { 8.0, 16.0, 32.0 };
    const string classesFile = "coco.names";
    const int inpWidth = 640;
    const int inpHeight = 640;
    float confThreshold;
    float nmsThreshold;
    float objThreshold;

    char netname[20];
    vector<string> classes;
    Net net;
    void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame);
    void sigmoid(Mat* out, int length);
};

static inline float sigmoid_x(float x)
{
    return static_cast<float>(1.f / (1.f + exp(-x)));
}



Net_config yolo_nets[4] = {
    {0.5, 0.5, 0.5, "model_s/yolov5s"},     //model_s/yolov5s    //这里加载模型文件//
    {0.5, 0.5, 0.5,  "yolov5m"},
    {0.5, 0.5, 0.5, "yolov5l"},
    {0.5, 0.5, 0.5, "yolov5x"}
};

YOLO::YOLO(Net_config config)
{
    cout << "Net use " << config.netname << endl;
    this->confThreshold = config.confThreshold;
    this->nmsThreshold = config.nmsThreshold;
    this->objThreshold = config.objThreshold;
    /strcpy_s(this->netname, config.netname.c_str());   //这里跳过,直接用string即可//

    ifstream ifs(this->classesFile.c_str());
    string line;
    while (getline(ifs, line)) this->classes.push_back(line);

    string modelFile = config.netname + ".onnx";//this->netname;
    this->net = readNet(modelFile);
}

void YOLO::drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame)   // Draw the predicted bounding box
{
    //Draw a rectangle displaying the bounding box
    rectangle(frame, Point(left, top), Point(right, bottom), Scalar(0, 0, 255), 3);

    //Get the label for the class name and its confidence
    string label = format("%.2f", conf);
    label = this->classes[classId] + ":" + label;

    //Display the label at the top of the bounding box
    int baseLine;
    Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
    top = max(top, labelSize.height);
    //rectangle(frame, Point(left, top - int(1.5 * labelSize.height)), Point(left + int(1.5 * labelSize.width), top + baseLine), Scalar(0, 255, 0), FILLED);
    putText(frame, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 255, 0), 1);
}

void YOLO::sigmoid(Mat* out, int length)
{
    float* pdata = (float*)(out->data);
    int i = 0;
    for (i = 0; i < length; i++)
    {
        pdata[i] = 1.0 / (1 + expf(-pdata[i]));
    }
}

void YOLO::detect(Mat& frame)
{
    Mat blob;
    blobFromImage(frame, blob, 1 / 255.0, Size(this->inpWidth, this->inpHeight), Scalar(0, 0, 0), true, false);
    this->net.setInput(blob);
    vector<Mat> outs;
    this->net.forward(outs, this->net.getUnconnectedOutLayersNames());

    /generate proposals
    vector<int> classIds;
    vector<float> confidences;
    vector<Rect> boxes;
    float ratioh = (float)frame.rows / this->inpHeight, ratiow = (float)frame.cols / this->inpWidth;
    int n = 0, q = 0, i = 0, j = 0, nout = this->classes.size() + 5, c = 0;
    for (n = 0; n < 3; n++)   ///尺度
    {
        int num_grid_x = (int)(this->inpWidth / this->stride[n]);
        int num_grid_y = (int)(this->inpHeight / this->stride[n]);
        int area = num_grid_x * num_grid_y;
        this->sigmoid(&outs[n], 3 * nout * area);
        for (q = 0; q < 3; q++)    ///anchor数
        {
            const float anchor_w = this->anchors[n][q * 2];
            const float anchor_h = this->anchors[n][q * 2 + 1];
            float* pdata = (float*)outs[n].data + q * nout * area;
            for (i = 0; i < num_grid_y; i++)
            {
                for (j = 0; j < num_grid_x; j++)
                {
                    float box_score = pdata[4 * area + i * num_grid_x + j];
                    if (box_score > this->objThreshold)
                    {
                        float max_class_socre = 0, class_socre = 0;
                        int max_class_id = 0;
                        for (c = 0; c < this->classes.size(); c++)  get max socre
                        {
                            class_socre = pdata[(c + 5) * area + i * num_grid_x + j];
                            if (class_socre > max_class_socre)
                            {
                                max_class_socre = class_socre;
                                max_class_id = c;
                            }
                        }

                        if (max_class_socre > this->confThreshold)
                        {
                            float cx = (pdata[i * num_grid_x + j] * 2.f - 0.5f + j) * this->stride[n];  ///cx
                            float cy = (pdata[area + i * num_grid_x + j] * 2.f - 0.5f + i) * this->stride[n];   ///cy
                            float w = powf(pdata[2 * area + i * num_grid_x + j] * 2.f, 2.f) * anchor_w;   ///w
                            float h = powf(pdata[3 * area + i * num_grid_x + j] * 2.f, 2.f) * anchor_h;  ///h

                            int left = (cx - 0.5 * w) * ratiow;
                            int top = (cy - 0.5 * h) * ratioh;   ///坐标还原到原图上

                            classIds.push_back(max_class_id);
                            confidences.push_back(max_class_socre);
                            boxes.push_back(Rect(left, top, (int)(w * ratiow), (int)(h * ratioh)));
                        }
                    }
                }
            }
        }
    }

    // Perform non maximum suppression to eliminate redundant overlapping boxes with
    // lower confidences
    vector<int> indices;
    NMSBoxes(boxes, confidences, this->confThreshold, this->nmsThreshold, indices);
    for (size_t i = 0; i < indices.size(); ++i)
    {
        int idx = indices[i];
        Rect box = boxes[idx];
        this->drawPred(classIds[idx], confidences[idx], box.x, box.y,
            box.x + box.width, box.y + box.height, frame);
    }
}

int main()
{
    YOLO yolo_model(yolo_nets[0]);
    string imgpath = "v_0.jpg";
    Mat srcimg = imread(imgpath);
    yolo_model.detect(srcimg);

    static const string kWinName = "Deep learning object detection in OpenCV";
    namedWindow(kWinName, WINDOW_NORMAL);
    imshow(kWinName, srcimg);
    waitKey(0);
    destroyAllWindows();
}

YOLOV6-DNN可参考另一篇文章:yolov6-onnx + opencv-DNN

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于将 YOLOv5 转换为 ONNX 格式并使用 DNN 调用的问题,您可以按照以下步骤进行操作: 1. 首先,您需要将 YOLOv5 模型转换为 ONNX 格式。您可以使用官方提供的 `export.py` 脚本来执行此操作。确保您已经安装了 PyTorch 和其他所需的依赖项。 ```bash $ python export.py --weights yolov5s.pt --img 640 --batch 1 ``` 上述命令中的 `--weights` 参数指定了您的 YOLOv5 权重文件的路径,`--img` 参数指定了输入图像的大小,`--batch` 参数指定了批处理大小。您可以根据需要进行调整。 2. 执行上述命令后,将生成一个 `yolov5s.onnx` 文件,这是转换后的 ONNX 模型。 3. 接下来,您可以使用 OpenCVDNN 模块来加载并使用 ONNX 模型。请确保您已经安装了 OpenCV 的正确版本。 ```python import cv2 # 加载模型 net = cv2.dnn.readNetFromONNX('yolov5s.onnx') # 加载图像 image = cv2.imread('image.jpg') # 构建输入 blob blob = cv2.dnn.blobFromImage(image, scalefactor=1/255, size=(640, 640), mean=(0, 0, 0), swapRB=True, crop=False) # 设置输入 blob net.setInput(blob) # 前向推理 outputs = net.forward() # 处理输出 # ... ``` 在上述代码中,您需要将 `'yolov5s.onnx'` 替换为您转换后的 ONNX 模型的路径,并将 `'image.jpg'` 替换为您要进行目标检测的图像。 4. 最后,您可以处理模型的输出以获取检测到的目标信息。具体的处理方式取决于您的应用场景和需求。 请注意,上述步骤仅适用于 YOLOv5,如果您使用的是其他版本的 YOLO,请参考相应版本的文档和代码示例。希望以上信息能对您有所帮助!如果您有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值