fix: NCC robusto + reject bbox fuori scena + threshold piu rigorosi
3 fix per match spuri ad alto score visti su scena reale: 1. NCC con guard varianza minima: se template-patch o scene-patch hanno std quasi-zero (zone uniformi bianche/nere) NCC e instabile e da false-correlation alta. Ora ritorna 0 sotto soglia varianza. 2. Reject post-bbox: se il bounding-box ruotato del match sfora la scena per piu del 25%, scarto (centro derivato male o scala incoerente). Tollera 25% out-of-bounds (bordi). 3. FILTRO_FP_MAP alzato: leggero 0.20→0.30, medio 0.35→0.50, forte 0.50→0.70. Default piu conservativo per evitare match spuri su zone con pochi edge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+25
-1
@@ -796,7 +796,15 @@ class LineShapeMatcher:
|
||||
scn = scn_crop[valid].astype(np.float32)
|
||||
tm = tpl - tpl.mean()
|
||||
sm = scn - scn.mean()
|
||||
denom = np.sqrt((tm * tm).sum() * (sm * sm).sum()) + 1e-9
|
||||
# Std minimo: se template o scena patch sono quasi uniformi
|
||||
# (es. zona di sfondo bianco/nero), NCC e instabile e da false
|
||||
# high-correlation. Halcon-style: scarta match.
|
||||
tpl_var = float((tm * tm).sum())
|
||||
scn_var = float((sm * sm).sum())
|
||||
n_pix = float(valid.sum())
|
||||
if tpl_var < 1e-3 * n_pix or scn_var < 1e-3 * n_pix:
|
||||
return 0.0
|
||||
denom = np.sqrt(tpl_var * scn_var) + 1e-9
|
||||
return float((tm * sm).sum() / denom)
|
||||
|
||||
def find(
|
||||
@@ -1175,6 +1183,22 @@ class LineShapeMatcher:
|
||||
poly = _oriented_bbox_polygon(
|
||||
cx_out, cy_out, tw * var.scale, th * var.scale, ang_f,
|
||||
)
|
||||
# Reject match con bbox che sfora pesantemente la scena:
|
||||
# spesso indica match spurio (centro derivato male o scala
|
||||
# incoerente). Tollera 25% out-of-bounds, sopra rigetta.
|
||||
H_scn, W_scn = gray_full.shape
|
||||
poly_area = float(cv2.contourArea(poly))
|
||||
if poly_area > 0:
|
||||
# Clip poly alla scena: intersezione con rettangolo (0,0,W,H)
|
||||
scene_rect = np.array([
|
||||
[0, 0], [W_scn, 0], [W_scn, H_scn], [0, H_scn],
|
||||
], dtype=np.float32)
|
||||
inter, _ = cv2.intersectConvexConvex(
|
||||
poly.astype(np.float32), scene_rect,
|
||||
)
|
||||
inside_ratio = float(inter) / poly_area
|
||||
if inside_ratio < 0.75:
|
||||
continue
|
||||
# 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(
|
||||
|
||||
+3
-3
@@ -249,9 +249,9 @@ PRECISION_ANGLE_STEP = {
|
||||
# Un operatore sceglie il livello di rigore, non un numero astratto.
|
||||
FILTRO_FP_MAP = {
|
||||
"off": 0.0, # disabilitato: mantieni tutti i match shape-based
|
||||
"leggero": 0.20, # tollera variazioni intensità/illuminazione forti
|
||||
"medio": 0.35, # default bilanciato (consigliato)
|
||||
"forte": 0.50, # scarta match con intensità molto diversa dal template
|
||||
"leggero": 0.30, # tollera variazioni intensità/illuminazione forti
|
||||
"medio": 0.50, # default bilanciato (consigliato)
|
||||
"forte": 0.70, # scarta match con intensità molto diversa dal template
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user