diff --git a/pm2d/line_matcher.py b/pm2d/line_matcher.py index eae4d50..360a82d 100644 --- a/pm2d/line_matcher.py +++ b/pm2d/line_matcher.py @@ -954,7 +954,7 @@ class LineShapeMatcher: # variante e' quantizzato a multipli di angle_step (5 deg default). # Refine angolare e' essenziale per orientamento sub-step. if search_radius is None: - search_radius = self._effective_angle_step() / 2.0 + search_radius = self._effective_angle_step() h, w = template_gray.shape sw = max(16, int(round(w * scale))) @@ -1042,8 +1042,11 @@ class LineShapeMatcher: # Score all'origine come riferimento (ang offset 0) s0, cx0_s, cy0_s = _score_at_angle(0.0) best = (angle_deg, s0, cx0_s, cy0_s) - tol = 0.1 # gradi - for _ in range(8): + # Precisione angolare: tol piu' stretto + piu' iterazioni golden. + # 16 iter golden coprono ~1e-3 della search_radius -> precisione + # ~0.005 deg per step=10 deg. + tol = 0.02 + for _ in range(16): if s1 > best[1]: best = (angle_deg + x1, s1, cx1, cy1) if s2 > best[1]: @@ -1060,6 +1063,22 @@ class LineShapeMatcher: x1 = x2; s1 = s2; cx1 = cx2; cy1 = cy2 x2 = a_lo + _GOLDEN * (a_hi - a_lo) s2, cx2, cy2 = _score_at_angle(x2) + # Parabolic fit finale sui 3 punti vicini al best per refinement + # sub-step ulteriore (precisione <0.01 deg quando lo score map e' + # smooth attorno al picco). + best_off = best[0] - angle_deg + delta = max(0.05, abs(a_hi - a_lo) * 0.5) + sm, _, _ = _score_at_angle(best_off - delta) + sp, _, _ = _score_at_angle(best_off + delta) + # Vertice parabola su 3 punti (sm, sb, sp) a (-delta, 0, +delta) + denom = sm - 2 * best[1] + sp + if abs(denom) > 1e-9: + shift = 0.5 * (sm - sp) / denom * delta + shift = max(-delta, min(delta, shift)) + new_off = best_off + shift + sn, cxn, cyn = _score_at_angle(new_off) + if sn >= best[1]: + return (angle_deg + new_off, sn, cxn, cyn) return best def _get_view_template( @@ -1825,7 +1844,10 @@ class LineShapeMatcher: ang_f, score_f, cx_f, cy_f = self._refine_angle( spread0, bit_active_full, self.template_gray, cx_f, cy_f, var.angle_deg, var.scale, mask_full, - search_radius=self._effective_angle_step() / 2.0, + # Search radius esteso allo step pieno (era step/2): + # copre il caso peggiore in cui il picco vero e' all'estremo + # del bin angolare della variante grezza. + search_radius=self._effective_angle_step(), original_score=score, ) # Halcon SubPixel='least_squares_high': refinement iterativo diff --git a/pm2d/web/static/index.html b/pm2d/web/static/index.html index 442a9b3..4d23bc6 100644 --- a/pm2d/web/static/index.html +++ b/pm2d/web/static/index.html @@ -102,8 +102,8 @@