Openvino2024.3版部署YOLO (C++)

在网上很少看到有2024版的openvino,老版本的接口很多也都不在了,此篇写出来也算是为了防止自己忘记。

openvino下载

下载英特尔发行版 OpenVINO 工具套件 (intel.com)

下载好后解压出来,放C盘D盘都一样,我放在D盘了,这个文件夹名字有点长,自己修改成openvino_2024

打开你pycharm或者命令打开你的虚拟环境,安装下载

python 复制代码
pip install openvino-genai==2024.3.0

cmd,进入虚拟环境->D盘openvino_2024文件夹中,运行setupvars.bat,再把下面的都运行,可能需要先更新一下你的pip

python 复制代码
python -m pip install --upgrade pip
pip install onnx
pip install tensorflow
pip install mxnet
pip install network
如果下载速度太慢,可以加个清华源 -i https://pypi.tuna.tsinghua.edu.cn/simple

添加电脑环境变量

将openvino_2024中的路径加进去,我的是在D盘

python 复制代码
D:\openvino_2024\runtime\bin\intel64\Debug
D:\openvino_2024\runtime\bin\intel64\Release
D:\openvino_2024\runtime\3rdparty\tbb\bin

到这一步openvino的环境算是全部装好了,前提是上面的安装都没有报错,验证的话先使用pycharm进行转换,pt->onnx->xml/bin

利用YOLO代码中的export.py将pt转成onnx

python 复制代码
python export.py --weights yolov5s.pt --img 640 --batch 1

由于2024版的openvino已经取消了mo_onnx.py模型转换工具,所以需要我们自己转,脚本写在下方了

python 复制代码
from openvino.runtime import Core
from openvino.runtime import serialize
 
ie = Core()
onnx_model_path = r"自己的模型路径.onnx"
model_onnx = ie.read_model(model=onnx_model_path)
# compiled_model_onnx = ie.compile_model(model=model_onnx, device_name="CPU")
serialize(model=model_onnx, xml_path="生成xml的模型路径.xml", bin_path="生成bin模型的路径.bin", version="UNSPECIFIED")

运行之后你就得到了xml和bin模型,如果报错了,就说明你openvino没装好,自己再去对照一下上面步骤

C++部署

自己去创个新项目,配置一下项目环境

包含目录添加

cpp 复制代码
D:\opencv\build\include
D:\opencv\build\include\opencv2
D:\openvino_2024\runtime\include
D:\openvino_2024\runtime\include\openvino

库目录添加

cpp 复制代码
D:\opencv\build\x64\vc15\lib
D:\openvino_2024\runtime\lib\intel64\Release

链接器->输入->附加依赖项

cpp 复制代码
opencv_world452.lib
openvino.lib

这就算全部配置完了,直接上代码

openvino.cpp

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

YOLO_OPENVINO::YOLO_OPENVINO()
{
}

YOLO_OPENVINO::~YOLO_OPENVINO()
{
}


YOLO_OPENVINO::Resize YOLO_OPENVINO::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));

    cv::resize(img, resize.resized_image, cv::Size(new_unpadW, new_unpadH), 0, 0, cv::INTER_AREA);

    resize.dw = new_shape.width - new_unpadW;//w方向padding值 
    resize.dh = new_shape.height - new_unpadH;//h方向padding值 
    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;
}

void YOLO_OPENVINO::yolov5_compiled(std::string xml_path, ov::CompiledModel& compiled_model)
{
    // Step 1. Initialize OpenVINO Runtime core
    ov::Core core;
    // Step 2. Read a model
    //std::shared_ptr<ov::Model> model = core.read_model("best.xml");
    std::shared_ptr<ov::Model> model = core.read_model(xml_path);
    // 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();
    compiled_model = core.compile_model(model, "CPU");
}

void YOLO_OPENVINO::yolov5_detector(ov::CompiledModel compiled_model, cv::Mat input_detect_img, cv::Mat output_detect_img, vector<cv::Rect>& nms_box)
{
    // Step 3. Read input image
    cv::Mat img = input_detect_img.clone();
    int img_height = img.rows;
    int img_width = img.cols;
    vector<cv::Mat>images;
    vector<cv::Rect> boxes;
    vector<int> class_ids;
    vector<float> confidences;

    if (img_height < 5000 && img_width < 5000)
    {
        images.push_back(img);
    }
    else
    {
        images.push_back(img(cv::Range(0, 0.6 * img_height), cv::Range(0, 0.6 * img_width)));
        images.push_back(img(cv::Range(0, 0.6 * img_height), cv::Range(0.4 * img_width, img_width)));
        images.push_back(img(cv::Range(0.4 * img_height, img_height), cv::Range(0, 0.6 * img_width)));
        images.push_back(img(cv::Range(0.4 * img_height, img_height), cv::Range(0.4 * img_width, img_width)));
    }

    for (int m = 0; m < images.size(); m++)
    {
        // resize image
        Resize res = resize_and_pad(images[m], cv::Size(640, 640));
        // 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);

        //计算推理时间
        auto start = std::chrono::system_clock::now();
        infer_request.infer();
        auto end = std::chrono::system_clock::now();
        std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::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<float>();

        for (int i = 0; i < output_shape[1]; i++)//遍历所有框
        {
            float* detection = &detections[i * output_shape[2]];//bbox(x y w h obj cls)

            float confidence = detection[4];//当前bbox的obj
            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];//框中心x 
                    float y = detection[1];//框中心y 
                    float w = detection[2];//49
                    float h = detection[3];//50

                    float rx = (float)images[m].cols / (float)(res.resized_image.cols - res.dw);//x方向映射比例
                    float ry = (float)images[m].rows / (float)(res.resized_image.rows - res.dh);//y方向映射比例

                    x = rx * x;
                    y = ry * y;
                    w = rx * w;
                    h = ry * h;

                    if (m == 0)
                    {
                        x = x;
                        y = y;
                    }
                    else if (m == 1)
                    {
                        x = x + 0.4 * img_width;
                        y = y;

                    }
                    else if (m == 2)
                    {
                        x = x;
                        y = y + 0.4 * img_height;
                    }
                    else if (m == 3)
                    {
                        x = x + 0.4 * img_width;
                        y = y + 0.4 * img_height;
                    }

                    float xmin = x - (w / 2);//bbox左上角x
                    float ymin = y - (h / 2);//bbox左上角y
                    boxes.push_back(cv::Rect(xmin, ymin, w, h));
                }
            }
        }
    }

    std::vector<int> nms_result;
    cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, nms_result);
    std::vector<Detection> 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];
        nms_box.push_back(result.box);//传给Qt NMS后的box
        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 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));

    }
    img.copyTo(output_detect_img);


}

