环境配置
本示例运行环境:
- Windows 10
- GTX 1060 + CUDA11.4+cudnn8
- VS2019+python3.9
- opencv 4.10
Python
yolov8要求python版本在3.8及以上,pytorch版本在1.8以上。本示例只有测试,因此没有安装pytorch。这里使用anaconda安装python3.9来将模型文件导出至onnx。
conda create -n py39 python==3.9
下载yolov8源码并在terminal中打开该目录,安装onnx和yolov8
conda activate py39
pip install onnx onnxruntime-gpu
python setup.py install
OpenCV
CMake编译源码
下载安装CMake
下载opencv源码(这里以4.1.0为例 https://github.com/opencv/opencv/archive/4.1.0.zip)
编译
首先设置源码位置和构建位置,然后点击configure
选择编译器,这里选用VS2019 (vc16)
然后等待配置,配置完成后如下
找到并勾选BUILD_opencv_world,然后再点configure,直到没有标红的项目,点击generate
生成完成后点击open project,进入VS2019。在release|x64模式下,在解决方案资源管理器—>CMakeTargets—>右键点击ALL_BUILD–>生成。然后在解决方案资源管理器—>CMakeTargets—>右键点击INSTALL–>生成
生成文件
<build_path>\install\x64\vc16
CUDA+cudnn
CUDA:在官网上选择版本下载安装即可
cudnn:在官网上下载(需要注册账号),然后将压缩包解压至cuda路径(例如: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4)
ONNX-runtime
从官网下载onnx环境(这里以1.16.3 Windows x64 c++ cuda为例 https://globalcdn.nuget.org/packages/microsoft.ml.onnxruntime.gpu.1.16.3.nupkg),解压至文件夹(本示例为:D:\onnx)
运行步骤
导出至onnx文件
在terminal中打开yolov8目录,然后导出模型。
yolo export model=yolov8n.pt opset=12 simplify=True dynamic=False format=onnx imgsz=640
如果当前路径没有yolov8n.pt,则自动下载
最后输出文件yolov8n.onnx
VS2019配置
创建项目,把配置设为Release|x64,把yolov8代码中example\YOLOv8-ONNXRuntime-CPP中的.h和.cpp文件添加到项目中
然后配置项目:项目(P)—>项目属性
首先将配置改成Release x64
然后配置属性—>常规中把C++语言标准设置成C++17
配置属性—>VC++目录
在包含目录中加上opencv和onnx的include目录
- <opencv_build_path>\install\include
- <opencv_build_path>\install\include\opencv2
- <onnx_path>\build\native\include
在库目录中加上opencv和onnx的库目录
- <opencv_build_path>\install\x64\vc16\lib
- <onnx_path>\runtimes\win-x64\native
配置属性—>C/C++—>预处理器,在预处理器定义中加上_CRT_SECURE_NO_WARNINGS
配置属性—>C/C++—>语言,将符合模式设为默认值,C++语言标准设为C++17
配置属性—>链接器—>输入
在附加依赖项中加入相关lib
onnxruntime.lib
onnxruntime_providers_cuda.lib
onnxruntime_providers_shared.lib
opencv_world410.lib
代码bug
在inference.cpp中TensorProcess函数中的strideNum和signalResultNum的意义是反的
解决方法:
取消244行rawData=rawData.t()的注释
将248行的for循环中的strideNum和signalResultNum对调
for (int i = 0; i < signalResultNum; ++i)
{
float* classesScores = data + 4;
cv::Mat scores(1, this->classes.size(), CV_32FC1, classesScores);
cv::Point class_id;
double maxClassScore;
cv::minMaxLoc(scores, 0, &maxClassScore, 0, &class_id);
if (maxClassScore > rectConfidenceThreshold)
{
confidences.push_back(maxClassScore);
class_ids.push_back(class_id.x);
float x = data[0];
float y = data[1];
float w = data[2];
float h = data[3];
int left = int((x - 0.5 * w) * resizeScales);
int top = int((y - 0.5 * h) * resizeScales);
int width = int(w * resizeScales);
int height = int(h * resizeScales);
boxes.push_back(cv::Rect(left, top, width, height));
}
data += strideNum;
}
std::vector<int> nmsResult;
cv::dnn::NMSBoxes(boxes, confidences, rectConfidenceThreshold, iouThreshold, nmsResult);
for (int i = 0; i < nmsResult.size(); ++i)
{
int idx = nmsResult[i];
DL_RESULT result;
result.classId = class_ids[idx];
result.confidence = confidences[idx];
result.box = boxes[idx];
oResult.push_back(result);
}
运行结果
下载coco.yaml文件(该文件定义了不同类别的index),并将其与测试数据放在vs项目目录中
最后将<opencv_build_path>\install\x64\vc16\bin\opencv_world410.dll复制到exe相同路径,或者C:\Windows\SysWOW64和C:\Windows\System32中
然后将<onnx_path>\runtimes\win-x64\native中的以下dll复制到exe相同路径中
onnxruntime.dll
onnxruntime_providers_cuda.dll
onnxruntime_providers_shared.dll
如果需要用CUDA,在main.cpp里面加上#define USE_CUDA
运行结果如下: