> 技术文档 > 【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8


通过C/C++语言能够实现深度学习模型的高效部署。在众多部署框架中,本文采用OpenCV结合ONNX Runtime的方案来部署YOLOv8目标检测模型。其中,ONNX Runtime作为核心推理引擎,而OpenCV则主要负责图像读取等辅助功能。

文章目录

  • 前言
  • 一、环境准备
    • 1.1 yolov8推理源码
    • 1.2 环境变量添加
  • 二、项目属性
    • 2.1 新建项目
    • 2.2 配置项目属性(opencv+onnxruntime)
      • 2.2.1 C++语言标准
      • 2.2.2 附加包含目录
      • 2.2.3 附加库目录
      • 2.2.4 附加依赖项
      • 2.2.5 生成解决方案文件
  • 三、YOLOv8源代码修改
    • 3.1 inference.cpp
    • 3.2 opencv测试
    • 3.3 main.cpp修改
    • 3.4 运行检测
  • 四、一些可能遇到的问题和解决方法
    • 4.1 filesystem飘红
    • 4.2 应用程序无法正常启动
    • 4.3 Debug Error
    • 4.4 头文件报错

前言

OpenCV(Open Source Computer Vision Library)集成了数百种先进的计算机视觉算法,涵盖图像处理、特征检测、目标跟踪及人脸识别等核心功能。该库支持包括C++、Python和Java在内的多种编程语言,并具备出色的跨平台兼容性,可在Windows、Linux、macOS、Android和iOS等主流操作系统上稳定运行。
ONNX Runtime(Open Neural Network Exchange Runtime)是一款开源的高性能推理引擎,专门用于执行 ONNX模型。作为机器学习模型的开放标准格式,ONNX 为模型交换提供了统一规范。ONNX Runtime 通过提供一致的 API 接口,实现了跨硬件平台和操作系统的无缝部署。

基于 OpenCV 和 ONNX Runtime 的目标检测流程主要包含以下步骤:

  1. 图像加载与预处理:通过 OpenCV 读取目标图像,并根据模型需求进行尺寸调整、归一化等预处理操作。
  2. 模型加载:使用 ONNX Runtime 加载预训练的 ONNX 格式目标检测模型,为推理做好准备。
  3. 模型推理:将预处理后的图像数据输入模型,利用 ONNX Runtime 进行推理计算,获取初步检测结果。
  4. 结果后处理:借助 OpenCV 对检测结果进行可视化处理,包括绘制目标边界框、添加类别标签等操作。

一、环境准备

  • 系统:Win10;
  • IDE:Visual Studio 2019;
  • C++标准:>=C++17
  • opencv4.9.0:https://opencv.org/releases/
  • onnxruntime1.15.1(本文用的CPU版):https://github.com/microsoft/onnxruntime/releases

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8 【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

1.1 yolov8推理源码

获取yolov8代码:github:
https://github.com/ultralytics/ultralytics/tree/main/examples/YOLOv8-ONNXRuntime-CPP
或者gitcode(推荐,下载速度更快):
https://gitcode.com/gh_mirrors/ul/ultralytics/tree/main/examples/YOLOv8-ONNXRuntime-CPP?utm_source=csdn_github_accelerator&isLogin=1
重点是这三个文件:

  • main.cpp
  • inference.cpp
  • inference.h

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

1.2 环境变量添加

不管是opencv还是onnxruntime,其本质都是给用户提供include和lib去使用。我这里将opencv和onnxruntime分别解压到以下文件夹里

D:\\opencvD:\\onnxruntime

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

下载好opencv和onnxruntime后,将其加入到环境变量中。右键/设置 此电脑–》属性–》高级系统设置–》高级–》环境变量,将onnxruntime文件夹里include/lib以及opencv文件夹下…\\build\\x64\\vc16添加进环境变量。

D:\\onnxruntime\\includeD:\\onnxruntime\\libD:\\opencv\\build\\x64\\vc16\\binD:\\opencv\\build\\x64\\vc16\\lib

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

二、项目属性

2.1 新建项目

打开VS2019创建一个空项目,命名为“yolov8”。将上面下载的yolov8中推理源码main.cppinference.cppinference.h复制到项目文件夹下,方便下一步添加进项目里:

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

