Mark every below-threshold finger sample with an idle dot

The selector now returns candidate locations with an activity flag, so the quiet half of
the finger's sampling grid can be drawn at last: one radius-1 dot per candidate, in the
idle tint and off the flow ramp, on no sample that also carries an arrow. The dots are
`DRAW_IDLE_GRID_DOTS` (on) and `draw_arrow_display(idle_dots=...)`; box and mini keep
their own SDK path.
This commit is contained in:
ykcheungab
2026-10-04 11:09:19 +08:00
parent ca28d788c2
commit aa526c62a9
4 changed files with 548 additions and 32 deletions
@@ -233,11 +233,17 @@ def _patch_flow(mask: np.ndarray, dx: float, dy: float):
def _drawn_displacement(image: np.ndarray, origin: tuple[int, int]) -> tuple[float, float]:
"""The drawn arrow's displacement, in display pixels, from its own origin.
The origin is where the canvas would have put the sample; every non-background
pixel belongs to the one arrow drawn, and their centroid sits along it. The sign
is the whole assertion, but the magnitude is returned so a failure is readable.
The origin is where the canvas would have put the sample. The canvas is black apart
from what it drew, so the arrow's pixels are the non-background ones **minus the idle
markers**: every candidate below the threshold is marked with an idle dot, and
counting those would measure the marker grid instead of the arrow. The sign is the
whole assertion, but the magnitude is returned so a failure is readable.
"""
pixels = np.argwhere(np.any(image != 0, axis=2))
from orisys_app_shared.acquisition.arrows import FLOW_IDLE_HEX, hex_to_bgr
idle_tint = np.asarray(hex_to_bgr(FLOW_IDLE_HEX), dtype=np.uint8)
drawn = np.any(image != 0, axis=2) & ~np.all(image == idle_tint, axis=2)
pixels = np.argwhere(drawn)
assert pixels.size, "the canvas drew no arrow at all"
centre = pixels.mean(axis=0)
return float(centre[1] - origin[1]), float(centre[0] - origin[0])