使用C++版本的opencv dnn 部署onnx模型

使用OpenCV的DNN模块在C++中部署ONNX模型涉及几个步骤,包括加载模型、预处理输入数据、进行推理以及处理输出。

构建了yolo类,方便调用

yolo.h 文件

cpp 复制代码
#ifndef YOLO_H
#define YOLO_H
#include <fstream>
#include <sstream>
#include <iostream>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

struct yoloDetectionResult_detection_thread
{
    cv::Point2f DetectionResultLocation; // 目标中心点像素位置
    cv::Point2d DetectionResultClassAndConf; //类型、置信度
    cv::Rect DetectionResultRect; //目标矩形框
    cv::Mat DetectionResultIMG;   //目标像素
    unsigned char object_no = -1;  //目标序号
    unsigned char object_mission = -1; //目标任务状态
    int frame_no;  //图像帧号
};
class detect_result
{
public:
    int classId;
    float confidence;
    cv::Rect_<float> box;

};

class YOLO
{
public:
    YOLO();
    ~YOLO();
    void init(std::string onnxpath);
    void detect(cv::Mat& frame, std::vector<detect_result>& result);
    void draw_frame(cv::Mat& frame, std::vector<detect_result>& results);

private:
    cv::dnn::Net net;

    const float confidence_threshold_ = 0.4f;
    const float nms_threshold_ = 0.4f;
    const int model_input_width_ = 640;
    const int model_input_height_ = 640;
    double HighWidthHeightRatio = 25;
    double LowWidthHeightRatio = 0.05;
};

#endif // !YOLO_H

yolo.cpp

cpp 复制代码
#include "yolo.h"

YOLO::YOLO()
{

}

YOLO::~YOLO()
{

}

void YOLO::init(std::string onnxpath)
{

    this->net = cv::dnn::readNetFromONNX(onnxpath);
}

void YOLO::detect(cv::Mat& frame, std::vector<detect_result>& results)
{
    int w = frame.cols;
    int h = frame.rows;
    int _max = std::max(h, w);
    cv::Mat image = cv::Mat::zeros(cv::Size(_max, _max), CV_8UC3);
    if(frame.channels()==1){
        cv::cvtColor(frame, frame, cv::COLOR_GRAY2BGR);
    }  
    cv::Rect roi(0, 0, w, h);
    frame.copyTo(image(cv::Rect(0, 0, w, h)));

    float x_factor = static_cast<float>(image.cols) / model_input_width_;
    float y_factor = static_cast<float>(image.rows) / model_input_height_;
    cv::Mat blob = cv::dnn::blobFromImage(image, 1 / 255.0, cv::Size(model_input_width_, model_input_height_), cv::Scalar(0, 0, 0), true, false);
    this->net.setInput(blob);
    cv::Mat preds = this->net.forward("output0");
    //outputname,使用Netron看一下输出的名字,一般为output0或者output
    cv::Mat det_output(preds.size[1], preds.size[2], CV_32F, preds.ptr<float>());

    std::vector<cv::Rect> boxes;
    std::vector<int> classIds;
    std::vector<float> confidences;
    for (int i = 0; i < det_output.rows; i++)
    {
        float box_conf = det_output.at<float>(i, 4);
        if (box_conf < nms_threshold_)
        {
            continue;
        }

        cv::Mat classes_confidences = det_output.row(i).colRange(5, 6);
        cv::Point classIdPoint;
        double cls_conf;
        cv::minMaxLoc(classes_confidences, 0, &cls_conf, 0, &classIdPoint);


        if (cls_conf > confidence_threshold_)
        {
            float cx = det_output.at<float>(i, 0);
            float cy = det_output.at<float>(i, 1);
            float ow = det_output.at<float>(i, 2);
            float oh = det_output.at<float>(i, 3);
            int x = static_cast<int>((cx - 0.5 * ow) * x_factor);
            int y = static_cast<int>((cy - 0.5 * oh) * y_factor);
            int width = static_cast<int>(ow * x_factor);
            int height = static_cast<int>(oh * y_factor);
            cv::Rect box;
            box.x = x;
            box.y = y;
            box.width = width;
            box.height = height;

            boxes.push_back(box);
            classIds.push_back(classIdPoint.x);
            confidences.push_back(cls_conf * box_conf);
        }
    }

    std::vector<int> indexes;
    cv::dnn::NMSBoxes(boxes, confidences, confidence_threshold_, nms_threshold_, indexes);
    for (size_t i = 0; i < indexes.size(); i++)
    {
        detect_result dr;
        int index = indexes[i];
        int idx = classIds[index];
        dr.box = boxes[index];
        dr.classId = idx;
        dr.confidence = confidences[index];
        results.push_back(dr);
    }
    std::vector<cv::Rect>().swap(boxes);
    std::vector<int>().swap( classIds);
    std::vector<float>().swap( confidences);
    std::vector<int>().swap( indexes);
}

