【C++】使用ort推理yolov10

news/2024/9/12 21:06:28/文章来源:https://www.cnblogs.com/water-wells/p/18304361

【C++】使用ort推理yolov10

前言:由于笔者是编导专业,想玩玩yolo模型,搜来搜去全是python,所以在学会之后写一篇文章帮助和笔者同样情况的人

环境

Windows 10

C++17

onnxruntime18.1(DML版本)

opencv4.9

visual studio2022

1. 环境配置

1.1 OpenCV环境配置

1.1.1 OpenCV 配置

  1. 访问 OpenCV 的 GitHub 页面 https://github.com/opencv/opencv
  2. 在 Releases 页面找到最新的 .exe 文件并下载
  3. 运行安装程序,选择默认安装路径

1.1.2 在 Visual Studio 中配置 OpenCV

  1. 打开 Visual Studio,新建一个控制台项目
  2. 右键点击项目,选择“属性”
  3. 在属性页中,选择“VC++ 目录”
  4. 在“包含目录”中添加 OpenCV 安装目录下的 include 文件夹路径,如:C:\opencv\build\include
  5. 在“库目录”中添加 OpenCV 安装目录下的 x64\vc16\lib 文件夹路径,如:C:\opencv\build\x64\vc16\lib

运行下面的代码,如果环境配置没有问题,则会正确显示图片

如果显示无法打开文件lib.obj,则把代码中的#pragma comment(lib,"opencv_world490.lib")去掉

改成在 "项目” → "链接器” → “输入” 附加依赖项中写opencv_world490.lib

#include <opencv2/opencv.hpp>
#pragma comment(lib,"opencv_world490.lib")
//注意!!我这里是opencv_world490.lib,不同版本的OpenCV跟的数字是不一样,如果是按照默认位置安装,则可以在这个文件夹看你的lib叫什么
//  C:\opencv\build\x64\vc16\lib
int main()
{cv::Mat image = cv::imread("path/to/your/image.jpg"); // 替换为你的图像路径if (image.empty()){std::cout << "无法加载图像!" << std::endl;return -1;}cv::imshow("图像", image);cv::waitKey(0);return 0;
}

1.2 onnxruntime1.18.1(DML版本)配置

使用 NuGet 安装 ONNX Runtime

  1. 在 Visual Studio 中,右键点击项目,选择“管理 NuGet 程序包”。
  2. 在搜索框中输入 “onnxruntime”。
  3. 选择 “Microsoft.ML.OnnxRuntime.DirectML”,点击“安装”。

1.3 把环境改成C++17

  1. 打开项目属性页: 右键点击项目,选择“属性”。
  2. 选择 C/C++ 选项卡: 在左侧菜单中选择“C/C++”。
  3. 选择“高级”选项: 在右侧菜单中选择“高级”。
  4. 更改编译器语言标准: ****在“编译器语言标准”下拉菜单中选择“ISO C++17 标准 (/std:c++17)”。

2. 需要了解的知识

2.1 onnxruntime基本认识

首先我们对onnxruntime建立一些基本认识,onnxruntime就是一个推理框架,可以把模型摆进去,输入数据,模型输出数据,不止可以跑yolo,还可以跑其他模型,同样是推理框架的有Pytorch,OpenVINO,tensorRT,NCNN(据说神中神,还没开始玩),关于为什么选择ORT,不知道,群友说ORT也神中神,所以就决定是他了

2.2 yolo模型基本认识

推理一个yolo模型,我们一般把他分为三个步骤: 1. 前处理 2.推理 3. 后处理

前处理要做什么: 把不同宽高的图片处理成模型能推理的宽高,一般yolo模型都是支持(640,640)的图片的推理,如果输入的是(1920,1080)的图片就进行缩放+填充,把他变成(640,640)的图片

推理在做什么: 推理就是拿推理框架推理,一般就是一行代码,也许就是session.run(),就推理完了

后处理在做什么:模型输出的数据是非常杂乱的,因此需要对数据进行处理,比如说置信度过滤,nms,这是非常耗时的,但是在yolov10中,可以省去这一步,这也是yolov10效率高的原因

2.3 onnxruntime 是怎么进行推理的

