🚀 从 0 到 1:Windows WSL2 环境下的 YOLOv5 + ONNX Runtime C++ 工业级部署全指南

📖 项目背景与架构说明

在端侧设备(如树莓派、RK3588)部署计算机视觉模型前,必须在 PC 端进行严格的算法重构与跨平台验证。本项目旨在带你从零搭建 Windows Subsystem for Linux (WSL2) x86_64 架构开发环境,彻底剥离 Python 臃肿生态,完全使用 C++17 与 ONNX Runtime (ORT) 引擎,实现高性能的单帧极速推理,为后续的 ARM 端侧落地打下坚实的底层基座。


🛠️ Phase 1: 零基础搭建 WSL2 底层系统

假设你使用的是全新的 Windows 10/11 系统,从未接触过 Linux。

1. 开启 WSL 功能并安装 Ubuntu
右键点击 Windows 的“开始”菜单,选择“Windows PowerShell (管理员)”,执行以下命令,系统会自动为你安装最稳定的 Ubuntu 22.04 LTS 版本:

wsl --install -d Ubuntu-22.04

(注:执行完毕后,根据提示重启电脑。重启后会自动弹出 Ubuntu 终端,按照提示设置你的 UNIX 用户名和密码。)

2. 替换国内镜像源并更新系统(极其重要,防卡死)
进入 Ubuntu 终端后,为了保证后续下载速度,先更新系统软件包(全量复制执行):

# 1. 更新软件列表
sudo apt update
# 2. 升级现有软件 (遇到提示按 Y 回车)
sudo apt upgrade -y

🧱 Phase 2: 配置 C++ 兵工厂与 OpenCV 视觉库

工业级部署离不开底层的 C++ 编译链和 OpenCV 图像处理矩阵。在 Ubuntu 终端逐行执行:

1. 安装核心编译工具链

sudo apt install build-essential cmake git wget unzip -y

2. 安装 OpenCV C++ 运行库

sudo apt install libopencv-dev -y

🚀 Phase 3: 挂载 ONNX Runtime (x86_64 工业级推理引擎)

在 WSL 的 x86_64 架构下,我们直接使用微软官方预编译的 ORT 库,避免耗时数小时的源码编译。

1. 下载并解压预编译包

# 回到用户根目录
cd ~

# 下载官方 x64 架构 1.17.1 版本压缩包
wget https://github.com/microsoft/onnxruntime/releases/download/v1.17.1/onnxruntime-linux-x64-1.17.1.tgz

# 解压压缩包
tar -zxvf onnxruntime-linux-x64-1.17.1.tgz

# 重命名文件夹以精简路径
mv onnxruntime-linux-x64-1.17.1 onnxruntime-linux

2. 配置系统环境变量(打通动态库血脉)

# 将 ORT 的 lib 路径永久写入环境变量配置中
echo 'export LD_LIBRARY_PATH=$HOME/onnxruntime-linux/lib:$LD_LIBRARY_PATH' >> ~/.bashrc

# 立刻刷新环境变量使其生效
source ~/.bashrc


🧠 Phase 4: 炼丹炉预热 —— YOLOv5 模型导出固化

我们需要用 Python 环境拉取 YOLOv5 源码,并将 .pt 权重转换为 C++ 能直接调用的 .onnx 计算图,同时强制锁死输入尺寸。

1. 安装 Python 依赖

# 安装 Python 包管理器 pip
sudo apt install python3-pip -y
# 安装导出必需的核心库
pip3 install onnx onnxsim

2. 克隆源码并下载权重

cd ~
# 克隆官方源码
git clone https://github.com/ultralytics/yolov5.git

# 进入目录
cd yolov5

# 安装 YOLOv5 框架依赖
pip3 install -r requirements.txt

# 下载 yolov5s 版本权重文件
wget https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.pt

3. 念出终极导出咒语(核心避坑)

# 强制开启简化 (--simplify),并锁死底层输入尺寸为 640x640,防止 C++ 部署时 Concat 算子撕裂
python3 export.py --weights yolov5s.pt --imgsz 640 640 --include onnx --opset 12 --simplify

(执行完毕后,在当前 ~/yolov5 目录下会生成一个 yolov5s.onnx 文件,这就是咱们的 AI 大脑。)


💻 Phase 5: 构建纯 C++ 验证工程

现在,我们离开 Python 的世界,纯手写 C++ 推理管线。

1. 创建工程目录与文件

cd ~
# 创建工程主目录
mkdir -p yolo_workspace/src
cd yolo_workspace

# 将刚才转换好的 onnx 模型拷贝过来
cp ~/yolov5/yolov5s.onnx .

2. 准备一张测试图片

# 下载一张包含人或车的测试图片命名为 test.jpg (你也可以自己拖拽图片到该目录下)
wget https://raw.githubusercontent.com/ultralytics/yolov5/master/data/images/zidane.jpg -O test.jpg

3. 编写 C++ 源码 (src/main.cpp)
使用你顺手的编辑器(如 VS Code 或 vim),在 src 目录下新建 main.cpp,贴入以下核心代码:

#include <iostream>
#include <vector>
#include <string>
#include <opencv2/opencv.hpp>
#include <onnxruntime_cxx_api.h>

const std::vector<std::string> COCO_CLASSES = {
    "Person", "Bicycle", "Car", "Motorcycle", "Airplane", "Bus", "Train", "Truck", "Boat", "Traffic Light",
    "Fire Hydrant", "Stop Sign", "Parking Meter", "Bench", "Bird", "Cat", "Dog", "Horse", "Sheep", "Cow"
};

struct LetterboxInfo {
    cv::Mat image; float scale; int left_pad; int top_pad;
};

