Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f05dec5183 |
@@ -740,6 +740,63 @@ class LineShapeMatcher:
|
|||||||
s2, cx2, cy2 = _score_at_angle(x2)
|
s2, cx2, cy2 = _score_at_angle(x2)
|
||||||
return best
|
return best
|
||||||
|
|
||||||
|
def _compute_recall(
|
||||||
|
self, spread0: np.ndarray, variant: _Variant,
|
||||||
|
cx: float, cy: float, angle_deg: float,
|
||||||
|
) -> float:
|
||||||
|
"""Frazione di feature template che combaciano nello spread scena
|
||||||
|
alla pose (cx, cy, angle, variant.scale).
|
||||||
|
|
||||||
|
Riusa template_gray + warp per estrarre features alla pose esatta
|
||||||
|
(vs feature pre-computate alla pose della variante grezza). Ritorna
|
||||||
|
hits/N in [0, 1]. Halcon-equivalent: questo e' il "MinScore" originale.
|
||||||
|
"""
|
||||||
|
if self.template_gray is None:
|
||||||
|
return 1.0
|
||||||
|
h, w = self.template_gray.shape
|
||||||
|
scale = variant.scale
|
||||||
|
sw = max(16, int(round(w * scale)))
|
||||||
|
sh = max(16, int(round(h * scale)))
|
||||||
|
gray_s = cv2.resize(self.template_gray, (sw, sh), interpolation=cv2.INTER_LINEAR)
|
||||||
|
mask_src = (
|
||||||
|
self._train_mask if self._train_mask is not None
|
||||||
|
else np.full_like(self.template_gray, 255)
|
||||||
|
)
|
||||||
|
mask_s = cv2.resize(mask_src, (sw, sh), interpolation=cv2.INTER_NEAREST)
|
||||||
|
diag = int(np.ceil(np.hypot(sh, sw))) + 6
|
||||||
|
py = (diag - sh) // 2; px = (diag - sw) // 2
|
||||||
|
gray_p = cv2.copyMakeBorder(
|
||||||
|
gray_s, py, diag - sh - py, px, diag - sw - px, cv2.BORDER_REPLICATE,
|
||||||
|
)
|
||||||
|
mask_p = cv2.copyMakeBorder(
|
||||||
|
mask_s, py, diag - sh - py, px, diag - sw - px,
|
||||||
|
cv2.BORDER_CONSTANT, value=0,
|
||||||
|
)
|
||||||
|
center = (diag / 2.0, diag / 2.0)
|
||||||
|
M = cv2.getRotationMatrix2D(center, angle_deg, 1.0)
|
||||||
|
gray_r = cv2.warpAffine(gray_p, M, (diag, diag),
|
||||||
|
flags=cv2.INTER_LINEAR,
|
||||||
|
borderMode=cv2.BORDER_REPLICATE)
|
||||||
|
mask_r = cv2.warpAffine(mask_p, M, (diag, diag),
|
||||||
|
flags=cv2.INTER_NEAREST, borderValue=0)
|
||||||
|
mag, bins = self._gradient(gray_r)
|
||||||
|
fx, fy, fb = self._extract_features(mag, bins, mask_r)
|
||||||
|
n_feat = len(fx)
|
||||||
|
if n_feat < 4:
|
||||||
|
return 0.0
|
||||||
|
H, W = spread0.shape
|
||||||
|
spread_dtype = spread0.dtype.type
|
||||||
|
ix = int(round(cx)); iy = int(round(cy))
|
||||||
|
hits = 0
|
||||||
|
for i in range(n_feat):
|
||||||
|
xs = ix + int(fx[i] - center[0])
|
||||||
|
ys = iy + int(fy[i] - center[1])
|
||||||
|
if 0 <= xs < W and 0 <= ys < H:
|
||||||
|
bit = spread_dtype(1 << int(fb[i]))
|
||||||
|
if spread0[ys, xs] & bit:
|
||||||
|
hits += 1
|
||||||
|
return hits / n_feat
|
||||||
|
|
||||||
def _verify_ncc(
|
def _verify_ncc(
|
||||||
self, scene_gray: np.ndarray, cx: float, cy: float,
|
self, scene_gray: np.ndarray, cx: float, cy: float,
|
||||||
angle_deg: float, scale: float,
|
angle_deg: float, scale: float,
|
||||||
@@ -828,6 +885,7 @@ class LineShapeMatcher:
|
|||||||
greediness: float = 0.0,
|
greediness: float = 0.0,
|
||||||
batch_top: bool = False,
|
batch_top: bool = False,
|
||||||
nms_iou_threshold: float = 0.3,
|
nms_iou_threshold: float = 0.3,
|
||||||
|
min_recall: float = 0.0,
|
||||||
) -> list[Match]:
|
) -> list[Match]:
|
||||||
"""
|
"""
|
||||||
scale_penalty: se > 0, riduce lo score per match a scala diversa da 1.0:
|
scale_penalty: se > 0, riduce lo score per match a scala diversa da 1.0:
|
||||||
@@ -1195,6 +1253,17 @@ class LineShapeMatcher:
|
|||||||
if float(score_f) < min_score:
|
if float(score_f) < min_score:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Feature recall (Halcon MinScore-style): conta quante feature
|
||||||
|
# template effettivamente combaciano nello spread scena alla
|
||||||
|
# pose finale. Scarta se sotto min_recall (default 0 = off).
|
||||||
|
# Util contro match parziali ad alto NCC ma poche feature reali.
|
||||||
|
if min_recall > 0.0:
|
||||||
|
recall = self._compute_recall(
|
||||||
|
spread0, var, cx_f, cy_f, ang_f,
|
||||||
|
)
|
||||||
|
if recall < min_recall:
|
||||||
|
continue
|
||||||
|
|
||||||
# Ri-traslo coord da spazio crop ROI a spazio scena originale.
|
# Ri-traslo coord da spazio crop ROI a spazio scena originale.
|
||||||
cx_out = cx_f + roi_offset[0]
|
cx_out = cx_f + roi_offset[0]
|
||||||
cy_out = cy_f + roi_offset[1]
|
cy_out = cy_f + roi_offset[1]
|
||||||
|
|||||||
Reference in New Issue
Block a user