onnxruntime执行推理依靠一行代码:auto output_tensors = session->Run(...)

他需要传入的参数有这些

  • Ort::RunOptions{ nullptr }: 推理选项,这里使用默认选项。
  • input_node_names_cstr.data(): 输入节点名称数组。
  • &input_tensor, 1: 输入张量指针和数量。
  • output_node_names_cstr.data(): 输出节点名称数组。
  • output_node_names.size(): 输出节点数量。

按照这些参数我们再继续

首先input_node_names_cstr.data() 这个参数的值怎么得到,笔者不知道,选择抄代码,代码如下

  session = std::make_unique<Ort::Session>(*env, model_path.c_str(), session_options);allocator = std::make_unique<Ort::AllocatorWithDefaultOptions>();auto num_input_nodes = session->GetInputCount();auto num_output_nodes = session->GetOutputCount();input_node_names.resize(num_input_nodes);output_node_names.resize(num_output_nodes);for (size_t i = 0; i < num_input_nodes; i++){auto input_name = session->GetInputNameAllocated(i, *allocator);input_node_names[i] = input_name.get();input_node_names_cstr.push_back(input_node_names[i].c_str());}

紧接着input_tensor 的值要怎么得到,这个笔者知道

  1. 我们要先处理图片,把图片处理成640*640
  2. 将图片转成RGB格式
  3. 把图片归一化到[0,1]
  4. 把图片用split函数分成三个通道,分别存进大小为(640,640,1)的Mat的数组中(mat就是OpenCV提供的,用来储存图片信息的结构)
  5. 用for循环把三个通道的值分别用memcpy存到input_tensor_value
  6. Ort::Value::CreateTensor<float>();input_tensor_value 变成input_tensor

接下来是output_node_names_cstr.data() 怎么得到,经典抄代码环节

    for (size_t i = 0; i < num_output_nodes; i++){auto output_name = session->GetOutputNameAllocated(i, *allocator);output_node_names[i] = output_name.get();output_node_names_cstr.push_back(output_node_names[i].c_str());}

接下来是output_node_names ,也是抄代码,就上面一段一起的,哦这些代码都是在官方仓库抄的

这些参数都有了,就可以推理了

3. 敲代码环节

3.1 预处理图片(把图片改成模型接受的shape,然后用灰度填充)

#include <opencv2/opencv.hpp>
// 我这里出现莫名奇妙的报错,然后去掉#pragma comment(lib,"opencv_world490.lib"),
// 在visual studio中的链接器中添加opencv_world490.lib就好了
void LetterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,bool autoShape, bool scaleFill, bool scaleUp, int stride, const cv::Scalar& color)
{cv::Size shape = image.size();float r = std::min((float)newShape.height / (float)shape.height,(float)newShape.width / (float)shape.width);if (!scaleUp)r = std::min(r, 1.0f);float ratio[2]{ r, r };int new_un_pad[2] = { (int)std::round((float)shape.width * r),(int)std::round((float)shape.height * r) };auto dw = (float)(newShape.width - new_un_pad[0]);auto dh = (float)(newShape.height - new_un_pad[1]);if (autoShape){dw = (float)((int)dw % stride);dh = (float)((int)dh % stride);}else if (scaleFill){dw = 0.0f;dh = 0.0f;new_un_pad[0] = newShape.width;new_un_pad[1] = newShape.height;ratio[0] = (float)newShape.width / (float)shape.width;ratio[1] = (float)newShape.height / (float)shape.height;}dw /= 2.0f;dh /= 2.0f;if (shape.width != new_un_pad[0] && shape.height != new_un_pad[1]){cv::resize(image, outImage, cv::Size(new_un_pad[0], new_un_pad[1]));}else {outImage = image.clone();}int top = int(std::round(dh - 0.1f));int bottom = int(std::round(dh + 0.1f));int left = int(std::round(dw - 0.1f));int right = int(std::round(dw + 0.1f));params[0] = ratio[0];params[1] = ratio[1];params[2] = left;params[3] = top;cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);
}int main()
{auto img = cv::imread("./zidane.jpg");// 目标尺寸cv::Size newShape = cv::Size(640, 640);cv::Vec4d temp_param = { 1,1,0,0 };cv::Scalar color = cv::Scalar(114, 114, 114);cv::Mat outImage;LetterBox(img, outImage, temp_param, newShape, false, false, true, 32, color);return 0;
}

