feat(detect): 固定 160x160 输入,只用裁剪与镜像填充,禁止缩放

产线要求送进模型的图固定为 N×N 且不许 resize——缺陷的绝对尺度是判别依据,
拉伸会把"5 像素的黑点"变成别的东西。

- engine/tiling.py:切片几何。边长 < N 镜像填充(reflect,真镜像,原图居中);
  边长 >= N 按步长裁剪、末片贴边保证全覆盖。框跟着平移裁剪,露出面积低于
  min_visibility 的丢弃;to_source 反向映射供推理时拼回原图。
- scripts/tile_dataset.py:整套数据集转换。有框图切出的空片会爆量
  (524x959 能切 24 片),用 --max-empty-ratio 限量;原本无框的真负样本不受限。
- 训练配置 imgsz 改 160,并显式关掉 scale 与 translate——ultralytics 的默认值是
  0.5 / 0.1 而不是 0,不写出来等于一直在做仿射缩放,违反约束。

尺寸正好等于 imgsz 时 letterbox 退化为空操作(r=1、dw=dh=0),核对过源码。
合成数据上验证:所有片正好 160x160、框区域与原图逐像素一致、填充是真镜像。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Shaun Zhou
2026-09-23 12:27:57 +08:00
co-authored by Claude Opus 5
parent 1684fddd7f
commit 2a92275317
5 changed files with 753 additions and 2 deletions
+16 -2
View File
@@ -17,7 +17,10 @@ seed: 42
device: auto
data:
yaml: data/film_yolo/data.yaml
# 切成固定 160x160 的片:产线要求模型输入固定尺寸且禁止 resize。
# uv run python scripts/tile_dataset.py --data data/film_yolo/data.yaml \
# --out data/film_yolo_160 --size 160
yaml: data/film_yolo_160/data.yaml
model:
# CLAUDE.md 的"只用 convolution 模型"只约束聚类与数据集生成阶段,检测这一步不受限,
@@ -27,7 +30,11 @@ model:
train:
epochs: 500
imgsz: 640
# 必须与数据集的片大小一致。数据已经是 160x160,ultralytics 的 letterbox 这时
# 缩放比 r = min(160/160, 160/160) = 1、填充 dw=dh=0,退化成空操作,不会碰像素。
# 改尺寸时:重跑 tile_dataset.py,再同步改这里。
imgsz: 160
batch: 16
workers: 8
optimizer: auto
@@ -39,8 +46,15 @@ train:
# 数据增强。翻转按聚类阶段的结论开着(缺陷没有固定朝向);
# 但 mosaic/mixup 关掉——它们会把四张图拼在一起,而我们每张图只有一个弱监督框,
# 拼接后小目标被缩得更小,对 blackdot / whitedot 这类本来就只占千分之几面积的类别是伤害。
# 只留镜像翻转:翻转不改变尺度,符合"禁止拉伸"的约束
fliplr: 0.5
flipud: 0.5
# 以下几何增强都会重采样像素,全部关掉。
# 注意 scale 与 translate 的 ultralytics 默认值是 0.5 / 0.1(不是 0),
# 不显式写出来就等于一直在做仿射缩放平移。
scale: 0.0
translate: 0.0
degrees: 0.0
mosaic: 0.0
mixup: 0.0