Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fb1efcab8 | |||
| 35df4c473c |
@@ -127,6 +127,7 @@ class Match:
|
||||
scale: float
|
||||
score: float
|
||||
bbox_poly: np.ndarray # (4, 2) float32 - 4 vertici ordinati (ruotato)
|
||||
variant_idx: int = -1 # indice variante usata (per overlay coerente)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -1863,6 +1864,7 @@ class LineShapeMatcher:
|
||||
scale=var.scale,
|
||||
score=score_f,
|
||||
bbox_poly=poly,
|
||||
variant_idx=int(vi),
|
||||
))
|
||||
if len(kept) >= max_matches:
|
||||
break
|
||||
|
||||
+72
-35
@@ -157,49 +157,86 @@ def _draw_matches(scene: np.ndarray, matches: list[Match],
|
||||
]
|
||||
for i, m in enumerate(matches):
|
||||
color = palette[i % len(palette)]
|
||||
if template_gray is not None:
|
||||
# Posizione UCS: baricentro feature warpate (default = cx, cy se non disponibile).
|
||||
# Mantiene coerenza con anteprima modello che mostra UCS sul baricentro.
|
||||
ucs_x, ucs_y = float(m.cx), float(m.cy)
|
||||
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
|
||||
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
|
||||
if matcher is not None:
|
||||
# Edge filtrati con stessi param matcher (hysteresis)
|
||||
warped_gray = cv2.warpAffine(
|
||||
t, M, (W, H), flags=cv2.INTER_LINEAR, borderValue=0)
|
||||
mag, bins = matcher._gradient(warped_gray)
|
||||
if matcher.weak_grad < matcher.strong_grad:
|
||||
edge_mask = matcher._hysteresis_mask(mag)
|
||||
else:
|
||||
edge_mask = mag >= matcher.strong_grad
|
||||
# Background edge filtrati: tinta scura colore match
|
||||
if edge_mask.any():
|
||||
bg_overlay = np.zeros_like(out)
|
||||
dark = tuple(int(c * 0.35) for c in color)
|
||||
bg_overlay[edge_mask] = dark
|
||||
out = cv2.addWeighted(out, 1.0, bg_overlay, 0.7, 0)
|
||||
# Feature scelte: estrazione alla pose, dot colorati per bin
|
||||
fx, fy, fb = matcher._extract_features(mag, bins, None)
|
||||
for k in range(len(fx)):
|
||||
px, py = int(fx[k]), int(fy[k])
|
||||
if 0 <= px < W and 0 <= py < H:
|
||||
bcol = bin_colors[int(fb[k]) % len(bin_colors)]
|
||||
cv2.circle(out, (px, py), 2, bcol, -1, cv2.LINE_AA)
|
||||
# Background edge filtrati: warpa template + hysteresis
|
||||
warped_gray = cv2.warpAffine(
|
||||
t, M, (W, H), flags=cv2.INTER_LINEAR, borderValue=0)
|
||||
mag, _ = matcher._gradient(warped_gray)
|
||||
if matcher.weak_grad < matcher.strong_grad:
|
||||
edge_mask = matcher._hysteresis_mask(mag)
|
||||
else:
|
||||
# Legacy Canny
|
||||
edge = cv2.Canny(t, 50, 150)
|
||||
warped = cv2.warpAffine(edge, M, (W, H),
|
||||
flags=cv2.INTER_NEAREST, borderValue=0)
|
||||
mask = warped > 0
|
||||
if mask.any():
|
||||
overlay = np.zeros_like(out)
|
||||
overlay[mask] = color
|
||||
out[mask] = (0.3 * out[mask] + 0.7 * overlay[mask]).astype(np.uint8)
|
||||
edge_mask = mag >= matcher.strong_grad
|
||||
if edge_mask.any():
|
||||
bg_overlay = np.zeros_like(out)
|
||||
dark = tuple(int(c * 0.35) for c in color)
|
||||
bg_overlay[edge_mask] = dark
|
||||
out = cv2.addWeighted(out, 1.0, bg_overlay, 0.7, 0)
|
||||
# Feature reali del matcher: usa quelle pre-computate della
|
||||
# variante che ha generato il match. Stesse identiche feature
|
||||
# mostrate nell'anteprima modello (ruotate/scalate alla pose).
|
||||
vi = getattr(m, "variant_idx", -1)
|
||||
fx_scene = fy_scene = fb_arr = None
|
||||
if 0 <= vi < len(matcher.variants):
|
||||
lvl0 = matcher.variants[vi].levels[0]
|
||||
# dx/dy sono offsets relativi al CENTRO del template warpato
|
||||
# nelle coordinate del kernel template (gia' pre-ruotate
|
||||
# all'angolo della variante grezza). Per coerenza con la
|
||||
# pose finale m.angle_deg (post-refine), ri-rotazione del
|
||||
# delta angolare (m.angle_deg - var.angle_deg).
|
||||
var = matcher.variants[vi]
|
||||
dang = np.deg2rad(m.angle_deg - var.angle_deg)
|
||||
ca, sa = np.cos(dang), np.sin(dang)
|
||||
dxr = lvl0.dx * ca + lvl0.dy * sa
|
||||
dyr = -lvl0.dx * sa + lvl0.dy * ca
|
||||
fx_scene = m.cx + dxr
|
||||
fy_scene = m.cy + dyr
|
||||
fb_arr = lvl0.bin
|
||||
else:
|
||||
# Fallback: estrai feature dal warpato (perde precisione)
|
||||
_, bins_w = matcher._gradient(warped_gray)
|
||||
fx, fy, fb = matcher._extract_features(mag, bins_w, None)
|
||||
fx_scene = fx.astype(np.float32)
|
||||
fy_scene = fy.astype(np.float32)
|
||||
fb_arr = fb
|
||||
# Disegna feature
|
||||
for k in range(len(fx_scene)):
|
||||
px = int(round(float(fx_scene[k])))
|
||||
py = int(round(float(fy_scene[k])))
|
||||
if 0 <= px < W and 0 <= py < H:
|
||||
bcol = bin_colors[int(fb_arr[k]) % len(bin_colors)]
|
||||
cv2.circle(out, (px, py), 2, bcol, -1, cv2.LINE_AA)
|
||||
# UCS sul baricentro feature (in scene coords)
|
||||
if len(fx_scene) > 0:
|
||||
ucs_x = float(np.mean(fx_scene))
|
||||
ucs_y = float(np.mean(fy_scene))
|
||||
elif template_gray is not None:
|
||||
# Senza matcher: legacy Canny
|
||||
t = template_gray
|
||||
th, tw = t.shape
|
||||
cx_t = (tw - 1) / 2.0; cy_t = (th - 1) / 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
|
||||
edge = cv2.Canny(t, 50, 150)
|
||||
warped = cv2.warpAffine(edge, M, (W, H),
|
||||
flags=cv2.INTER_NEAREST, borderValue=0)
|
||||
mask = warped > 0
|
||||
if mask.any():
|
||||
overlay = np.zeros_like(out)
|
||||
overlay[mask] = color
|
||||
out[mask] = (0.3 * out[mask] + 0.7 * overlay[mask]).astype(np.uint8)
|
||||
# bbox poly e linea-marker rimossi (richiesta utente "togli la ROI"):
|
||||
# UCS + edge filtrati gia' identificano pose e orientamento,
|
||||
# il rettangolo aggiunto era ridondante e copriva il pezzo.
|
||||
cx, cy = int(round(m.cx)), int(round(m.cy))
|
||||
# UCS + edge filtrati gia' identificano pose e orientamento.
|
||||
cx, cy = int(round(ucs_x)), int(round(ucs_y))
|
||||
# UCS sul centro pose match (richiesta utente: come nell'anteprima
|
||||
# modello). Asse X rosso destra, Y verde basso (image y-down).
|
||||
# Lunghezza derivata dalla diagonale bbox per scala-invariante.
|
||||
|
||||
Reference in New Issue
Block a user