运行起来应该是下面这个效果

Untitled

3.2紧接着为了要session.run(),我们需要先创建session,同时要创建session的参数

比如,打算使用几线程,打算用什么加速器,可以是cpu推理,也可以是cuda加速,也可以是dml加速,我们这里自然是选择dml加速,在选择加速器前,要判断加速器可不可用,使用的代码是auto dml_it = std::find(providers.begin(), providers.end(), "DmlExecutionProvider");

std::vector<float> input_tensor_values;
input_tensor_values.resize(3 * width * height);
env = std::make_unique<Ort::Env>(ORT_LOGGING_LEVEL_ERROR, "YOLOv10Inference");
session_options.SetIntraOpNumThreads(1);
session_options.SetGraphOptimizationLevel(ORT_ENABLE_ALL);std::vector<std::string> providers = Ort::GetAvailableProviders();
auto cuda_it = std::find(providers.begin(), providers.end(), "CUDAExecutionProvider");
auto dml_it = std::find(providers.begin(), providers.end(), "DmlExecutionProvider");if (cuda_it != providers.end())
{std::cout << "CUDA Execution Provider is available" << std::endl;
}
else if (dml_it != providers.end())
{std::cout << "DirectML Execution Provider is available" << std::endl;OrtSessionOptionsAppendExecutionProvider_DML(session_options, 0);
}
else
{std::cout << "No suitable provider found, using default CPU execution" << std::endl;
}session = std::make_unique<Ort::Session>(*env, model_path.c_str(), session_options);

加了这几行之后代码应该张这个样子,并且编译应该是能通过的,如果编译不能通过,自己排查一下吧~,我是边做边写的,如果你真的和我做的一样,应该也是可以编译通过的

// yolov10示例2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define NOMINMAX
#include <iostream>
#include <opencv2/opencv.hpp>
#include <onnxruntime_cxx_api.h>
#include <dml_provider_factory.h>
void LetterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,bool autoShape, bool scaleFill, bool scaleUp, int stride, const cv::Scalar& color)
{cv::Size shape = image.size();float r = std::min((float)newShape.height / (float)shape.height,(float)newShape.width / (float)shape.width);if (!scaleUp)r = std::min(r, 1.0f);float ratio[2]{ r, r };int new_un_pad[2] = { (int)std::round((float)shape.width * r),(int)std::round((float)shape.height * r) };auto dw = (float)(newShape.width - new_un_pad[0]);auto dh = (float)(newShape.height - new_un_pad[1]);if (autoShape){dw = (float)((int)dw % stride);dh = (float)((int)dh % stride);}else if (scaleFill){dw = 0.0f;dh = 0.0f;new_un_pad[0] = newShape.width;new_un_pad[1] = newShape.height;ratio[0] = (float)newShape.width / (float)shape.width;ratio[1] = (float)newShape.height / (float)shape.height;}dw /= 2.0f;dh /= 2.0f;if (shape.width != new_un_pad[0] && shape.height != new_un_pad[1]){cv::resize(image, outImage, cv::Size(new_un_pad[0], new_un_pad[1]));}else {outImage = image.clone();}int top = int(std::round(dh - 0.1f));int bottom = int(std::round(dh + 0.1f));int left = int(std::round(dw - 0.1f));int right = int(std::round(dw + 0.1f));params[0] = ratio[0];params[1] = ratio[1];params[2] = left;params[3] = top;cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);cv::imshow("1", outImage);cv::waitKey(0);
}int main()
{auto img = cv::imread("./zidane.jpg");// 目标尺寸int width = 640;int height = 640;const std::wstring& model_path = L"./yolov10n.onnx";cv::Size newShape = cv::Size(width, height);cv::Vec4d temp_param = { 1,1,0,0 };cv::Scalar color = cv::Scalar(114, 114, 114);cv::Mat outImage;LetterBox(img, outImage, temp_param, newShape, false, false, true, 32, color);Ort::SessionOptions session_options;std::unique_ptr<Ort::Env> env;std::unique_ptr<Ort::Session> session;std::vector<float> input_tensor_values;input_tensor_values.resize(3 * width * height);env = std::make_unique<Ort::Env>(ORT_LOGGING_LEVEL_ERROR, "YOLOv10Inference");session_options.SetIntraOpNumThreads(1);session_options.SetGraphOptimizationLevel(ORT_ENABLE_ALL);std::vector<std::string> providers = Ort::GetAvailableProviders();auto cuda_it = std::find(providers.begin(), providers.end(), "CUDAExecutionProvider");auto dml_it = std::find(providers.begin(), providers.end(), "DmlExecutionProvider");if (cuda_it != providers.end()){std::cout << "CUDA Execution Provider is available" << std::endl;}else if (dml_it != providers.end()){std::cout << "DirectML Execution Provider is available" << std::endl;OrtSessionOptionsAppendExecutionProvider_DML(session_options, 0);}else{std::cout << "No suitable provider found, using default CPU execution" << std::endl;}session = std::make_unique<Ort::Session>(*env, model_path.c_str(), session_options);return 0;
}

