"""Test di non-regressione su precisione e recall (GT sintetica). Soglie derivate dalle misure di Fase 2 (errore mediano ~0.05 deg / ~0.08 px) con margine 3-4x per assorbire rumore tra run/macchine. Una regressione del refine (es. score saturo, minMaxLoc sul plateau) riporterebbe gli errori a 2-4 deg / 4 px e fa fallire i test con margine enorme. """ from __future__ import annotations import numpy as np from pm2d import LineShapeMatcher from tests.conftest import GT_POSES, match_errors def _find(template, scene, step, **kw): m = LineShapeMatcher(angle_step_deg=step, num_features=96) m.train(template) return m.find(scene, min_score=0.5, max_matches=10, **kw) def test_recall_and_precision_step5(template, scene): matches = _find(template, scene, 5.0) errs_a, errs_p, miss = match_errors(matches, GT_POSES) assert miss == 0, f"{miss} pose GT non trovate" assert float(np.median(errs_a)) < 0.2, f"err angolo mediano {np.median(errs_a):.3f} deg" assert float(np.max(errs_a)) < 0.5, f"err angolo max {np.max(errs_a):.3f} deg" assert float(np.median(errs_p)) < 0.3, f"err posizione mediano {np.median(errs_p):.3f} px" assert float(np.max(errs_p)) < 1.0, f"err posizione max {np.max(errs_p):.3f} px" def test_recall_and_precision_step2(template, scene): # Step fine: storicamente il caso peggiore (plateau con piu' varianti # dentro la tolleranza spread → scelta variante arbitraria). matches = _find(template, scene, 2.0) errs_a, errs_p, miss = match_errors(matches, GT_POSES) assert miss == 0, f"{miss} pose GT non trovate" assert float(np.median(errs_a)) < 0.2 assert float(np.max(errs_a)) < 0.5 assert float(np.median(errs_p)) < 0.3 def test_no_false_positives(template, scene): # max_matches alto: non devono comparire match spuri oltre le 7 pose. matches = _find(template, scene, 5.0) assert len(matches) <= len(GT_POSES) + 1, ( f"{len(matches)} match per {len(GT_POSES)} oggetti reali" ) def test_full_scan_path_equivalent(template, scene): # Il path full-scan (propagate off) deve trovare le stesse pose. matches = _find(template, scene, 5.0, pyramid_propagate=False) _, _, miss = match_errors(matches, GT_POSES) assert miss == 0