然后将这三个文件添加进项目里:在相应文件夹上右键–》添加–》现有项,将代码添加进项目中

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

添加后是这样:

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

2.2 配置项目属性(opencv+onnxruntime)

然后重点来了,打开项目属性:(或者直接右击目标项目,选择属性)。在配置前一定确保配置在dubug、x64模式下!!!(也可以配置为release,但也需要在x64模式下)。

2.2.1 C++语言标准

在常规-》C++语言标准中修改为C++17(>=17就行)

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

2.2.2 附加包含目录

在C/C++栏–》常规中选择“附加包含项目”,将opencv和onnxruntime中相关文件添加进去:

D:\\onnxruntime\\includeD:\\opencv\\build\\include\\opencv2D:\\opencv\\build\\include

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

2.2.3 附加库目录

接着在链接器–》常规–》附加库目录中将opencv和onnxruntime的‘“lib”文件夹添加进去

D:\\opencv\\build\\x64\\vc16\\libD:\\onnxruntime\\lib

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

2.2.4 附加依赖项

接着在链接器–》输入–》附加依赖项中将添加以下内容

opencv_world490d.libonnxruntime.libonnxruntime_providers_shared.lib

这三个lib文件在“D:\\onnxruntime\\lib”和“D:\\opencv\\build\\x64\\vc16\\lib

也可以直接复制以下代码:注意,opencv_world490d.lib中的\"490\"表示OpenCV版本为4.9.0,请根据您的实际版本修改该数字;后缀\"d\"代表调试模式(Debug),若为发布模式(Release),请使用opencv_world490.lib。

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

2.2.5 生成解决方案文件

运行时一定将将模式设置为和所配置的项目属性一致,我这里就是debug、x64(否则会找不到对应的头文件)
【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8
到这里打开main.cpp文件,执行编译操作以生成解决方案文件。(都没有报错不用管,这一步旨在创建一个…\\x64\\Debug文件夹)

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

然后将“D:\\onnxruntime\\lib下的DLL文件全部复制到…\\x64\\Debug文件夹中

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

至此已经完成了项目属性的配置。掌握这一流程至关重要,因为在Visual Studio中配置其他库的步骤与此基本一致。

三、YOLOv8源代码修改

3.1 inference.cpp

inference.cpp:

第一行加上#define _CRT_SECURE_NO_WARNINGS 1(否则会出现strcpy报警告,程序无法运行!!!

#define _CRT_SECURE_NO_WARNINGS 1

两行飘红的字符串前加上(char*):
Ret = (char*) “[YOLO_V8]:Your model path is error.Change your model path without chinese characters.”;(102行附近)

Ret = (char*)\"[YOLO_V8]:Your model path is error.Change your model path without chinese characters.\";

return (char*) “[YOLO_V8]:Create session failed.”;(166行附近)

return (char*)\"[YOLO_V8]:Create session failed.\";

3.2 opencv测试

在 main.cpp 文件中,通过编写测试代码来验证上述配置是否成功。测试代码只需在 int main() 函数中实现,无需修改其他部分。图片正常显示,说明配置成功;若异常,再检查一下自己的配置流程。

