# 实验演进记录(A → L) > 最终方案与使用说明见 [solution.md](solution.md)。 > 本文记录每个方法的思路、失败原因与沉淀的经验教训, > 原始实验脚本在 `try/`,输出在 `try/out/<方法字母>/`。 ## 方法总览 | 方法 | 脚本 | 思路 | 结论 | | --- | --- | --- | --- | | A | method_a_template.py | 蒙版 CCORR 多尺度模板匹配 | 废弃 | | A2 | method_a2_ccoeff.py | 蒙版 CCOEFF + 峰显著度 + NMS | 基线可用,但锁纹理 | | B | method_b_sift.py | SIFT + RANSAC 迭代聚类 | 仅 2 样本可用,留作真值锚点 | | C | method_c_rotation.py | NCC 粗扫 + 旋转响应二次评分 | 第一阶段候选即错 | | D | method_d_shape.py | Chamfer 轮廓距离 | 小尺度纹理饱和 | | E | method_e_shape_coverage.py | 轮廓边缘覆盖率 | 同上 | | F | method_f_contour.py | Canny 轮廓 + matchShapes | 背景轮廓合并成超大块 | | G | method_g_component.py | 固定暗度阈值连通域 | 阈值敏感 | | H | method_h_silhouette.py | alpha 轮廓距离 + 局部对比度 | 分数归一化饱和 | | I | method_i_adaptive_components.py | 自适应暗目标连通域 | 误检照片内容 | | J | method_j_objects.py | 低饱和度暗色物体分割 | 同上 | | K | method_k_objectness.py | 暗色覆盖物概率图 + 掩码 CCORR | 掩码 CCORR 边界产生 inf | | **L** | `src/method_l_shape.py` | **方向感知倒角 + 洞内部特征 + 旋转扫描** | **最终方案,10/10** | ## 逐方法教训 ### A / A2:RGB 模板匹配(不减小均值的代价) - `TM_CCORR_NORMED` 不做均值中心化,亮背景上处处高分; - 跨尺度直接比原始分数偏向小模板 → A2 改用峰显著度 `(max-median)/std`; - A2 在 8/10 样本上候选位置合理,但 41ac 出现多峰分歧—— 后来证明这些 0.7 的高分全是**小尺度纹理巧合**,方向本身是错的。 ### B:SIFT(意外价值) - 平面图形缺少纹理,大部分样本匹配不足; - 但在纹理丰富的 4db9、d7a7 上给出亚像素级真值 (scale≈1.00、rot≈0°),成为后续所有方法的**交叉验证锚点**。 ### C:旋转感知 NCC(两次评分救不了错误的候选) - 旋转响应曲线本身有效(真目标 rot≈0),但候选来自 NCC 粗扫, 粗扫错了旋转阶段无法挽回。 ### D/E:倒角与覆盖率(尺度公平性问题) - 覆盖率在小尺度上饱和到 1.0(背景纹理到处有边); - 倒角均值在密纹理区反而更低 → 必须限制尺度范围并加方向约束。 ### F/G/H/I/J/K:分割路线的共同困境 - Canny 轮廓易把地面/山脉合并成超大块(F); - 固定/自适应暗度阈值对每张照片都不同(G/I/J); - K 的教训:`TM_CCORR_NORMED` 带 mask 在边界产生 inf 值, 需要手写 filter2D 掩码 NCC(后来用于决定性实验)。 ## 转折点实验(值得复用的诊断手段) 1. **掩码 NCC 全图扫描**(手写 filter2D 实现,无 inf 问题): 对 41ac/444d 在尺度 0.9–1.1 全图扫描,最高分仅 0.56/0.46 → 证明 mark RGB 与洞内容无像素关系,RGB 路线全部判死。 2. **闭合轮廓 + matchShapes**(444d 上): Canny 闭合轮廓直接命中两个洞,Hu≈0.003,左洞 rot=-0.6°、右洞 -15.5° → 证明"轮廓 + 尺度 + 旋转"路线成立,且给出 444d 独立真值。 3. **三特征分离度测量**: 洞:内部边缘密度 ≤0.1、亮度差 -40~-104; 草地误检:密度 0.36、亮度差 +6 → 直接给出 L 的特征权重依据。 ## 调试中踩过的具体坑 - `np.flatnonzero` 对 2D 数组返回一维扁平索引,取坐标应用 `np.argwhere`; - `filter2D` 输出是全尺寸,与手写滑窗比对时要裁剪有效相关区 `[h//2 : h//2+H-h+1, w//2 : w//2+W-w+1]`; - 方向桶不能越界重叠:角度已在 [0,180),9 桶直接线性划分即可, 最后一桶再做 wrap 会导致点被双计(表现为均值超上限); - `np.arange` 有浮点累积误差,参与区间比较前先 `round(s, 3)`; - Canny 阈值过低(如 26/77)会让 JPEG 噪声淹没"内部平坦"特征。 ## 无 ground truth 时的交叉验证方法 1. 找至少一个可用独立方法的样本建立锚点(如 SIFT 能用的纹理丰富样本); 2. 用结构性证据补充锚点:候选 bbox 尺寸与 mark alpha bbox 完全一致 (41ac:88×106 vs 88×106); 3. 全部候选可视化后人工目检:真目标应落在几何图形上而非纹理上; 4. 结果叠加轮廓回贴大图(`src/verify_result.py`),观察贴合精度。