fix(vision): erode mask pre-CC to sever anti-aliasing bridges

With tol=25 all dots in the strip fused into one blob via 1px anti-aliased
bridges between adjacent dots → centroid landed mid-strip instead of on the
rightmost dot. Erosion (3x3 kernel, 2 iters) cleanly separates discrete
dots before connected-components labelling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-04-16 07:12:57 +00:00
parent 74b5d33c86
commit 4dac21b7c0

View File

@@ -103,9 +103,11 @@ def find_rightmost_dot(
diff = np.linalg.norm(roi_img.astype(np.float32) - bgr_bg, axis=2)
mask = (diff > bg_tol).astype(np.uint8)
# Connected components → one component per dot. Anti-aliasing bridges
# between adjacent dots are small enough that 8-connectivity still
# separates them cleanly.
# Anti-aliasing bridges between adjacent dots can fuse the entire strip
# into one blob under 8-connectivity. Erode by 2px to sever those bridges
# before labelling — dots shrink but remain well above min_cluster_px.
kernel = np.ones((3, 3), dtype=np.uint8)
mask = cv2.erode(mask, kernel, iterations=2)
n_labels, _labels, stats, centroids = cv2.connectedComponentsWithStats(
mask, connectivity=8,
)