int main(){ //DetectTest(); //ClsTest(); cv::Mat image = cv::imread(\"D:\\\\test.png\");//输入测试图片 cv::imshow(\"test\", image); cv::waitKey(0); cv::destroyAllWindows(); return 0;}

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

3.3 main.cpp修改

由于本文是做目标检测任务,因此仅需调整与目标检测相关的函数。

  • void Detector(YOLO_V8*& p)
  • void DetectTest()
  • int main()

void Detector(YOLO_V8*& p)

std::filesystem::path imgs_path:将其修改为待检测图片所在的文件夹;
std::string output_folder:检测后的图片输出位置;
在函数末尾添加保存图片的代码片段。

void Detector(YOLO_V8*& p) { /*std::filesystem::path current_path = std::filesystem::current_path();*/ std::filesystem::path imgs_path = \"D:/result/test\";//这里一定输入待检测图片所在的文件夹!!! std::string output_folder = \"D:/run\"; // 输出文件夹路径 std::filesystem::create_directories(output_folder); for (auto& i : std::filesystem::directory_iterator(imgs_path)) { if (i.path().extension() == \".jpg\" || i.path().extension() == \".png\" || i.path().extension() == \".jpeg\") { std::string img_path = i.path().string(); cv::Mat img = cv::imread(img_path); std::vector<DL_RESULT> res; p->RunSession(img, res); for (auto& re : res) { cv::RNG rng(cv::getTickCount()); cv::Scalar color(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256)); cv::rectangle(img, re.box, color, 3); float confidence = floor(100 * re.confidence) / 100; std::cout << std::fixed << std::setprecision(2); std::string label = p->classes[re.classId] + \" \" +  std::to_string(confidence).substr(0, std::to_string(confidence).size() - 4); cv::rectangle(  img,  cv::Point(re.box.x, re.box.y - 25),  cv::Point(re.box.x + label.length() * 15, re.box.y),  color,  cv::FILLED ); cv::putText(  img,  label,  cv::Point(re.box.x, re.box.y - 5),  cv::FONT_HERSHEY_SIMPLEX,  0.75,  cv::Scalar(0, 0, 0),  2 ); } std::cout << \"Press any key to exit\" << std::endl; cv::imshow(\"Result of Detection\", img); std::string save_path = output_folder + \"/\" + i.path().filename().string(); cv::imwrite(save_path, img); cv::waitKey(0); cv::destroyAllWindows(); img.release(); } }}

void DetectTest()

函数中的ReadCocoYaml(yoloDetector)注释掉,改为:
yoloDetector->classes = { “person”};

yoloDetector->classes = { \"person\"}; //可根据实际需求自定义类别设置,本文仅需进行人物识别以验证效果即可。

函数中params.modelPath修改为onnx模型的路径
函数末尾加上delete yoloDetector;

void DetectTest(){ YOLO_V8* yoloDetector = new YOLO_V8; /*ReadCocoYaml(yoloDetector);*/ yoloDetector->classes = { \"person\" }; DL_INIT_PARAM params; params.rectConfidenceThreshold = 0.1; params.iouThreshold = 0.5; params.modelPath = \"D:/result/yolov8n.onnx\"; params.imgSize = { 640, 640 };#ifdef USE_CUDA params.cudaEnable = true; // GPU FP32 inference params.modelType = YOLO_DETECT_V8; // GPU FP16 inference //Note: change fp16 onnx model //params.modelType = YOLO_DETECT_V8_HALF;#else // CPU inference params.modelType = YOLO_DETECT_V8; params.cudaEnable = false;#endif yoloDetector->CreateSession(params); Detector(yoloDetector); delete yoloDetector;}

int main()

int main(){ DetectTest(); return 0;}

main.cpp 文件中包含的以下函数与目标检测功能无关,删除后不会影响检测结果。

  • void Classifier(YOLO_V8*& p)
  • int ReadCocoYaml(YOLO_V8*& p)
  • void ClsTest()

3.4 运行检测

完成代码修改后即可开始检测。

  • 若使用CPU,直接编译运行即可。
  • 如需在GPU上运行,请在main.cpp文件首行添加#define USE_CUDA指令。

检测结果将统一保存在指定目录下,默认路径为std::string output_folder = “D:/run”

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

四、一些可能遇到的问题和解决方法

经过实际测试,按照上述步骤配置程序可以确保正常运行。然而,某些容易被忽视的细节仍可能导致程序出现错误。

4.1 filesystem飘红

文件系统类filesystem是从C++17开始引入的。VS2019默认标准是C++14,因此需要将标准修改为17及以上。见2.1节。

4.2 应用程序无法正常启动

编译的时候正常,但在运行时出现“应用程序无法正常启动”。出现这个问题基本是因为缺少DLL文件。检查是否将D:\\onnxruntime\\lib**下的DLL文件全部复制到…\\x64\\Debug文件夹中,见2.4节。这样问题基本就能解决。

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

4.3 Debug Error

Debug Error 的出现通常源于文件路径错误或包含中文字符。建议仔细核对文件路径的准确性,并将文件名统一改为英文格式。

【C++】使用opencv+onnxruntime推理YOLOv8目标检测_c++ yolov8

4.4 头文件报错

检查运行时的模式(Debug,x64)是否和配置的项目属性一致,见第2节。