LetterboxInfo letterbox(const cv::Mat& source, int target_width, int target_height) {
    int org_width = source.cols, org_height = source.rows;
    float scale = std::min((float)target_width / org_width, (float)target_height / org_height);
    int new_width = org_width * scale, new_height = org_height * scale;
    cv::Mat resized_image;
    cv::resize(source, resized_image, cv::Size(new_width, new_height));
    int top_pad = (target_height - new_height) / 2;
    int bottom_pad = target_height - new_height - top_pad;
    int left_pad = (target_width - new_width) / 2;
    int right_pad = target_width - new_width - left_pad;
    cv::Mat result_image;
    cv::copyMakeBorder(resized_image, result_image, top_pad, bottom_pad, left_pad, right_pad, 
                       cv::BORDER_CONSTANT, cv::Scalar(114, 114, 114));
    return {result_image, scale, left_pad, top_pad};
}

int main() {
    std::cout << "=== ONNX Runtime C++ x86_64 工业级验证引擎启动 ===" << std::endl;

    cv::Mat original_image = cv::imread("../test.jpg"); 
    if (original_image.empty()) { std::cerr << "找不到图片!" << std::endl; return -1; }
    LetterboxInfo lb_info = letterbox(original_image, 640, 640);

    // 1. 初始化 ORT 环境与并发选项
    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "YOLOv5_ORT");
    Ort::SessionOptions session_options;
    session_options.SetIntraOpNumThreads(4); // 压榨 4 核心性能
    session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);
    Ort::Session session(env, "../yolov5s.onnx", session_options);

    // 2. 图像转 Blob 与零拷贝张量映射
    cv::Mat blob;
    cv::dnn::blobFromImage(lb_info.image, blob, 1.0 / 255.0, cv::Size(640, 640), cv::Scalar(0, 0, 0), true, false);
    size_t input_tensor_size = 1 * 3 * 640 * 640;
    std::vector<int64_t> input_node_dims = {1, 3, 640, 640};
    Ort::MemoryInfo memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
    Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
        memory_info, (float*)blob.data, input_tensor_size, input_node_dims.data(), 4);

    // 3. 执行前向推理
    const char* input_names[] = {"images"};
    const char* output_names[] = {"output0"};
    auto output_tensors = session.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor, 1, output_names, 1);

    // 4. 手写指针跃迁,解析高维输出
    float* data = output_tensors[0].GetTensorMutableData<float>();
    std::vector<int> class_ids; std::vector<float> confidences; std::vector<cv::Rect> boxes;
    for (int i = 0; i < 25200; ++i) {
        float obj_conf = data[4]; 
        if (obj_conf >= 0.45f) { 
            float* classes_scores = data + 5;
            cv::Mat scores(1, 80, CV_32FC1, classes_scores);
            cv::Point class_id_point; double max_class_score;
            cv::minMaxLoc(scores, 0, &max_class_score, 0, &class_id_point);
            if (max_class_score > 0.45) {
                confidences.push_back(obj_conf * max_class_score);
                class_ids.push_back(class_id_point.x);
                float cx = data[0], cy = data[1], w = data[2], h = data[3];
                int left = int((cx - w / 2 - lb_info.left_pad) / lb_info.scale);
                int top = int((cy - h / 2 - lb_info.top_pad) / lb_info.scale);
                int width = int(w / lb_info.scale), height = int(h / lb_info.scale);
                boxes.push_back(cv::Rect(left, top, width, height));
            }
        }
        data += 85; 
    }

    // 5. NMS 与图像绘制
    std::vector<int> nms_indices;
    cv::dnn::NMSBoxes(boxes, confidences, 0.45f, 0.45f, nms_indices);
    for (int idx : nms_indices) {
        cv::Rect box = boxes[idx]; int class_id = class_ids[idx];
        cv::rectangle(original_image, box, cv::Scalar(0, 0, 255), 2);
        std::string label = "ORT_" + COCO_CLASSES[class_id];
        cv::putText(original_image, label, cv::Point(box.x, std::max(box.y, 15)), 
                    cv::FONT_HERSHEY_SIMPLEX, 0.6, cv::Scalar(0, 0, 255), 2);
    }

    cv::imshow("ORT Validation Engine", original_image);
    cv::waitKey(0);
    return 0;
}

4. 编写工程构建文件 (CMakeLists.txt)
yolo_workspace 根目录下,新建 CMakeLists.txt,填入以下配置:

cmake_minimum_required(VERSION 3.10)
project(YoloWSLValidation)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 开启 C++ 极致优化
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -march=native -ffast-math")

# 寻找 OpenCV
find_package(OpenCV REQUIRED)

# 挂载 x64 版本的 ONNX Runtime 库
include_directories($ENV{HOME}/onnxruntime-linux/include)
link_directories($ENV{HOME}/onnxruntime-linux/lib)

# 编译与链接
add_executable(ort_test src/main.cpp)
target_link_libraries(ort_test PRIVATE ${OpenCV_LIBS} onnxruntime)

⚡ Phase 6: 编译执行与验证

现在,执行最后的构建与运行命令,见证奇迹:

# 在 yolo_workspace 目录下创建构建文件夹
mkdir build
cd build

# 执行 CMake 解析图纸
cmake ..

# 执行多线程急速编译
make -j8

# 运行生成的二进制可执行文件
./ort_test

🎉 成功标志: > 借助 WSL2 原生支持的 GUI 功能(WSLg),你的 Windows 桌面上会瞬间弹出一个原生的 OpenCV 窗口,上面精准地画着红框,标有 ORT_Person 等字样!
至此,x86_64 架构下的 C++ 引擎重构与跑通彻底完成,随时可以迁移至 ARM 端侧(树莓派/RK3588)执行流水线封装!


Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