openvino.h

cpp 复制代码
#pragma once
#pragma once
#pragma once
#include <opencv2/dnn.hpp>
#include <openvino/openvino.hpp>
#include <opencv2/opencv.hpp>

using namespace std;

class YOLO_OPENVINO
{
public:
    YOLO_OPENVINO();
    ~YOLO_OPENVINO();

public:
    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);
    void yolov5_compiled(std::string xml_path, ov::CompiledModel& compiled_model);
    void yolov5_detector(ov::CompiledModel compiled_model, cv::Mat input_detect_img, cv::Mat output_detect_img, vector<cv::Rect>& nms_box);

private:

    const float SCORE_THRESHOLD = 0.4;
    const float NMS_THRESHOLD = 0.4;
    const float CONFIDENCE_THRESHOLD = 0.1;

    //vector<cv::Mat>images;//图像容器 
    //vector<cv::Rect> boxes;
    //vector<int> class_ids;
    //vector<float> confidences;
    //vector<cv::Rect>output_box;
    Resize resize;

};

main.cpp

cpp 复制代码
#include"openvino.h"
#include<string>
#include<vector>
#include<iostream>
using namespace cv;
using namespace std;
YOLO_OPENVINO yolo_openvino;
std::string path = "yolov5s.xml";
ov::CompiledModel model;
cv::Mat input_img, output_img;
vector<cv::Rect>output_box;
int main()
{
    String path1 = "D:\\py\\images";//文件夹路径
    vector<String>src_test;
    glob(path1, src_test, false);//将文件夹路径下的所有图片路径保存到src_test中

    if (src_test.size() == 0) {//判断文件夹里面是否有图片
        printf("error!!!\n");
        exit(1);
    }
    /* input_img = cv::imread("3.jpg");
     yolo_openvino.yolov5_compiled(path, model);
     yolo_openvino.yolov5_detector(model, input_img, output_img, output_box);*/

    yolo_openvino.yolov5_compiled(path, model);
    for (int i = 0; i < src_test.size(); i++) {//依照顺序读取文价下面的每张图片,并显示
        int pos = src_test[i].find_last_of("\\");
        std::string img_name(src_test[i].substr(pos + 1));
        Mat frame = imread(src_test[i]);
        yolo_openvino.yolov5_detector(model, frame, output_img, output_box);
        for (int i = 0; i < output_box.size(); i++)
        {
            cv::rectangle(frame, cv::Point(output_box[i].x, output_box[i].y), cv::Point(output_box[i].x + output_box[i].width, output_box[i].y + output_box[i].height), cv::Scalar(0, 255, 0), 3);
        }
        output_box.clear();
        cv::imwrite("检测图片保存的路径" + img_name, frame);

    }


}

运行效果图就不展示了,代码没有问题的,如果报错了,肯定是你自己的细节问题,不懂的下面评论

相关推荐
智驱力人工智能7 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
工程师老罗7 小时前
YOLOv1 核心结构解析
yolo
Lun3866buzha7 小时前
YOLOv10-BiFPN融合:危险物体检测与识别的革新方案,从模型架构到实战部署全解析
yolo
Katecat996638 小时前
YOLOv8-MambaOut在电子元器件缺陷检测中的应用与实践_1
yolo
工程师老罗9 小时前
YOLOv1 核心知识点笔记
笔记·yolo
工程师老罗14 小时前
基于Pytorch的YOLOv1 的网络结构代码
人工智能·pytorch·yolo
学习3人组17 小时前
YOLO模型集成到Label Studio的MODEL服务
yolo
孤狼warrior18 小时前
YOLO目标检测 一千字解析yolo最初的摸样 模型下载,数据集构建及模型训练代码
人工智能·python·深度学习·算法·yolo·目标检测·目标跟踪
水中加点糖19 小时前
小白都能看懂的——车牌检测与识别(最新版YOLO26快速入门)
人工智能·yolo·目标检测·计算机视觉·ai·车牌识别·lprnet
前端摸鱼匠1 天前
YOLOv8 环境配置全攻略:Python、PyTorch 与 CUDA 的和谐共生
人工智能·pytorch·python·yolo·目标检测