3.3 获取输入输出节点名称输入输出节点数量(写完了报错不要怕,因为我也报错)

allocator = std::make_unique<Ort::AllocatorWithDefaultOptions>();auto num_input_nodes = session->GetInputCount();
auto num_output_nodes = session->GetOutputCount();
input_node_names.resize(num_input_nodes);
output_node_names.resize(num_output_nodes);for (size_t i = 0; i < num_input_nodes; i++)
{auto input_name = session->GetInputNameAllocated(i, *allocator);input_node_names[i] = input_name.get();input_node_names_cstr.push_back(input_node_names[i].c_str());
}for (size_t i = 0; i < num_output_nodes; i++)
{auto output_name = session->GetOutputNameAllocated(i, *allocator);output_node_names[i] = output_name.get();output_node_names_cstr.push_back(output_node_names[i].c_str());
}

3.4 把图片转成浮点型,并且归一化到[0,1],把三个通道的数据分别储存到channels中(channels是三个一维的Mat组成的数组),并把他放到input_tensor_values中,并且CreateTensor,创建input_tensor

cv::Mat float_img;
std::vector<cv::Mat> channels(3);
outImage.convertTo(float_img, CV_32FC3, 1.0 / 255.0);
cv::split(float_img, channels);
for (int i = 0; i < 3; ++i)
{std::memcpy(input_tensor_values.data() + i * width * height, channels[i].data, width * height * sizeof(float));
}
std::vector<int64_t> input_node_dims = { 1, 3, height, width };
Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_tensor_values.data(), input_tensor_values.size(),input_node_dims.data(), input_node_dims.size()
);

3.5 推理!!获取推理结果

  auto output_tensors = session->Run(Ort::RunOptions{ nullptr },input_node_names_cstr.data(), &input_tensor, 1,output_node_names_cstr.data(), output_node_names.size());

3.6 把现在的内容整合一下(这应该是编译成功的),看到那个output_tensors ,模型输出就在那里面

// yolov10示例2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define NOMINMAX
#include <iostream>
#include <opencv2/opencv.hpp>
#include <onnxruntime_cxx_api.h>
#include <dml_provider_factory.h>
void LetterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,bool autoShape, bool scaleFill, bool scaleUp, int stride, const cv::Scalar& color)
{cv::Size shape = image.size();float r = std::min((float)newShape.height / (float)shape.height,(float)newShape.width / (float)shape.width);if (!scaleUp)r = std::min(r, 1.0f);float ratio[2]{ r, r };int new_un_pad[2] = { (int)std::round((float)shape.width * r),(int)std::round((float)shape.height * r) };auto dw = (float)(newShape.width - new_un_pad[0]);auto dh = (float)(newShape.height - new_un_pad[1]);if (autoShape){dw = (float)((int)dw % stride);dh = (float)((int)dh % stride);}else if (scaleFill){dw = 0.0f;dh = 0.0f;new_un_pad[0] = newShape.width;new_un_pad[1] = newShape.height;ratio[0] = (float)newShape.width / (float)shape.width;ratio[1] = (float)newShape.height / (float)shape.height;}dw /= 2.0f;dh /= 2.0f;if (shape.width != new_un_pad[0] && shape.height != new_un_pad[1]){cv::resize(image, outImage, cv::Size(new_un_pad[0], new_un_pad[1]));}else {outImage = image.clone();}int top = int(std::round(dh - 0.1f));int bottom = int(std::round(dh + 0.1f));int left = int(std::round(dw - 0.1f));int right = int(std::round(dw + 0.1f));params[0] = ratio[0];params[1] = ratio[1];params[2] = left;params[3] = top;cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);cv::imshow("1", outImage);cv::waitKey(0);
}int main()
{auto img = cv::imread("./zidane.jpg");// 目标尺寸int width = 640;int height = 640;const std::wstring& model_path = L"./yolov10n.onnx";cv::Size newShape = cv::Size(width, height);cv::Vec4d temp_param = { 1,1,0,0 };cv::Scalar color = cv::Scalar(114, 114, 114);cv::Mat outImage;LetterBox(img, outImage, temp_param, newShape, false, false, true, 32, color);Ort::SessionOptions session_options;std::unique_ptr<Ort::Env> env;, 1.0 / 255.0std::unique_ptr<Ort::Session> session;std::unique_ptr<Ort::AllocatorWithDefaultOptions> allocator;std::vector<float> input_tensor_values;std::vector<std::string> input_node_names;std::vector<std::string> output_node_names;std::vector<const char*> input_node_names_cstr;std::vector<const char*> output_node_names_cstr;input_tensor_values.resize(3 * width * height);env = std::make_unique<Ort::Env>(ORT_LOGGING_LEVEL_ERROR, "YOLOv10Inference");session_options.SetIntraOpNumThreads(1);session_options.SetGraphOptimizationLevel(ORT_ENABLE_ALL);std::vector<std::string> providers = Ort::GetAvailableProviders();auto cuda_it = std::find(providers.begin(), providers.end(), "CUDAExecutionProvider");auto dml_it = std::find(providers.begin(), providers.end(), "DmlExecutionProvider");if (cuda_it != providers.end()){std::cout << "CUDA Execution Provider is available" << std::endl;}else if (dml_it != providers.end()){std::cout << "DirectML Execution Provider is available" << std::endl;OrtSessionOptionsAppendExecutionProvider_DML(session_options, 0);}else{std::cout << "No suitable provider found, using default CPU execution" << std::endl;}session = std::make_unique<Ort::Session>(*env, model_path.c_str(), session_options);allocator = std::make_unique<Ort::AllocatorWithDefaultOptions>();auto num_input_nodes = session->GetInputCount();auto num_output_nodes = session->GetOutputCount();input_node_names.resize(num_input_nodes);output_node_names.resize(num_output_nodes);for (size_t i = 0; i < num_input_nodes; i++){auto input_name = session->GetInputNameAllocated(i, *allocator);input_node_names[i] = input_name.get();input_node_names_cstr.push_back(input_node_names[i].c_str());}for (size_t i = 0; i < num_output_nodes; i++){auto output_name = session->GetOutputNameAllocated(i, *allocator);output_node_names[i] = output_name.get();output_node_names_cstr.push_back(output_node_names[i].c_str());}cv::Mat float_img;std::vector<cv::Mat> channels(3);outImage.convertTo(float_img, CV_32FC3, 1.0 / 255.0);cv::split(float_img, channels);for (int i = 0; i < 3; ++i){std::memcpy(input_tensor_values.data() + i * width * height, channels[i].data, width * height * sizeof(float));}std::vector<int64_t> input_node_dims = { 1, 3, height, width };Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_tensor_values.data(), input_tensor_values.size(),input_node_dims.data(), input_node_dims.size());auto output_tensors = session->Run(Ort::RunOptions{ nullptr },input_node_names_cstr.data(), &input_tensor, 1,output_node_names_cstr.data(), output_node_names.size());return 0;
}

