Files
archery/design_doc/algo.md
T

185 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
1. 系统目标
# 检测靶纸四角的等腰直角三角形标记(每个角一个)
# 计算激光落点在靶面上的二维偏移(厘米)
# 通过PnP算法估算靶面到相机的距离(米)
2. 核心算法流程
2.1 三角形检测 (detect_triangle_markers)
采用多策略级联保证鲁棒性:
图像输入 → 多阈值策略 → 候选三角形过滤 → 四点匹配
检测策略(按优先级):
1.全局Otsu二值化(最快,~10ms
2.自适应阈值(多种block size,光照不均时)
3.ROI局部阈值(候选不足3个时,分象限独立处理)
4.Black-Hat形态学增强(仍不足时,突出暗色标记)
三角形几何验证:
# 必须是直角三角形(检查勾股定理,容差20%)
# 两直角边长度差<20%
# 内部像素足够暗(灰度≤130,暗像素比例≥30%)
# 与周围背景对比度≥15灰度级
四点匹配算法:
# 从候选三角形中枚举所有4点组合
# 计算四边形评分:(对角比-1)*3 + (水平比-1) + (垂直比-1) + (边长偏差)*2
# 选择评分最低的组合作为四角标记
2.2 单应性落点计算 (homography_calibration)
建立图像坐标系 → 靶面坐标系(二维平面)的透视变换
将激光点像素坐标映射到靶面坐标(厘米)
使用RANSAC提高鲁棒性(阈值1像素)
2.3 PnP距离估计 (pnp_distance_meters)
已知四个标记点的三维坐标(x,y,z,单位cm)
通过solvePnP求解相机外参(旋转+平移)
距离 = ‖平移向量‖ / 100(转换为米)
3. 关键优化策略
3.1 多路径投票
同一图像区域被不同二值化方法检测到时,path_votes++
选择投票数高的候选,提高检测可信度
3.2 早退机制
候选≥3个 且 覆盖3个以上象限 → 停止更多阈值尝试
大幅降低嵌入式设备计算开销
3.3 3点补全机制
当只检测到3个角时,通过仿射变换估算第4个角位置
公式:P_missing = M_inv @ [x_target, y_target, 1]
3.4 图像缩放
默认缩放到0.5倍进行检测(由config控制)
坐标还原时乘以inv_scale,保持与标定矩阵一致
4. 数据流示例
python
输入:
- img_rgb: H×W×3 图像
- laser_xy: (x_px, y_px) 激光点像素坐标
- marker_positions: {0:[0,0,0], 1:[0,30,0], 2:[30,30,0], 3:[30,0,0]} # 4角3D坐标(cm)
输出:
{
"ok": True,
"dx_cm": 2.5, # 靶面X偏移(cm,向右为正)
"dy_cm": -3.2, # 靶面Y偏移(cm,向上为正)
"distance_m": 5.43, # 相机到靶面距离(米)
"offset_method": "triangle_homography",
"distance_method": "pnp_triangle"
}
5. 鲁棒性设计
5.1 参数自适应
从config.py动态读取所有阈值(可在线调整)
三角形边长范围、灰度阈值、对比度要求等均可配置
5.2 异常处理
角点退化检测(距离<3像素判定为重复)
NaN/Inf校验(单应性矩阵、偏移量、距离)
距离合理性检查(0.3~20米)
5.3 降级策略
PnP失败 → 只输出偏移,距离置None
4角检测失败 → 尝试3角补全
快速路径失败 → CLAHE增强兜底(可选)
6. 性能特点
CPU友好:默认Otsu单次处理,多数场景10-30ms完成检测
内存可控:最大候选数截断(默认10个),避免组合爆炸
嵌入式适配:支持图像缩放、早退机制降低计算量
7. 局限性
依赖四个等腰直角三角形(需靶纸特殊设计)
要求三角形内部足够暗、与背景有对比度
单应性假设靶面为平面(实际靶纸可能有轻微起伏)
这套算法在射击训练系统中作为主要定位手段。
8. 为了加速单应性的计算,引入了yolo模型,一共做了两个模型,一个为靶纸和黑色三角形一体的识别模型,用于做原照片上快速找到靶纸区域。另一个模型是黑色三角形的模型,用于做靶纸区域再找黑色三角形。但是经过对比发现,引入黑色三角形模型反而更慢。入下面的流程A和流程B:
yolo靶纸+传统(流程B yolo靶纸+yolo黑色三角形(流程A)
平均值 646.08 916.4457143
标准差 94.61300968 57.40401849
公共前置(两条路都一样)
是否用靶环模型裁 Stage1
TRIANGLE_YOLO_ROI_ENABLE=True 时:跑 靶环 YOLO,得到全图上的 roi_xyxy,后面的三角形都在 img_work = 全图[roi] 上做(必要时再缩成 img_det 给整图传统分支用)。
False 时:roi_xyxy=None,三角形在 整幅相机图 上当 img_work。
之后都进入 try_triangle_scoring(img_cv, …, roi_xyxy=…, black_yolo_boxes_work=…)
在里面先做灰度、v_suppress、锐化、det_scale 缩略图等 prep(与是否黑三角模型无关)。
差别从 black_yolo_boxes_work 有没有有效子框列表 开始。
流程 A:用黑色三角形模型(Stage2 黑三角 YOLO
配置要点:TRIANGLE_BLACK_YOLO_ENABLE=True,且 TRIANGLE_BLACK_TRIANGLE_LOCATE_MODE="yolo",并且 已有 Stage1 裁切(roi_xyxy 不能为 None,否则根本不会跑黑三角 YOLO)。
步骤概要:
try_black_triangle_boxes_work
输入:全图 RGB + Stage1 的 ring_roi_xyxy。
在 Stage1 裁切图(与训练一致的 slab)上跑 黑三角 YOLO,得到若干个 子框(black_boxes_work,坐标在 裁切图/work 系)。
try_triangle_scoring 内
若 black_yolo_boxes_work 非空:
按配置在 Stage1 全分辨率灰度(或缩略灰度,视 det_scale / TRIANGLE_BLACK_YOLO_PATCH_GRAY_SOURCE)上,对每个子框裁 patch,跑 _extract_triangle_from_yolo_patch(子框内:Otsu → 失败再单次 Adaptive + 轮廓 + 形状/颜色)。
median_leg 过滤,再 四点分配 ID。
若 ≥3 个(通常 4 个)有效:认为 Stage2 成功,跳过 整幅 Stage1 上的 detect_triangle_markers。
若 不足 3 个 且未关 fallback:在 缩略后的整幅 work 灰度上再走 detect_triangle_markers(整图 Otsu + 整图 Adaptive×block_sizes + 各类 fallback),与「不用黑三角模型时的传统主路径」同类。
后续
角点从 det 坐标 ×inv_scale 回到 work,再 +roi 原点 回到全图;单应性、补第 4 点、PnP 等与另一条路相同。
耗时上多出来的部分:黑三角 YOLO 推理 + 每个子框一遍传统小流水线(成功时通常 不再付整图 detect_triangle_markers)。
流程 B:不用黑色三角形模型(纯传统定位三角)
典型配置(任一即可达到「不用黑三角模型」的效果):
TRIANGLE_BLACK_YOLO_ENABLE=False,或
TRIANGLE_BLACK_TRIANGLE_LOCATE_MODE="traditional"(即使模型开关开着也不跑黑三角 YOLO),或
没有 Stage1 ROIroi_xyxy is None)时,当前逻辑下 也不会跑 Stage2 黑三角 YOLO。
此时 black_yolo_boxes_work=None(或不等价于「有子框」)。
步骤概要:
try_triangle_scoring 内
不跑 子框 _extract_triangle_from_yolo_patch。
直接在 img_det(缩略后的 work 上调用 detect_triangle_markers
全局 Otsu(若 TRIANGLE_SKIP_GLOBAL_OTSU_EXTRACT_ON_YOLO_ROI 在有 ROI 时可能 不算 Otsu 轮廓,但仍会生成 Otsu 图供后续用);
可选 象限 ROITRIANGLE_ROI_ENABLED);
整图 AdaptiveTRIANGLE_ADAPTIVE_BLOCK_SIZES,例如 (11,));
不足再走 放宽 approxPolyDP、BlackHat 等。
后面同样是过滤、四点组合/象限分配、单应性、PnP 等。
特点:没有黑三角 NPU 时间,也 没有「按框重复 4 次子框传统」;但要在 一整张(缩略)ROI 图 上跑一套更重的 整图 pipeline。
对照一句话
用黑三角 YOLO(流程 A) 不用黑三角 YOLO(流程 B)
Stage2
黑三角模型给子框 → 子框内 Otsu + 至多一次 Adaptive
无 Stage2 模型
三角角点从哪来
优先 子框传统;不够再 整图 detect_triangle_markers
只有 整图 detect_triangle_markers
和「全图是否只做 Adaptive」
子框 不是只做 Adaptive;整图回退时也与全图路径一致(先 Otsu 等)
整图路径 也不是只做 Adaptive
靶环 YOLOStage1 裁切)在 A/B 里都可以开或关,与「黑三角模型」是独立开关。