void YOLO::draw_frame(cv::Mat& frame, std::vector<detect_result>& results)
{
    for (auto dr : results)
    {

        cv::rectangle(frame, dr.box, cv::Scalar(0, 0, 255), 2, 8);
        cv::rectangle(frame, cv::Point(dr.box.tl().x, dr.box.tl().y - 20), cv::Point(dr.box.br().x, dr.box.tl().y), cv::Scalar(255, 0, 0), -1);

        std::string label = cv::format("%.2f", dr.confidence);
        label = dr.classId + ":" + label;

        cv::putText(frame, label, cv::Point(dr.box.x, dr.box.y + 6), 1, 2, cv::Scalar(0, 255, 0), 2);
    }


}

下面是调用函数编写部分

cpp 复制代码
#include<string>
#include"yolo.h"
#include<opencv2\opencv.hpp>
#include<iostream>
int main(){
    YOLO* yolo = new YOLO;
	std::string modelPath =  "C:\\Resource\\model\\XXX.onnx";//模型的地址
    std::string imgPath=  "C:\\Resource\\model\\XXX.jpg";//模型的地址
	//clock_t start_times{},end_times{};
	yolo->init(modelPath);
	std::vector<detect_result> output;
    cv::Mat yoloImages = cv::imread(imgPath);
    if(!yoloImages.empty()){  
        //start_times= clock();
        yolo->detect(yoloImages, output);
    	yolo->draw_frame(yoloImages, output);
    	//end_times = clock();
    	//double FPS = 1 / ((double)(end_times - start_times) / CLOCKS_PER_SEC);
    	cv::imshow("images", yoloImages);
    	cv::waitKey(1);

        std::vector<detect_result>().swap(output);
        std::string().swap(model);
        if(yolo!=NULL){
            delete yolo;
            yolo =NULL;
        }
    }
}	
相关推荐
汉克老师10 小时前
CSP-J 初赛(以满分为目标):第二十六课 《图的遍历——DFS深度优先搜索——从“树的先序遍历”走进真正的图世界》
c++·csp-j·小学生·学c++编程
程序猿编码10 小时前
基于GGML的C++17轻量化语音推理引擎:说话人识别与语音分析技术全解析
开发语言·c++·pytorch·深度学习·神经网络·大模型
leoZ23111 小时前
第 4 篇:布局骨架——页面壳、栅格、卡片
前端·javascript·vue.js·opencv·计算机视觉·数据挖掘·语音识别
影视飓风TIM11 小时前
C++哈希表深度剖析:冲突处理、rehash、迭代器与unordered容器封装
c++·哈希算法·散列表
C++ 老炮儿的技术栈11 小时前
Qt5 使用 QPainter 绘制阿基米德螺线
开发语言·c++·windows·qt·代码化
xxwxx__12 小时前
深入理解 C++ STL:stack、queue 与 deque 从使用到底层实现全解析
开发语言·c++·算法
wuminyu12 小时前
JVM锁膨胀与Futex源码解析
java·linux·c语言·jvm·c++
郝学胜-神的一滴12 小时前
C++11 工程级应用 08:Lambda表达式与Tuple元组
开发语言·jvm·c++·python·程序人生·开源
格林威12 小时前
C# 相机图像阴影校正:使用OpenCvSharp实现工业相机阴影平场校正功能
人工智能·数码相机·opencv·计算机视觉·c#·机器视觉·工业相机
水饺编程13 小时前
第5章,[Win32 章节] :圆角矩形教学插图绘制程序
c语言·c++·windows·visual studio