3.7 后处理咯,相当之简单,因为yolov10就是没后处理,他要做的就是根据缩放函数(letterbox),把坐标缩放回去

	auto output_tensors = session->Run(Ort::RunOptions{ nullptr },input_node_names_cstr.data(), &input_tensor, 1,output_node_names_cstr.data(), output_node_names.size());const float* raw_output = output_tensors[0].GetTensorData<float>();auto shape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape();int64_t num_boxes = shape[1];int64_t box_data_length = shape[2];detections.clear();for (int64_t i = 0; i < num_boxes; i++){const float* detection = raw_output + i * box_data_length;float x1 = detection[0];float y1 = detection[1];float x2 = detection[2];float y2 = detection[3];float confidence = detection[4];int class_id = static_cast<int>(detection[5]);if (confidence > 0.8){// Adjust coordinates to remove paddingfloat x = (x1 + 0.5 * (x2 - x1)-temp_param[2])/temp_param[0];float y = (y1 + 0.5 * (y2 - y1) - temp_param[3]) / temp_param[1];float w = (x2 - x1) / temp_param[0];float h = (y2 - y1) / temp_param[1];int left = MAX(int(x - 0.5 * w + 0.5), 0);int top = MAX(int(y - 0.5 * h + 0.5), 0);cv::Rect rect(left, top, int(w + 0.5), int(h + 0.5));detections.emplace_back(rect, confidence, class_id);}}

3.8 根据rect绘制方框

for (const auto& detection : detections)
{const auto& [rect, confidence, class_id] = detection;cv::rectangle(img, rect, cv::Scalar(0, 255, 0), 2);
}
cv::imshow("1", img);
cv::waitKey(0);

4. 最终代码和实现效果

实现效果,注意!!你使用的模型yolov10n.onnx,要和你的cpp文件在一个目录下

Untitled

// yolov10示例2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define NOMINMAX
#include <iostream>
#include <opencv2/opencv.hpp>
#include <onnxruntime_cxx_api.h>
#include <dml_provider_factory.h>
void LetterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,const cv::Scalar& color)
{cv::Size shape = image.size();float r = std::min((float)newShape.height / (float)shape.height,(float)newShape.width / (float)shape.width);float ratio[2]{ r, r };int new_un_pad[2] = { (int)std::round((float)shape.width * r),(int)std::round((float)shape.height * r) };auto dw = (float)(newShape.width - new_un_pad[0]);auto dh = (float)(newShape.height - new_un_pad[1]);dw /= 2.0f;dh /= 2.0f;if (shape.width != new_un_pad[0] && shape.height != new_un_pad[1]){cv::resize(image, outImage, cv::Size(new_un_pad[0], new_un_pad[1]));}else {outImage = image.clone();}int top = int(std::round(dh - 0.1f));int bottom = int(std::round(dh + 0.1f));int left = int(std::round(dw - 0.1f));int right = int(std::round(dw + 0.1f));params[0] = ratio[0];params[1] = ratio[1];params[2] = left;params[3] = top;cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);
}int main()
{auto img = cv::imread("./bus.jpg");// 目标尺寸int width = 640;int height = 640;const std::wstring& model_path = L"./yolov10n.onnx";cv::Size newShape = cv::Size(width, height);std::vector<std::tuple<cv::Rect, float, int>> detections;cv::Vec4d temp_param = { 1,1,0,0 };cv::Scalar color = cv::Scalar(114, 114, 114);cv::Mat outImage;LetterBox(img, outImage, temp_param, newShape, color);Ort::SessionOptions session_options;std::unique_ptr<Ort::Env> env;std::unique_ptr<Ort::Session> session;std::unique_ptr<Ort::AllocatorWithDefaultOptions> allocator;std::vector<float> input_tensor_values;std::vector<std::string> input_node_names;std::vector<std::string> output_node_names;std::vector<const char*> input_node_names_cstr;std::vector<const char*> output_node_names_cstr;input_tensor_values.resize(3 * width * height);env = std::make_unique<Ort::Env>(ORT_LOGGING_LEVEL_ERROR, "YOLOv10Inference");session_options.SetIntraOpNumThreads(1);session_options.SetGraphOptimizationLevel(ORT_ENABLE_ALL);std::vector<std::string> providers = Ort::GetAvailableProviders();auto cuda_it = std::find(providers.begin(), providers.end(), "CUDAExecutionProvider");auto dml_it = std::find(providers.begin(), providers.end(), "DmlExecutionProvider");if (cuda_it != providers.end()){std::cout << "CUDA Execution Provider is available" << std::endl;}else if (dml_it != providers.end()){std::cout << "DirectML Execution Provider is available" << std::endl;OrtSessionOptionsAppendExecutionProvider_DML(session_options, 0);}else{std::cout << "No suitable provider found, using default CPU execution" << std::endl;}session = std::make_unique<Ort::Session>(*env, model_path.c_str(), session_options);allocator = std::make_unique<Ort::AllocatorWithDefaultOptions>();auto num_input_nodes = session->GetInputCount();auto num_output_nodes = session->GetOutputCount();input_node_names.resize(num_input_nodes);output_node_names.resize(num_output_nodes);for (size_t i = 0; i < num_input_nodes; i++){auto input_name = session->GetInputNameAllocated(i, *allocator);input_node_names[i] = input_name.get();input_node_names_cstr.push_back(input_node_names[i].c_str());}for (size_t i = 0; i < num_output_nodes; i++){auto output_name = session->GetOutputNameAllocated(i, *allocator);output_node_names[i] = output_name.get();output_node_names_cstr.push_back(output_node_names[i].c_str());}cv::Mat float_img;std::vector<cv::Mat> channels(3);//cv::cvtColor(img, img, cv::COLOR_BGR2RGB);outImage.convertTo(float_img, CV_32FC3, 1.0 / 255.0);cv::split(float_img, channels);for (int i = 0; i < 3; ++i){std::memcpy(input_tensor_values.data() + i * width * height, channels[i].data, width * height * sizeof(float));}std::vector<int64_t> input_node_dims = { 1, 3, height, width };Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_tensor_values.data(), input_tensor_values.size(),input_node_dims.data(), input_node_dims.size());auto output_tensors = session->Run(Ort::RunOptions{ nullptr },input_node_names_cstr.data(), &input_tensor, 1,output_node_names_cstr.data(), output_node_names.size());const float* raw_output = output_tensors[0].GetTensorData<float>();auto shape = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape();int64_t num_boxes = shape[1];int64_t box_data_length = shape[2];detections.clear();for (int64_t i = 0; i < num_boxes; i++){const float* detection = raw_output + i * box_data_length;float x1 = detection[0];float y1 = detection[1];float x2 = detection[2];float y2 = detection[3];float confidence = detection[4];int class_id = static_cast<int>(detection[5]);if (confidence > 0.8){// Adjust coordinates to remove paddingfloat x = (x1 + 0.5 * (x2 - x1)-temp_param[2])/temp_param[0];float y = (y1 + 0.5 * (y2 - y1) - temp_param[3]) / temp_param[1];float w = (x2 - x1) / temp_param[0];float h = (y2 - y1) / temp_param[1];int left = MAX(int(x - 0.5 * w + 0.5), 0);int top = MAX(int(y - 0.5 * h + 0.5), 0);cv::Rect rect(left, top, int(w + 0.5), int(h + 0.5));detections.emplace_back(rect, confidence, class_id);}}for (const auto& detection : detections){const auto& [rect, confidence, class_id] = detection;cv::rectangle(img, rect, cv::Scalar(0, 255, 0), 2);}cv::imshow("1", img);cv::waitKey(0);return 0;
}

