feat(boxes): 新增传统 CV 定位方法(--method cv),不依赖分类模型
背景差分:大半径方框均值估背景 → 残差(可选极性)→ 平滑 → 有无判定 → 按峰值归一化, 再交给与 gradcam / shap 同一套 cam_to_boxes 出框。只依赖 numpy。 与归因方法的差别:不需要 --checkpoint,分类器还没训练出来就能先跑一版框,也不受分类 精度影响;类别只能来自目录(--target label);找的是偏离局部背景的区域,而不是模型 据以判断类别的区域,所以对局部目标好、对铺满整图的纹理类给不出有意义的框。 有无缺陷是显式判定的:残差峰值要同时高于绝对对比度下限与噪声水平(MAD 估计)的 15 倍, 否则返回全零图。这条是必需的——实测纯噪声图的"峰值/MAD"稳定在 9 附近(最大 10.9, 几乎与噪声大小无关),有 0.25 对比度黑点时是 25~330;若只按峰值归一化,正常图的噪声 会被拉到 1,满图假框。阈值 15 取在两者之间。 顺带把积分图方框均值从 shap_explain.smooth 提到 engine/classical.box_mean 共用, 避免两处实现各自漂移。 实测:单张 0.011 秒(全量 11k 约 2 分钟);真实薄膜图上框能套住黑点、虫状物与划痕。 已知局限:背景估计在图像边界处对明暗阶跃有响应,贴边的交界可能出假框。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
32e56cb230
commit
65bc6b2045
+4
-13
@@ -65,19 +65,10 @@ def smooth(attribution: np.ndarray, radius: int = 2) -> np.ndarray:
|
||||
轻微平滑后再阈值化,框更完整。radius=0 表示不平滑。"""
|
||||
if radius <= 0:
|
||||
return attribution
|
||||
size = 2 * radius + 1
|
||||
padded = np.pad(attribution, radius, mode="edge")
|
||||
# 用积分图做 O(1) 的方框均值,避免逐像素卷积
|
||||
integral = padded.cumsum(axis=0).cumsum(axis=1)
|
||||
integral = np.pad(integral, ((1, 0), (1, 0)), mode="constant")
|
||||
height, width = attribution.shape
|
||||
total = (
|
||||
integral[size:size + height, size:size + width]
|
||||
- integral[0:height, size:size + width]
|
||||
- integral[size:size + height, 0:width]
|
||||
+ integral[0:height, 0:width]
|
||||
)
|
||||
smoothed = total / (size * size)
|
||||
# 与 engine/classical.py 共用同一份积分图实现,免得两处各自漂移
|
||||
from engine.classical import box_mean
|
||||
|
||||
smoothed = box_mean(attribution, radius)
|
||||
peak = smoothed.max()
|
||||
return smoothed / peak if peak > 0 else smoothed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user