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

    }


}

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

相关推荐
JicasdC123asd5 小时前
Converse2D频域卷积上采样改进YOLOv26图像重建与细节恢复能力
人工智能·yolo·目标跟踪
FL16238631295 小时前
基于yolov8+pyqt5实现的水尺图像识别与水深计算系统
开发语言·qt·yolo
jay神5 小时前
基于YOLOv8的传送带异物检测系统
人工智能·python·深度学习·yolo·可视化·计算机毕业设计
智驱力人工智能5 小时前
馆藏文物预防性保护依赖的图像分析技术 文物损害检测 文物破损检测 文物损害识别误报率优化方案 文物安全巡查AI系统案例 智慧文保AI监测
人工智能·算法·安全·yolo·边缘计算
智驱力人工智能8 小时前
一盔一带AI抓拍系统能否破解非机动车执法取证难 骑行未戴头盔检测 电动车未戴头盔智能监测 摩托车头盔佩戴AI识别系统 边缘计算实时处理
人工智能·算法·yolo·目标检测·边缘计算
jay神8 小时前
基于YOLOv8的无人机识别与检测系统
人工智能·深度学习·yolo·目标检测·毕业设计·无人机
小高求学之路9 小时前
计算机视觉、YOLO算法模型训练、无人机监测人员密集自动识别
算法·yolo·计算机视觉
duyinbi75171 天前
ADown高效下采样改进YOLOv26目标检测性能提升
yolo·目标检测·目标跟踪
AidLux1 天前
手机上AidLux2.1.0 运行模型广场的yolov8模型
yolo·智能手机
gc_22991 天前
C#调用Microsoft.ML.OnnxRuntime和YOLO5模型时的输出数据处理分析
yolo