可以优化的地方

  1. OpenCV的mat速度好像是有点慢,自己实现一个MAT用,速度和占用都能好不少
  2. 如果确定要推理某个尺寸的图片,直接训练那个尺寸的图片,然后可以去掉letterbox,速度又能快点
  3. 如果追求极致效率,请转去ncnn,都说是神中神,快去试试,回来告诉我

最后

闷了,写的时候搜个半天搜不到,AI写出来的都是老代码,onnxruntime1.18.1都不适用,希望这篇文章能帮到你,如果文章有问题也欢迎斧正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/744401.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用FModel提取游戏资产

介绍使用FModel提取游戏资产的过程目录前言FModel简介FModel安装FModel使用初次使用资产预览资产导出附录dumperDumper-7生成usmap文件向游戏中注入dll 前言 这篇文章仅记录我作为初学者使用FModel工具提取某款游戏模型的过程。 FModel简介 FModel是一个开源软件,可以用于查看…

Codeforces Round 957 (Div. 3) 伤心的day少写一点

表白失败被拒绝了,但我觉得比留有遗憾更强👍,我从来没有自己是小丑的自卑,只会有接下来继续向前的勇气。 A. Only Pluses---------------------------------------------------题解--------------------------------------------- 挺愚蠢的一个题,进行555的暴力运算然后取…

