feat: scale_penalty - score riflette dimensione oltre a forma

Shape matching e invariante scala per design: 3 ruote dentate di dim
diverse avevano tutte score 1.00 confondendo l operatore.

Parametro scale_penalty [0..1]: score_final = score * max(0, 1 - penalty * |scale - 1|)
UI dropdown 'Peso dimensione nel score' con preset 0 / 0.3 / 0.5 / 0.8.

Test rings con penalty 0.5: 1.00 -> 1.00, 0.95 -> 0.97, 0.80 -> 0.90.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 14:37:36 +02:00
parent 37b718e45e
commit cc7d035f66
4 changed files with 30 additions and 0 deletions
+13
View File
@@ -548,7 +548,15 @@ class LineShapeMatcher:
verify_ncc: bool = True,
verify_threshold: float = 0.4,
coarse_angle_factor: int = 2,
scale_penalty: float = 0.0,
) -> list[Match]:
"""
scale_penalty: se > 0, riduce lo score per match a scala diversa da 1.0:
score_final = score_shape * max(0, 1 - scale_penalty * |scale - 1|)
Utile se l'operatore vuole che match "identico al template anche per
dimensione" abbia score più alto di match "stessa forma, dimensione
diversa". scale_penalty=0 (default) = comportamento shape puro.
"""
if not self.variants:
raise RuntimeError("Matcher non addestrato: chiamare train() prima.")
@@ -746,6 +754,11 @@ class LineShapeMatcher:
poly = _oriented_bbox_polygon(
cx_f, cy_f, tw * var.scale, th * var.scale, ang_f,
)
# Penalità scala opzionale: score degrada con distanza da 1.0
if scale_penalty > 0.0 and var.scale != 1.0:
score_f = float(score_f) * max(
0.0, 1.0 - scale_penalty * abs(var.scale - 1.0)
)
kept.append(Match(
cx=cx_f, cy=cy_f,
angle_deg=ang_f,