# Evision 开发计划 本文档是 Evision 双目视觉系统复活与现代化工程的总体开发计划,涵盖已完成的阶段 0–3,进行中的阶段 4(相机标定优化),以及阶段 5–6 的方向展望。文档与仓库根目录 README 的"路线图"一节保持同步。 > **阶段 3 计划变更(2026-07)**:原阶段 3 方案(ONNX Runtime + YOLOv8 替换内嵌 Darknet,详见 `.omo/plans/phase3-onnx-yolo.md`)经评估后决定**不再执行**——目标检测模块已完全过时(强制 CUDA、仅 Windows、YOLOv3 模型陈旧),已整体移除且不做替换,归档于 `archive/darknet-fork` 分支。原 ONNX 方案文档保留为历史参考;未来如需 AI 检测能力将重新立项设计。 ## 1. 项目背景与目标 Evision 是一个基于 C++/Qt 的双目视觉系统,提供标定、畸变校正、视差计算、三维重建、距离测量等功能(原目标检测模块已于阶段 3 移除,见第 4 节)。代码库经历了较长的停更期,存在以下历史包袱: - 构建体系老化:CMake 脚本停留在全局变量时代,Qt5/Qt6 变量混用,master 分支长期无法干净编译。 - 仓库臃肿:包含 C# 旧版本(legacy/)、编译产物(install/)、IDE 缓存与大体积测试数据,工作树约 1.2 GB。 - 依赖陈旧:目标检测基于内嵌 Darknet fork(约 40K 行,含 11 个 CUDA kernel),强制要求 NVIDIA 显卡与 CUDA 工具链,无法在无 NVCC 的机器上构建。 - API 过时:相机模块基于 Qt5 Multimedia(`QCameraInfo`/`QCameraImageCapture`/`QCameraViewfinder`),且依赖 Qt5Compat 兼容层与字符串宏 SIGNAL/SLOT 连接。 复活工程的总体目标:**先恢复可编译基线,再系统性地完成 Qt6 迁移与构建现代化,移除过时的内嵌 AI 引擎,并为深度学习立体匹配与 UI 现代化铺路。** ## 2. 总体路线图 | 阶段 | 目标 | 状态 | |:---:|:---|:---:| | 0 | 仓库清理:移除无关/大体积内容,工作树减重 | 已完成 | | 1 | 可编译恢复 + CMake 现代化 + 内存泄漏修复 + CI 骨架 | 已完成 | | 2 | Qt6 完整迁移(Qt5Compat 移除、PMF 信号槽、Qt6 Multimedia) | 已完成 | | 3 | 目标检测模块整体移除(内嵌 Darknet,不做替换;原 ONNX 替换方案废弃) | 已完成 | | 4 | 相机标定优化:共享标定核心、ChArUco/SB 检测、逐视图质量门控 | 进行中 | | 5 | 深度学习立体匹配:RAFT-Stereo / IGEV-Stereo 可选后端 | 未启动 | | 6 | UI 现代化:Dear ImGui(EvisionLight)或 Qt6 + Docking | 未启动 | ## 3. 已完成阶段回顾 ### 3.1 阶段 0 — 仓库清理 共 16 个提交,完成以下工作: - 移除 `legacy/`(C# 旧版本)、`install/`(编译产物)、`src/.vs/`、`sln/`、`src/EvisionSandbox/GeneratedFiles/` 等目录。 - 移除大体积数据:`yolov3.weights`、`data/Simulations/`、`data/Tracker/test_reg/`,并改为通过 GitHub Releases 按需下载(见 README 第 7 节)。 - 工作树体积从约 1.2 GB 降至约 120 MB。 - 被移除内容完整归档于 `archive/legacy-pre-cleanup` 分支,历史可追溯。 ### 3.2 阶段 1 — 可编译恢复与 CMake 现代化 - CMake 现代化:全面改用 `target_include_directories` / `target_compile_definitions` / 显式源文件列表,消除全局变量式写法。 - 修复 Qt5/Qt6 变量混用,修复明显内存泄漏,修正 `catch(...)` 反模式。 - 新增 GitHub Actions CI 骨架(提交 `6c7a462`),CI 以 `ObjectDetection=OFF` 配置构建。 - 回归修复(提交 `c2a4729`):现代化过程中移除了 `CMAKE_INCLUDE_CURRENT_DIR`,导致 `EvisionADCensus`/`EvisionElas` 中以 `#include ` 方式引用源码根目录头文件的编译失败;通过为目标补充 `${CMAKE_CURRENT_SOURCE_DIR}` 包含路径修复,此后全量 `EvisionSandbox.exe` 构建通过(40/40 步骤)。 ### 3.3 阶段 2 — Qt6 完整迁移 分三个子阶段,各自独立提交并验证: - **2.A(提交 `a35ec64`)**:移除 Qt5Compat 依赖与失效的 QRegExp 引用。 - **2.B(提交 `0532d47`)**:将 14 个文件中的 144 处字符串宏 SIGNAL/SLOT 连接全部转换为 PMF/lambda 语法,获得编译期类型检查。 - **2.C(提交 `3a1f4e2`)**:EvisionCamera 模块(13 个文件)迁移至 Qt6 Multimedia API——`QCameraInfo`→`QCameraDevice`、`QCameraImageCapture`→`QImageCapture`、`QCameraViewfinder`→`QVideoWidget`,新增 `QMediaCaptureSession`;同时修复了导出宏错误与 `StereoCameraView.ui` 槽名不匹配两个预存 bug,并重新在 CMake 中启用该模块、恢复 `EvisionSandbox` 消费者连接。验证:CMake configure 通过、全量构建通过(40/40 步骤,退出码 0)。 ## 4. 阶段 3 — 目标检测模块移除(已完成) **决策变更**:原方案(ONNX Runtime + YOLOv8 替换内嵌 Darknet)已废弃,改为**整体移除、不做替换**。理由:该模块已完全过时——强制 NVIDIA/CUDA 工具链、仅支持 Windows(pthreadVC2)、YOLOv3 模型陈旧(2018)、Darknet fork 约 40K 行 vendored 代码维护成本远超其价值。 **已执行的移除内容**: - 删除 `src/EvisionObjDetection/`(检测 UI)与 `src/EvisionObjDetectionEngine/`(内嵌 Darknet fork,约 40K LOC、130 个文件、11 个 CUDA kernel)。 - 删除 `package/pthread/`(pthreads-win32,仅被 Darknet 引擎引用)与 `data/yolo/`(`yolov3.cfg`、`coco.names`)。 - 顶层与 `EvisionSandbox` 的 CMake 移除 `ObjectDetection` 选项及全部条件块(含 windeployqt 部署清单)。 - `EvisionSandbox` 移除目标检测菜单/工具栏项、`menuAi`(仅剩检测一项)、`on_action_ObjectDetection_triggered()` 槽与 `WITH_CUDA` 条件编译块。 - CI 配置移除 `-DObjectDetection=OFF` 参数。 - 全部内容先归档至 `archive/darknet-fork` 分支再删除,git 历史零丢失。 **验证**:Ubuntu 24.04(GCC 13.3 + Qt 6.5.3 + OpenCV 4.14.0)全量重编译 13/13 目标通过、0 错误 0 警告,offscreen 运行正常。 --- ### 附:原阶段 3 方案摘要(已废弃,保留为历史参考) 原详细计划(17 项任务、依赖矩阵、验收标准)见 `.omo/plans/phase3-onnx-yolo.md`。 ### 4.1 目标与收益 用一个约 600 行的 ONNX Runtime C++ 封装(`OnnxDetector`)替换内嵌 Darknet fork(`EvisionObjDetectionEngine`,约 40K 行、130 个文件、11 个 `.cu` CUDA kernel),运行 YOLOv8n ONNX 模型完成目标检测。预期收益: - **解除 CUDA 工具链硬依赖**:替换后项目可在无 NVCC 的机器上构建;GPU 加速变为运行时可选,而非编译期必需。 - **跨 GPU 厂商覆盖**:通过 DirectML Execution Provider 支持 Windows 上所有 GPU(含 AMD/Intel),不再限于 NVIDIA。 - **依赖托管化**:ONNX Runtime 由 vcpkg 安装(v1.27.1),不再 vendored 维护一个陈旧 fork。 - **模型大幅减重**:YOLOv3 weights 约 248 MB → YOLOv8n ONNX 约 12 MB。 - **UI 简化**:文件选择对话框从 3 个(.cfg/.weights/.names)减至 2 个(.onnx + .names)。 UI 模块 `EvisionObjDetection`(8 个文件,约 439 行)保留并重写,不删除。 ### 4.2 关键决策 1. **模型选型**:YOLOv8n ONNX,使用 ultralytics Releases 提供的预导出资产(约 12 MB),不做模型转换(不运行 `yolo export`)。模型文件加入 `.gitignore`,不入库,由用户自行下载;`coco.names` 保留在仓库,`yolov3.cfg` 删除。模型输出为端到端 NMS 的 `(1,300,6)` = `[x1,y1,x2,y2,conf,class_id]`,后处理同时兼容转置布局 `(1,6,300)`。 2. **执行后端(EP)运行时自动选择**:CUDA → DirectML(仅 Windows)→ CPU,启动时记录所选 EP。绝不引入编译期 EP 选项,单一二进制处处可运行。 3. **Darknet fork 处置**:先完整归档到 `archive/darknet-fork` 分支并推送远端,再从主树删除,git 历史零丢失,无双栈并存。 4. **UI 简化范围**:仅做对话框 3→2 的简化,不改动布局、样式与控件类型。 vcpkg 特性矩阵:纯 CPU 安装 `onnxruntime`;NVIDIA 安装 `onnxruntime[cuda]`;Windows 全 GPU 安装 `onnxruntime[dml]`(DirectML 仅 Windows 可用)。 ### 4.3 执行计划概览 共 5 个波次、17 项任务: - **波次 0 — 预验证门禁(2 项,并行)**:验证 vcpkg 三种特性安装结果;下载 YOLOv8n ONNX 并转储/校验输入输出形状。两项必须先通过,任何源码改动之前完成,环境问题尽早暴露。 - **波次 1 — Darknet 移除与 CMake(3 项,顺序)**:创建并推送 `archive/darknet-fork` 归档分支 → 主树删除 `src/EvisionObjDetectionEngine/` → 顶层 CMake 移除对应 `add_subdirectory`,在 `ObjectDetection` 选项下加入 `find_package(onnxruntime)`。 - **波次 2 — 核心重写(4 项)**:新建 `OnnxDetector` 类 → `ObjectDetectionEntity` 状态改写(`onnxModelFilename`/`namesFilename` 替换 `cfgFilename`/`weightsFilename`)→ `ObjectDetectionEngine` 的 QThread `run()` 重写(会话缓存一次构建、`Ort::Exception` 捕获、协作式停止)→ 工厂修复(`CreateEvisionEvisionCloudViewer` 更名为 `CreateObjectDetectionView` 并修正导出宏)。 - **波次 3 — 消费者/UI/数据/文档(4 项,并行)**:`EvisionSandbox` 消费者 C++ 侧 `#ifdef WITH_CUDA` → `WITH_OBJECT_DETECTION` 并改用新工厂;消费者 CMake 链接 `EvisionObjDetection` 并清除引擎残留引用;UI 对话框简化;`data/yolo/` 清理与 README 下载说明更新。 - **波次 4 — 构建验证(4 项,顺序)**:`ObjectDetection=ON` 配置通过 → 构建 `EvisionObjDetection.dll` 并用 `dumpbin` 验证其依赖 `onnxruntime.dll` → `ninja -k 0` 全量构建 `EvisionSandbox.exe` 通过 → 运行时冒烟测试:加载模型对真实样例图推理,断言至少返回 1 个检测框,打印实际使用的 EP,保存标注结果图。 ### 4.4 验证策略 - 无人工干预,所有验证由执行代理完成。 - 本阶段不引入单元测试框架(项目现状无测试体系);`OnnxDetector` 正确性由运行时冒烟测试背书。 - 每项任务产出证据文件至 `.omo/evidence/task-N-phase3-onnx-yolo.*`(构建日志、ONNX 形状转储、冒烟测试输出与标注图)。 - 全部任务完成后运行最终验证波次 F1–F4(计划符合性审计、代码质量评审、真实手工 QA、范围保真),四项全部 APPROVE 方可宣告完成。 - 已接受的折中:`ObjectDetection=OFF` 构建路径不显式列入任务,由现有 CI(OFF 配置)隐式覆盖。 ### 4.5 风险与缓解 | 风险 | 缓解 | |:---|:---| | 运行时 EP/驱动不可用(CUDA/DirectML 初始化失败) | 波次 0 预验证门禁提前暴露;EP 自动回退链最终落到 CPU,保证可用 | | vcpkg 特性平台差异(DirectML 仅 Windows) | 波次 0 验证三种特性安装;CMake 中仅记录特性矩阵,不做平台硬编码 | | ONNX 输出布局差异(`(1,300,6)` vs `(1,6,300)`) | 波次 0 下载后立即转储形状存证,后处理按证据自适应 | | ONNX Runtime DLL 部署遗漏 | 构建期 `dumpbin /dependents` 验证 + 运行时冒烟测试双重确认 | | 消费者守卫宏切换遗漏(`WITH_CUDA` → `WITH_OBJECT_DETECTION`) | 波次 3 专项任务 + 波次 4 全量构建验证 | ### 4.6 范围边界 本阶段明确不做: - 不保留 Darknet 作为回退路径(无双栈)。 - 不把 EP 选择做成 CMake 选项(仅运行时)。 - 不做模型训练、微调、数据集工具或模型格式转换。 - 不支持 YOLOv8n 以外的模型(非 v5/v7/v9/v11,非自定义数据集)。 - 不修改 CI 的 ObjectDetection 配置(保持 OFF;CI 侧 qt5compat 残留清理另立小任务)。 - 不做 UI 重设计;不支持多模型;不做异步/批量推理(QThread 内单图同步推理)。 ## 5. 阶段 4 — 相机标定优化(进行中) **动机**:标定是整条双目链路(校正→视差→重建→测量)的误差源头。经代码诊断,原标定模块存在三类问题:明确的 bug(空点集调用 `calibrateCamera` 崩溃、读图失败与读完混淆、多处内存泄漏、库代码内 `exit(-1)`)、影响精度的逻辑缺失(无逐视图重投影误差门控、角点检测使用旧 API、失败反馈只到 console、结果无结构化输出)、以及工程问题(`EvisionMonocularCalib` 与 `EvisionCalibrate` 单目路径约 350 行逐行重复)。 **方案**(经评估后确定,优先级高于深度学习立体匹配): 1. **共享标定核心**:在 `EvisionUtils` 新增 Qt-free 的 `CalibrationCore`(纯 OpenCV),单/双目两个模块共用,消除重复实现。 2. **检测层升级**:棋盘格改用 `findChessboardCornersSB`(失败回退经典 API);新增 ChArUco 标定板路径(OpenCV 4.7+ `cv::aruco::CharucoDetector`,objdetect 模块,部分可见即可用);圆点阵列保留。 3. **质量门控**:逐视图重投影误差计算、高误差视图迭代剔除与标注、RMS/极线误差/逐视图误差结构化报告上报 UI。 4. **bug 修复**:空点集保护、读图失败与列表结束分离、内存泄漏、`exit(-1)` 移除。 **技术要点**:ChArUco 自 OpenCV 4.7 起并入主仓库 objdetect 模块,无需 opencv_contrib;本地 OpenCV 4.10.0 已验证可用。ChArUco 部分可见特性要求每个视图携带各自的 object points,核心 API 以 `DetectionResult{corners, objects}` 一一对应建模;双目匹配取左右公共角点子集(`matchStereoPair`)。 **范围边界**:不引入 Ceres/BA 自研求解器(Kalibr 路线,成本远大于收益);不支持学习类标定;不合并两个模块的参数实体(保持模块插件独立性,去重只到算法核心层)。 ## 6. 阶段 5 展望 — 深度学习立体匹配 引入 RAFT-Stereo / IGEV-Stereo 等深度立体匹配网络作为**可选**后端,ADCensus/ELAS 保留为基线算法。该阶段计划引入 ONNX Runtime 基础设施(EP 自动选择、vcpkg 依赖、模型下载约定;原阶段 3 的 ONNX 方案设计可复用),避免重复造轮子。具体模型选型与精度/性能预算在阶段 4 完成后评估。 ## 7. 阶段 6 展望 — UI 现代化 延续作者原 EvisionLight 设想探索两条路线:Dear ImGui(脱离 Qt,简化分发、提升运行效率),或继续 Qt6 + Docking 框架(如 Qt Advanced Docking System)路线。阶段 5 完成后基于当时的技术栈状态做路线决策。 ## 8. 开发环境与工具链 - 操作系统:Windows 10/11(开发主环境)。 - 编译器:Visual Studio 2019 或更高(已在 VS 2026、MSVC 14.x 上验证),桌面 C++ 工作负载。 - 构建系统:CMake ≥ 3.20(开发使用 3.26.4)+ Ninja。 - 依赖(vcpkg classic 模式):Qt 6.9.0、OpenCV 4.10.0、Boost 1.82.0、PCL;阶段 3 起增加 `onnxruntime`。 - Qt 模块:Core/Gui/Widgets/Multimedia/MultimediaWidgets/PrintSupport/Concurrent 等,按模块 `find_package(Qt6 COMPONENTS ...)` 引入。 ## 9. Git 工作流与提交规范 - 远端布局:`origin` 指向上游仓库(SSH,只读);推送经 HTTPS + Personal Access Token 至个人 fork(`jiafeng5513/Evision`)。 - 工作分支:`code_refine`(当前阶段全部工作在此进行)。 - 归档分支:统一命名 `archive/*`(已有 `archive/legacy-pre-cleanup`;阶段 3 将新增 `archive/darknet-fork`)。 - 提交信息规范:`(): `,类型取自 `chore` / `feat` / `fix` / `refactor` / `build` / `docs` / `test`,与既有提交历史保持一致。 - 原则:小步原子提交;每个可验证单元一个提交;不经显式要求不提交;永不提交密钥与令牌。 ## 10. 验证与证据约定 - 构建验证:CMake configure 退出码 0;Ninja 全量构建(`-k 0`)退出码 0;`dumpbin /dependents` 检查 DLL 依赖链。 - 静态检查:改动文件经 LSP 诊断无错误后方可标记任务完成。 - 证据留存:每个可验证任务在 `.omo/evidence/` 留存日志或产物,命名 `task--<主题>.<扩展名>`。 - 最终验收:阶段级工作完成后进行独立复核(计划符合性、代码质量、真实 QA、范围保真),全部通过方可宣告阶段完成。 ## 11. 已知遗留事项 1. CI 工作流仍安装 qt5compat 相关包(阶段 2.A 后已属残留),另立小任务清理。 2. ~~阶段 3 计划已就绪,待批准后启动执行~~ —— 已变更为整体移除并执行完毕,见第 4 节。 3. `origin` 的 SSH 密钥未获上游授权,推送固定走 HTTPS + PAT 的 fork 远端。 4. ~~阶段 3 中 `ObjectDetection=OFF` 构建路径依赖 CI 隐式覆盖~~ —— `ObjectDetection` 选项已随模块移除。