k8s资源清单

目录一、k8s中的资源1、集群资源分类2、什么是资源3、集群资源概述3.1、名称空间级别3.2、集群级资源3.3、元数据型资源二、查看资源清单属性1、查看资源有那些资源清单属性1.1、格式1.2、示例1.2.1、查看pod资源的资源清单属性1.2.2、查看pvc资源的资源清单属性1.2.3、查看sta…

CORS跨域问题梳理

什么是跨域浏览器的同源策略:浏览器为确保资源安全,而遵循的一种策略,该策略对访问资源进行了一些限制 https://www.w3.org/Security/wiki/Same_Origin_Policy https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS1、发生跨域后会出现的问题:1、限制DOM访问 <!-- &…

linux/unix/windows 查询服务器查询出口 ip

1. 使用 curl 命令 比如下面这个 curl cip.cc 2. 也可以在浏览器中直接输入 url 地址:http://www.cip.cc/ 3. 其他的类似的网址: https://ipinfo.io/ curl ipinfo.iohttps://ifconfig.me/ curl ifconfig.mehttps://ifconfig.io/ curl ifconfig.iohttps://icanhazip.com/ cu…

五、Python函数之基础

全局变量与局部变量 顶头,没有任何缩进就是全局变量 函数里的变量是局部变量 如果在函数里使用 global全局变量,则可以改变全局变量。 如果没有global全局变量,调用全局变量的时候,只能读取,无法重新赋值 nonlocal 取上一级变量 书写规范 全局变量大写 局部变量小写 递归函…

STM32时钟体系、SetSysClock、PLL、时钟源

简要介绍了一、时钟体系 1、参考手册 2、时钟源3种 3、时钟树 4.时钟详解 HSE时钟 HSI时钟 锁相环时钟 系统时钟 HCLK时钟 PCLK1时钟 PCLK2时钟 RTC时钟 独立看门狗时钟: 12S时钟: 以太网PHY时钟: USBPHY时钟: MCO时钟输出 系统时钟配置函数SetsysClockO 系统时钟配置流程 …

YApi可视化接口管理平台部署

使用我们提供的 yapi-cli 工具,部署 YApi 平台是非常容易的。执行 yapi server 启动可视化部署程序,输入相应的配置和点击开始部署,就能完成整个网站的部署。部署完成之后,可按照提示信息,执行 node/{网站路径/server/app.js} 启动服务器。在浏览器打开指定url, 点击登录输…

八大作业管理流程

安全影响力的小编非常喜欢王老师的风格,抄了他的创意,把八大高危作业做了一个“一图看懂”系列。

玄机-第一章 应急响应-webshell查杀

作者是个垃圾,第一次玩玄机太紧张了,不知道flag是啥样找了半天,第二次开靶机多次尝试才知道格式。争取下次一次过。 靶机账号密码 root xjwebshell 1.黑客webshell里面的flag flag{xxxxx-xxxx-xxxx-xxxx-xxxx} 2.黑客使用的什么工具的shell github地址的md5 flag{md5} 3.黑客…

WordPress标签如何实现批量自定义链接

网站外链和内链都是非常重要的一项 SEO 工作,并且一个网站的反链建设也并非一朝一夕就能够做好,而是日积月累的增加才会更有优化效果,且不论是否为 nofollow 或者 dofollow 属性,对于很 SEOer 来说可能觉得建设 Do Follow 的反链更有用,但是我们不妨换个 SEO 思维方式,一…