Compare commits
6 Commits
2c9160e4be
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 452810b67a | |||
| 8c46a6ca9b | |||
| d335f866a3 | |||
| 88f80a2cad | |||
| d52d0d0489 | |||
| 9451a418a6 |
+14
-6
@@ -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,12 @@ 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: 10 iter golden con tol 0.05 deg.
|
||||
# Compromesso speed/accuracy: il parabolic fit aggiuntivo era
|
||||
# instabile su score map non-smooth (template simmetrici producono
|
||||
# multipli local max ravvicinati che lo facevano divergere).
|
||||
tol = 0.05
|
||||
for _ in range(10):
|
||||
if s1 > best[1]:
|
||||
best = (angle_deg + x1, s1, cx1, cy1)
|
||||
if s2 > best[1]:
|
||||
@@ -1301,8 +1305,9 @@ class LineShapeMatcher:
|
||||
if t is None:
|
||||
return 1.0
|
||||
h, w = t.shape
|
||||
cx_t = (w - 1) / 2.0
|
||||
cy_t = (h - 1) / 2.0
|
||||
# Coerente con training (center = diag / 2.0, no -1)
|
||||
cx_t = w / 2.0
|
||||
cy_t = h / 2.0
|
||||
|
||||
# Bounding box del template ruotato/scalato attorno a (cx, cy)
|
||||
diag = int(np.ceil(np.hypot(w, h) * scale)) + 8
|
||||
@@ -1825,7 +1830,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
|
||||
|
||||
+12
-6
@@ -168,7 +168,10 @@ def _draw_matches(scene: np.ndarray, matches: list[Match],
|
||||
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
|
||||
# Centro template coerente col training: in train si usa
|
||||
# `center = (diag / 2.0, diag / 2.0)` (no -1). Usare (tw-1)/2
|
||||
# introduceva uno shift di 0.5px per template di lato pari.
|
||||
cx_t = tw / 2.0; cy_t = th / 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
|
||||
@@ -181,10 +184,11 @@ def _draw_matches(scene: np.ndarray, matches: list[Match],
|
||||
warped_mask = cv2.warpAffine(
|
||||
mask_src, M, (W_scene, H_scene),
|
||||
flags=cv2.INTER_NEAREST, borderValue=0)
|
||||
# Erode di spread_radius per scartare la fascia di transizione
|
||||
# bordo che produce gradient spurio
|
||||
er_k = max(3, 2 * matcher.spread_radius + 1)
|
||||
kernel_er = np.ones((er_k, er_k), np.uint8)
|
||||
# Erode minimo (3x3) per togliere SOLO artefatti border-padding
|
||||
# (~1px di bordo nero da warpAffine borderValue=0). Erode piu'
|
||||
# grande spostava visualmente l'edge verso l'interno e creava
|
||||
# apparente "traslazione fissa" rispetto al bordo del pezzo.
|
||||
kernel_er = np.ones((3, 3), np.uint8)
|
||||
warped_mask = cv2.erode(warped_mask, kernel_er)
|
||||
mag, _ = matcher._gradient(warped_gray)
|
||||
if matcher.weak_grad < matcher.strong_grad:
|
||||
@@ -194,7 +198,9 @@ def _draw_matches(scene: np.ndarray, matches: list[Match],
|
||||
edge_mask = edge_mask & (warped_mask > 0)
|
||||
if edge_mask.any():
|
||||
edge_overlay = np.zeros_like(out)
|
||||
edge_overlay[edge_mask] = (0, 220, 0) # verde brillante
|
||||
# Ciano (cambiato da verde): non collide col verde dell'asse
|
||||
# Y dell'UCS che altrimenti scompariva nell'overlay edge.
|
||||
edge_overlay[edge_mask] = (255, 200, 0) # ciano (BGR)
|
||||
out = cv2.addWeighted(out, 1.0, edge_overlay, 0.6, 0)
|
||||
L = max(20, int(L_base * m.scale))
|
||||
# X axis = rotazione di (1, 0) con cv2 matrix → (cos, -sin)
|
||||
|
||||
@@ -102,8 +102,8 @@
|
||||
<div class="field">
|
||||
<label>Simmetria</label>
|
||||
<select id="p-simmetria">
|
||||
<option value="nessuna" selected>Nessuna (0..360°)</option>
|
||||
<option value="invariante">Invariante (cerchi — no rotazione)</option>
|
||||
<option value="nessuna">Nessuna (0..360°)</option>
|
||||
<option value="bilaterale">Bilaterale (speculare 180°)</option>
|
||||
<option value="rot_3">Rotazionale 3× (120°)</option>
|
||||
<option value="rot_4">Rotazionale 4× (90°)</option>
|
||||
|
||||
Reference in New Issue
Block a user