From 8c46a6ca9b5632f0518c317fb1cd6272d7c69f28 Mon Sep 17 00:00:00 2001 From: AdrianoDev Date: Tue, 5 May 2026 12:45:11 +0200 Subject: [PATCH] fix: rimossa traslazione fissa edge overlay match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Causa principale: erode di (2*spread_radius+1) sulla maschera warpata toglieva troppo bordo. Per spread_radius=8 → kernel 17x17 = -8px da ogni lato. L'edge map applicata sopra mostrava i bordi spostati di ~8px verso l'interno del pezzo, creando apparente "traslazione fissa". Soluzione: erode 3x3 solo per rimuovere ~1px di bordo nero residuo da warpAffine borderValue=0 (artefatto di padding). Bordi del pezzo ora visualizzati nelle posizioni corrette. Bonus fix: cx_t calcolato come w/2 invece di (w-1)/2, coerente con center=diag/2.0 usato in training (era 0.5px di shift residuo per template di lato pari). Co-Authored-By: Claude Opus 4.7 (1M context) --- pm2d/line_matcher.py | 5 +++-- pm2d/web/server.py | 14 +++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pm2d/line_matcher.py b/pm2d/line_matcher.py index 87c108f..15967bd 100644 --- a/pm2d/line_matcher.py +++ b/pm2d/line_matcher.py @@ -1305,8 +1305,9 @@ class LineShapeMatcher: if t is None: return 1.0 h, w = t.shape - cx_t = (w - 1) / 2.0 - cy_t = (h - 1) / 2.0 + # Coerente con training (center = diag / 2.0, no -1) + cx_t = w / 2.0 + cy_t = h / 2.0 # Bounding box del template ruotato/scalato attorno a (cx, cy) diag = int(np.ceil(np.hypot(w, h) * scale)) + 8 diff --git a/pm2d/web/server.py b/pm2d/web/server.py index 8fdaf68..f1d58fb 100644 --- a/pm2d/web/server.py +++ b/pm2d/web/server.py @@ -168,7 +168,10 @@ def _draw_matches(scene: np.ndarray, matches: list[Match], if template_gray is not None and matcher is not None: t = template_gray th, tw = t.shape - cx_t = (tw - 1) / 2.0; cy_t = (th - 1) / 2.0 + # Centro template coerente col training: in train si usa + # `center = (diag / 2.0, diag / 2.0)` (no -1). Usare (tw-1)/2 + # introduceva uno shift di 0.5px per template di lato pari. + cx_t = tw / 2.0; cy_t = th / 2.0 M = cv2.getRotationMatrix2D((cx_t, cy_t), m.angle_deg, m.scale) M[0, 2] += m.cx - cx_t M[1, 2] += m.cy - cy_t @@ -181,10 +184,11 @@ def _draw_matches(scene: np.ndarray, matches: list[Match], warped_mask = cv2.warpAffine( mask_src, M, (W_scene, H_scene), flags=cv2.INTER_NEAREST, borderValue=0) - # Erode di spread_radius per scartare la fascia di transizione - # bordo che produce gradient spurio - er_k = max(3, 2 * matcher.spread_radius + 1) - kernel_er = np.ones((er_k, er_k), np.uint8) + # Erode minimo (3x3) per togliere SOLO artefatti border-padding + # (~1px di bordo nero da warpAffine borderValue=0). Erode piu' + # grande spostava visualmente l'edge verso l'interno e creava + # apparente "traslazione fissa" rispetto al bordo del pezzo. + kernel_er = np.ones((3, 3), np.uint8) warped_mask = cv2.erode(warped_mask, kernel_er) mag, _ = matcher._gradient(warped_gray) if matcher.weak_grad < matcher.strong_grad: