OpenVion22.3.x以及Opencv DNN部署yolov5(C++)全过程含代码

部署Openvino在win平台上走了不少坑,这里将从第一步开始进行,避免以后遗忘。

第一步肯定是先把yolo5的工程跑通啦,基本上7.0运行一下会自动下载各种,非常方便,基本不存在复杂的配置过程。

跑通后需要pip一下export.py所需要的openvino包:

  1.  openvino:这一般是OpenVINO的主要安装包,它包含了一系列的工具,库,和插件,用于优化,执行和部署各种深度学习模型。它可能包括但不限于Model Optimizer(模型优化器), nGraph API, Inference Engine(推理引擎),以及不同硬件设备的插件等。                        openvino-dev:这个包通常包含用于开发者的头文件和库。为了开发自己的程序并与OpenVINO库接口,需要用到这些开发工具。​​​​​​                                                        ​​​​​​​        ​​​​​​​        ​​​​​​​openvino-telemetry:这个包与收集和发送运行时的数据或者日志有关,以便在系统运行过程中进行监视或者调试。版本不需要与前两版本一致也不影响。                                                                                                                                                                                                                                                                       

  2.  具体配置export的部分:首先修改自己训练好的的pt模型路径,yaml路径根据自己需求选择导出的格式,这里选择openvino;然后运行一下等着就行啦,如果这里报错dll导入失败大概是版本不对应的问题。然后就得到xml和bin。XML文件:这个文件描述了模型的网络图结构。在这个文件中,你能找到每一层的信息,例如层名称,层类型,层参数,以及它们是如何连接起来的。BIN文件:这是一个二进制文件,包含了模型的权重和偏置。

  3. 配置openvino和opencv部分VS+OpenCV+OpenVINO2022详细配置(更新) - 知乎 (zhihu.com)这部分照这个配置想应的vs环境就行。

  4. 部署代码

    #include 
    #include 
    #include 
    
    
    using namespace std;
    
    
    const float SCORE_THRESHOLD = 0.2;
    const float NMS_THRESHOLD = 0.4;
    const float CONFIDENCE_THRESHOLD = 0.4;
    
    
    struct Detection
    {
        int class_id;
        float confidence;
        cv::Rect box;
    };
    
    
    struct Resize
    {
        cv::Mat resized_image;
        int dw;
        int dh;
    };
    
    
    Resize resize_and_pad(cv::Mat& img, cv::Size new_shape) {
        float width = img.cols;
        float height = img.rows;
        float r = float(new_shape.width / max(width, height));
        int new_unpadW = int(round(width * r));
        int new_unpadH = int(round(height * r));
        Resize resize;
        cv::resize(img, resize.resized_image, cv::Size(new_unpadW, new_unpadH), 0, 0, cv::INTER_AREA);
    
        resize.dw = new_shape.width - new_unpadW;
        resize.dh = new_shape.height - new_unpadH;
        cv::Scalar color = cv::Scalar(100, 100, 100);
        cv::copyMakeBorder(resize.resized_image, resize.resized_image, 0, resize.dh, 0, resize.dw, cv::BORDER_CONSTANT, color);
    
        return resize;
    }
    
    
    int main() {
    
        // Step 1. Initialize OpenVINO Runtime core
        ov::Core core;
        // Step 2. Read a model
        std::shared_ptr model = core.read_model("D://best.xml", "D://best.bin");
        //此处需要自行修改xml和bin的路径
    
        // Step 3. Read input image
        // 图像路径  
        cv::Mat img = cv::imread("D:/p.bmp");
        // resize image
        Resize res = resize_and_pad(img, cv::Size(640, 640));
    
    
        // Step 4. Inizialize Preprocessing for the model
        ov::preprocess::PrePostProcessor ppp = ov::preprocess::PrePostProcessor(model);
        // Specify input image format
        ppp.input().tensor().set_element_type(ov::element::u8).set_layout("NHWC").set_color_format(ov::preprocess::ColorFormat::BGR);
        // Specify preprocess pipeline to input image without resizing
        ppp.input().preprocess().convert_element_type(ov::element::f32).convert_color(ov::preprocess::ColorFormat::RGB).scale({ 255., 255., 255. });
        //  Specify model's input layout
        ppp.input().model().set_layout("NCHW");
        // Specify output results format
        ppp.output().tensor().set_element_type(ov::element::f32);
        // Embed above steps in the graph
        model = ppp.build();
        ov::CompiledModel compiled_model = core.compile_model(model, "CPU");
    
    
        // Step 5. Create tensor from image
        float* input_data = (float*)res.resized_image.data;
        ov::Tensor input_tensor = ov::Tensor(compiled_model.input().get_element_type(), compiled_model.input().get_shape(), input_data);
    
    
        // Step 6. Create an infer request for model inference 
        ov::InferRequest infer_request = compiled_model.create_infer_request();
        infer_request.set_input_tensor(input_tensor);
        //增加计时器统计推理时间
        double start = clock();
        infer_request.infer();
        double end = clock();
        double last = start - end;
        cout << "Detect Time" << last << "ms" << endl;
    
        //Step 7. Retrieve inference results 
        const ov::Tensor& output_tensor = infer_request.get_output_tensor();
        ov::Shape output_shape = output_tensor.get_shape();
        float* detections = output_tensor.data();
    
    
        // Step 8. Postprocessing including NMS  
        std::vector boxes;
        vector class_ids;
        vector confidences;
    
        for (int i = 0; i < output_shape[1]; i++) {
            float* detection = &detections[i * output_shape[2]];
    
            float confidence = detection[4];
            if (confidence >= CONFIDENCE_THRESHOLD) {
                float* classes_scores = &detection[5];
                cv::Mat scores(1, output_shape[2] - 5, CV_32FC1, classes_scores);
                cv::Point class_id;
                double max_class_score;
                cv::minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
    
                if (max_class_score > SCORE_THRESHOLD) {
    
                    confidences.push_back(confidence);
    
                    class_ids.push_back(class_id.x);
    
                    float x = detection[0];
                    float y = detection[1];
                    float w = detection[2];
                    float h = detection[3];
    
                    float xmin = x - (w / 2);
                    float ymin = y - (h / 2);
    
                    boxes.push_back(cv::Rect(xmin, ymin, w, h));
                }
            }
        }
        std::vector nms_result;
        cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, nms_result);
        std::vector output;
        for (int i = 0; i < nms_result.size(); i++)
        {
            Detection result;
            int idx = nms_result[i];
            result.class_id = class_ids[idx];
            result.confidence = confidences[idx];
            result.box = boxes[idx];
            output.push_back(result);
        }
    
    
        // Step 9. Print results and save Figure with detections
        for (int i = 0; i < output.size(); i++)
        {
            auto detection = output[i];
            auto box = detection.box;
            auto classId = detection.class_id;
            auto confidence = detection.confidence;
            float rx = (float)img.cols / (float)(res.resized_image.cols - res.dw);
            float ry = (float)img.rows / (float)(res.resized_image.rows - res.dh);
            box.x = rx * box.x;
            box.y = ry * box.y;
            box.width = rx * box.width;
            box.height = ry * box.height;
            cout << "Bbox" << i + 1 << ": Class: " << classId << " "
                << "Confidence: " << confidence << " Scaled coords: [ "
                << "cx: " << (float)(box.x + (box.width / 2)) / img.cols << ", "
                << "cy: " << (float)(box.y + (box.height / 2)) / img.rows << ", "
                << "w: " << (float)box.width / img.cols << ", "
                << "h: " << (float)box.height / img.rows << " ]" << endl;
            float xmax = box.x + box.width;
            float ymax = box.y + box.height;
            cv::rectangle(img, cv::Point(box.x, box.y), cv::Point(xmax, ymax), cv::Scalar(0, 255, 0), 3);
            cv::rectangle(img, cv::Point(box.x, box.y - 20), cv::Point(xmax, box.y), cv::Scalar(0, 255, 0), cv::FILLED);
            cv::putText(img, std::to_string(classId), cv::Point(box.x, box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
        }
        cv::imwrite("D:/pres.bmp", img);
        //显示具体结果
        cv::namedWindow("ImageWindow", cv::WINDOW_NORMAL);
        cv::resizeWindow("ImageWindow", 800, 600);
        cv::imshow("ImageWindow", img);
        
        cv::waitKey(0);
        cv::destroyAllWindows();
        return 0;
    }
    

    正常来说前面没问题这步就能直接跑啦,一般有问题的话可以选择从debug,release上选择哪个,配置是否有d考虑,其他各种崩溃都是版本原因引起,得从版本考虑,不行就重新装一次,版本问题确实麻烦,找起来不是非常方便,到这基本上就配置完成了。

  5. 下面是opencvDNN的部署方式

    OpenCV DNN (Deep Neural Network) 是 OpenCV 库中的一个模块,旨在提供对深度神经网络的支持。它允许你加载、推理和使用预训练的深度学习模型,以进行对象检测、图像分类、姿态估计等计算机视觉任务。OpenCV DNN 模块支持各种深度学习框架训练的模型,使用 OpenCV DNN,你可以通过简单的 API 载入训练好的模型并输入图像进行推理。该模块提供了高性能的计算图执行引擎,允许在 CPU 或者支持 GPU 加速的硬件上实现实时图像处理和分析。总之,OpenCV DNN 为开发者提供了一种方便快捷的方式,利用深度学习模型进行图像处理和计算机视觉任务。

  6. OpenVion22.3.x以及Opencv DNN部署yolov5(C++)全过程含代码_第1张图片此处贴上官方方法:Hexmagic/ONNX-yolov5: deploy yolov5 in c++ (github.com)因为原作者是在linux上配置我们是win,所以接下来,我们需要cmake一下cmakelist,然后就会得到一堆文件,新建过程,读取解决方案,当然,我们也可以直接复制他的源码自己建立一个工程也是可以的,不需要cmakelist,这里可以注意下OpenVion22.3.x以及Opencv DNN部署yolov5(C++)全过程含代码_第2张图片打开后的话就会有四个项目,我们可以移除三个,剩个main即可,配置一下OpenVion22.3.x以及Opencv DNN部署yolov5(C++)全过程含代码_第3张图片OpenVion22.3.x以及Opencv DNN部署yolov5(C++)全过程含代码_第4张图片OpenVion22.3.x以及Opencv DNN部署yolov5(C++)全过程含代码_第5张图片基本上opencv配置一下就行,然后就可以改改路径就可以run了。main.cpp:

    include 
    #include 
    #include 
    #include "loguru.hpp"
    #include "detector.h"
    using namespace cv;
    using namespace std;
    /* main */
    
    int main(int argc, char *argv[])
    {
        // 默认参数
        std::cout << "OpenCV version : " << CV_VERSION << std::endl;
        string model_path = "D://best.onnx";
        string img_path = "D://p.bmp";
        //string model_path = "3_best.onnx";
        //string img_path = "data/images/zidane.jpg";
        loguru::init(argc, argv);
        Config config = {0.25f, 0.45f, model_path, "E://yolo5//ONNX-yolov5-master//data//coco.names", Size(640, 640),false};
        LOG_F(INFO,"Start main process");
        Detector detector(config);
        LOG_F(INFO,"Load model done ..");
        Mat img = imread(img_path, IMREAD_COLOR);
        LOG_F(INFO,"Read image from %s", img_path.c_str());
        double start = clock();
        Detection detection = detector.detect(img);
        double end = clock();
        double last = start - end;
        cout << "Detect Time"<< last << "ms" << endl;
        LOG_F(INFO,"Detect process finished");
        Colors cl = Colors();
        detector.postProcess(img, detection,cl);
        LOG_F(INFO,"Post process done save image to assets/output.bmp");
        cv::imwrite("E:/yolo5/ONNX-yolov5-master/assets/p.bmp", img);
        std::cout << "detect Image And Save to assets/output.bmp" << endl;
        return 0;
    }

    到这基本上就结束了opencv和openvino部署的过程,大部分问题都可以从版本上寻找,因为部署代码多次测试是没有问题的。tks~

你可能感兴趣的:(openvino部署,YOLO,openvino,持续部署,opencv,c++)