Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 041b26e791 |
+22
-4
@@ -152,14 +152,27 @@ def _cache_key(template_bgr: np.ndarray, mask: np.ndarray | None) -> str:
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def auto_tune(template_bgr: np.ndarray, mask: np.ndarray | None = None) -> dict:
|
||||
def auto_tune(
|
||||
template_bgr: np.ndarray,
|
||||
mask: np.ndarray | None = None,
|
||||
angle_tolerance_deg: float | None = None,
|
||||
angle_center_deg: float = 0.0,
|
||||
) -> dict:
|
||||
"""Analizza template e ritorna dict parametri suggeriti.
|
||||
|
||||
Chiavi compatibili con edit_params PARAM_SCHEMA.
|
||||
|
||||
angle_tolerance_deg: se != None, restringe angle_range a
|
||||
(center - tol, center + tol). Usare quando l'orientamento del
|
||||
pezzo e' noto a priori (feeder con guida, posizionamento
|
||||
meccanico): training molto piu rapido (24x meno varianti per
|
||||
tol=15° vs 360° pieno).
|
||||
|
||||
Risultato cachato in-memory (LRU): ri-chiamare con stessa ROI è O(1).
|
||||
"""
|
||||
ck = _cache_key(template_bgr, mask)
|
||||
if angle_tolerance_deg is not None:
|
||||
ck = f"{ck}|tol={angle_tolerance_deg}|c={angle_center_deg}"
|
||||
cached = _TUNE_CACHE.get(ck)
|
||||
if cached is not None:
|
||||
_TUNE_CACHE.move_to_end(ck)
|
||||
@@ -208,8 +221,13 @@ def auto_tune(template_bgr: np.ndarray, mask: np.ndarray | None = None) -> dict:
|
||||
# spread_radius proporzionale a risoluzione + pyramid (tolleranza ~1% dim)
|
||||
spread_radius = int(np.clip(max(3, min_side * 0.02), 3, 8))
|
||||
|
||||
# angle range ridotto se simmetria rotazionale
|
||||
angle_max = 360.0 / sym["order"] if sym["order"] > 1 else 360.0
|
||||
# angle range: priorita' a tolerance hint utente, poi simmetria rotazionale.
|
||||
if angle_tolerance_deg is not None:
|
||||
angle_min = float(angle_center_deg - angle_tolerance_deg)
|
||||
angle_max = float(angle_center_deg + angle_tolerance_deg)
|
||||
else:
|
||||
angle_min = 0.0
|
||||
angle_max = 360.0 / sym["order"] if sym["order"] > 1 else 360.0
|
||||
|
||||
# min_score: se entropia orient alta → template distintivo → soglia alta ok
|
||||
# se entropia bassa → template ambiguo → soglia più permissiva
|
||||
@@ -228,7 +246,7 @@ def auto_tune(template_bgr: np.ndarray, mask: np.ndarray | None = None) -> dict:
|
||||
|
||||
result = {
|
||||
"backend": "line",
|
||||
"angle_min": 0.0,
|
||||
"angle_min": angle_min,
|
||||
"angle_max": angle_max,
|
||||
"angle_step": angle_step,
|
||||
"scale_min": 1.0,
|
||||
|
||||
+24
-35
@@ -49,27 +49,6 @@ from pm2d._jit_kernels import (
|
||||
N_BINS = 8 # orientamenti quantizzati modulo π
|
||||
|
||||
|
||||
def _poly_iou(p1: np.ndarray, p2: np.ndarray) -> float:
|
||||
"""IoU tra due poligoni convessi (4 vertici, float32) via cv2.intersectConvexConvex.
|
||||
|
||||
Usa OpenCV (cv2.intersectConvexConvex) per intersezione esatta:
|
||||
ritorna area intersezione / area unione. Robusto a rotazioni
|
||||
qualsiasi (anti-orarie/orarie) - cv2 normalizza orientamento.
|
||||
"""
|
||||
a1 = float(cv2.contourArea(p1))
|
||||
a2 = float(cv2.contourArea(p2))
|
||||
if a1 <= 0 or a2 <= 0:
|
||||
return 0.0
|
||||
inter_area, _ = cv2.intersectConvexConvex(
|
||||
p1.astype(np.float32), p2.astype(np.float32),
|
||||
)
|
||||
inter_area = float(inter_area)
|
||||
if inter_area <= 0:
|
||||
return 0.0
|
||||
union = a1 + a2 - inter_area
|
||||
return inter_area / union if union > 0 else 0.0
|
||||
|
||||
|
||||
def _oriented_bbox_polygon(
|
||||
cx: float, cy: float, w: float, h: float, angle_deg: float,
|
||||
) -> np.ndarray:
|
||||
@@ -213,6 +192,26 @@ class LineShapeMatcher:
|
||||
np.array(picked_y, np.int32),
|
||||
np.array(picked_b, np.int8))
|
||||
|
||||
def set_angle_range_around(
|
||||
self, center_deg: float, tolerance_deg: float,
|
||||
) -> None:
|
||||
"""Restringe angle_range a (center - tol, center + tol).
|
||||
|
||||
Comodo helper per scenari in cui l'orientamento del pezzo e'
|
||||
noto a priori entro ±tolerance_deg (es. feeder vibrante con
|
||||
guida meccanica). Riduce drasticamente le varianti generate
|
||||
in train(): es. ±15° vs 360° = 24x meno varianti, training
|
||||
e matching molto piu veloci.
|
||||
|
||||
Esempio:
|
||||
m.set_angle_range_around(0, 20) # cerca solo in [-20, +20]
|
||||
m.train(template)
|
||||
"""
|
||||
self.angle_range_deg = (
|
||||
float(center_deg - tolerance_deg),
|
||||
float(center_deg + tolerance_deg),
|
||||
)
|
||||
|
||||
def _scale_list(self) -> list[float]:
|
||||
s0, s1 = self.scale_range
|
||||
if s0 >= s1 or self.scale_step <= 0:
|
||||
@@ -783,7 +782,6 @@ class LineShapeMatcher:
|
||||
refine_pose_joint: bool = False,
|
||||
greediness: float = 0.0,
|
||||
batch_top: bool = False,
|
||||
nms_iou_threshold: float = 0.3,
|
||||
) -> list[Match]:
|
||||
"""
|
||||
scale_penalty: se > 0, riduce lo score per match a scala diversa da 1.0:
|
||||
@@ -1144,21 +1142,12 @@ class LineShapeMatcher:
|
||||
score_f = float(score_f) * max(
|
||||
0.0, 1.0 - scale_penalty * abs(var.scale - 1.0)
|
||||
)
|
||||
# NMS post-refine cross-variant: usa IoU bbox-poligonale invece
|
||||
# di sola distanza centro. Due match orientati diversi ma vicini
|
||||
# (pezzi adiacenti) NON vengono fusi se l'overlap reale e basso;
|
||||
# due match dello stesso pezzo (centri uguali, rotazione simile)
|
||||
# hanno IoU alto e vengono droppati.
|
||||
# Fallback distanza centro per match con bbox degenere.
|
||||
# NMS post-refine: refine puo spostare il match di nms_radius;
|
||||
# ricontrollo overlap su match gia accettati per evitare
|
||||
# duplicati (stesso oggetto trovato da varianti angolari diverse).
|
||||
dup = False
|
||||
for k in kept:
|
||||
iou = _poly_iou(k.bbox_poly, poly)
|
||||
if iou > nms_iou_threshold:
|
||||
dup = True
|
||||
break
|
||||
# Sicurezza: centri molto vicini (dentro nms_radius/2)
|
||||
# sempre fusi, anche con orientamenti molto diversi.
|
||||
if (k.cx - cx_out) ** 2 + (k.cy - cy_out) ** 2 < (r2 / 4.0):
|
||||
if (k.cx - cx_out) ** 2 + (k.cy - cy_out) ** 2 < r2:
|
||||
dup = True
|
||||
break
|
||||
if dup:
|
||||
|
||||
Reference in New Issue
Block a user