Openvino2024.3版部署YOLO (C++)
在网上很少看到有2024版的openvino,老版本的接口很多也都不在了,此篇写出来也算是为了防止自己忘记。
openvino下载
下载英特尔发行版 OpenVINO 工具套件 (intel.com)


下载好后解压出来,放C盘D盘都一样,我放在D盘了,这个文件夹名字有点长,自己修改成openvino_2024
打开你pycharm或者命令打开你的虚拟环境,安装下载
pip install openvino-genai==2024.3.0
cmd,进入虚拟环境->D盘openvino_2024文件夹中,运行setupvars.bat,再把下面的都运行,可能需要先更新一下你的pip
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盘
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 export.py --weights yolov5s.pt --img 640 --batch 1
由于2024版的openvino已经取消了mo_onnx.py模型转换工具,所以需要我们自己转,脚本写在下方了
from openvino.runtime import Core
from openvino.runtime import serializeie = 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++部署
自己去创个新项目,配置一下项目环境
包含目录添加
D:\opencv\build\include
D:\opencv\build\include\opencv2
D:\openvino_2024\runtime\include
D:\openvino_2024\runtime\include\openvino
库目录添加
D:\opencv\build\x64\vc15\lib
D:\openvino_2024\runtime\lib\intel64\Release
链接器->输入->附加依赖项
opencv_world452.lib
openvino.lib
这就算全部配置完了,直接上代码
openvino.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 coreov::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 imagecv::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 imageResize res = resize_and_pad(images[m], cv::Size(640, 640));// Step 5. Create tensor from imagefloat* 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的objif (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];//49float h = detection[3];//50float 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左上角xfloat ymin = y - (h / 2);//bbox左上角yboxes.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后的boxoutput.push_back(result);}// Step 9. Print results and save Figure with detectionsfor (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
#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
#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);}}
运行效果图就不展示了,代码没有问题的,如果报错了,肯定是你自己的细节问题,不懂的下面评论
