fixed display problem

This commit is contained in:
ykcheungab
2026-09-25 17:53:07 +08:00
parent 12781854ca
commit 3daee6d407
7 changed files with 367 additions and 5 deletions
+169
View File
@@ -191,3 +191,172 @@ def test_a_missing_field_is_reported_not_invented():
base = backend.render_image(no_flow, mode="arrows_pure")
assert base is not None
assert np.array_equal(base, _image()), "the base picture must not be redrawn"
# ------------------------------------------------------- the latched boundary
#: A domain the same size and the same kind of shape as the shipped finger sensor's
#: 300x280 UV island: one large blob with a long smooth rim, so "a one-pixel wobble"
#: and "the island moved" have the overlap the real package has (measured on the
#: shipped island: a 1 px wobble scores IoU 0.9633, a 6 px move 0.9102).
DOMAIN_HW = (300, 280)
ISLAND_RADIUS_PX = 95
def _island(h: int = DOMAIN_HW[0], w: int = DOMAIN_HW[1]) -> np.ndarray:
yy, xx = np.mgrid[0:h, 0:w]
return ((yy - h / 2.0) ** 2 + (xx - w / 2.0) ** 2) <= float(ISLAND_RADIUS_PX) ** 2
def _blank_image(h: int = DOMAIN_HW[0], w: int = DOMAIN_HW[1]) -> np.ndarray:
"""A base picture the two views do not read: only depth and the mask are drawn."""
return np.zeros((h, w, 3), dtype=np.uint8)
def _shift(mask: np.ndarray, dy: int, dx: int) -> np.ndarray:
out = np.zeros_like(mask)
h, w = mask.shape
ys = slice(max(0, dy), h + min(0, dy))
xs = slice(max(0, dx), w + min(0, dx))
ys2 = slice(max(0, -dy), h + min(0, -dy))
xs2 = slice(max(0, -dx), w + min(0, -dx))
out[ys, xs] = mask[ys2, xs2]
return out
def test_overlap_of_two_identical_masks_is_one():
mask = _island()
assert backend.mask_overlap(mask, mask) == 1.0
assert backend.mask_overlap(mask, ~mask) == 0.0
# Two frames that agree there is no island at all are not a change.
empty = np.zeros((4, 4), dtype=bool)
assert backend.mask_overlap(empty, empty) == 1.0
def test_the_gate_separates_a_rebuilt_mask_from_a_moved_one():
"""The threshold itself, on the two cases it exists to tell apart."""
island = _island()
for dy, dx in ((1, 0), (0, 1), (1, 1), (-1, 1), (2, 0)):
assert backend.mask_overlap(island, _shift(island, dy, dx)) >= (
backend.DOMAIN_MASK_MIN_IOU
), f"a {dy},{dx} rebuild would be taken for a moved boundary"
assert backend.mask_overlap(island, _shift(island, 6, 0)) < backend.DOMAIN_MASK_MIN_IOU
def test_a_stable_domain_mask_is_latched_once_for_the_session():
"""The device's island is geometry: rebuilt per frame, decided once."""
latch = backend.DomainMaskLatch()
mask = _island()
seen = {latch.update(mask).tobytes() for _ in range(20)}
assert len(seen) == 1, "a stable mask was rebuilt into a different array"
assert np.array_equal(latch.mask, mask)
assert (latch.adoptions, latch.held) == (1, 19)
def test_a_wobbling_domain_mask_does_not_repaint_the_boundary():
"""A one-pixel rim wobble is the mask being rebuilt, not the island moving.
The measured case: on the shipped finger island this is a 0.73% area flip that
repaints 69% of the boundary band and 35% of the rendered edge pixels.
"""
latch = backend.DomainMaskLatch()
image = _blank_image()
# A zero field, so nothing but the boundary can change the picture.
flow = np.zeros((*DOMAIN_HW, 2), dtype=np.float32)
depth = np.ones(DOMAIN_HW, dtype=np.float32)
wobbles = [(0, 0), (1, 0), (0, -1), (1, 1), (-1, 0), (0, 1), (-1, -1)]
arrows, maps = [], []
for dy, dx in wobbles:
mask = _shift(_island(), dy, dx)
frame = backend.ImageFrame(image, flow=flow, depth=depth, valid_mask=mask)
used = latch.update(mask)
arrows.append(
backend.render_image(
frame, mode="arrows_pure", draw_style="finger", domain_mask=used
)
)
maps.append(
backend.render_image(
frame, mode="depth", depth_range=(0.0, 1.0), domain_mask=used
)
)
assert all(np.array_equal(arrows[0], other) for other in arrows), (
"the arrow canvas repainted a boundary that had not moved"
)
assert all(np.array_equal(maps[0], other) for other in maps), (
"the depth view's no-data boundary repainted a boundary that had not moved"
)
assert latch.adoptions == 1, "a rim wobble was taken for a moved boundary"
def test_a_real_move_of_the_domain_is_followed():
"""The latch must not freeze a boundary that actually moved."""
latch = backend.DomainMaskLatch()
island = _island()
latch.update(island)
moved = _shift(island, 6, 0)
used = latch.update(moved)
assert np.array_equal(used, moved), "a moved island kept the old boundary"
assert latch.adoptions == 2
frame = backend.ImageFrame(
_blank_image(), flow=np.zeros((*DOMAIN_HW, 2), np.float32)
)
before = backend.render_image(
frame, mode="arrows_pure", draw_style="finger", domain_mask=island
)
after = backend.render_image(
frame, mode="arrows_pure", draw_style="finger", domain_mask=used
)
assert not np.array_equal(before, after)
def test_a_frame_without_a_mask_cannot_move_the_boundary():
latch = backend.DomainMaskLatch()
assert latch.update(None) is None, "a session with no mask invented one"
island = _island()
latch.update(island)
assert np.array_equal(latch.update(None), island), (
"a frame that states no mask dropped the session's boundary"
)
assert (latch.adoptions, latch.held) == (1, 0)
def test_the_latched_boundary_never_gates_the_arrows():
"""Latching the boundary must not put an arrow on an unvouched-for sample."""
image = _blank_image()
flow = np.zeros((*DOMAIN_HW, 2), dtype=np.float32)
flow[::10, ::10, 0] = 3.0
# The frame claims nothing; the session's boundary is the whole domain.
frame = backend.ImageFrame(image, flow=flow, valid_mask=np.zeros(DOMAIN_HW, bool))
boundary = np.ones(DOMAIN_HW, dtype=bool)
got = backend.render_image(
frame, mode="arrows_pure", draw_style="finger", domain_mask=boundary
)
expected = draw_arrow_display(
image,
flow,
background="pure_color",
draw_style="finger",
valid_mask=frame.valid_mask,
domain_mask=boundary,
colormap=flow_colormap("dark"),
)
assert np.array_equal(got, expected)
# A whole-domain boundary paints one tone; an empty frame mask means no arrows,
# so the picture stays that one tone rather than gaining arrow pixels.
tones = {tuple(int(v) for v in tone) for tone in np.unique(got.reshape(-1, 3), axis=0)}
assert tones == {(0x16, 0x13, 0x12)}, (
f"arrows were drawn from a mask the frame does not claim: {tones}"
)
def test_resetting_the_latch_clears_the_session_boundary():
latch = backend.DomainMaskLatch()
latch.update(_island())
latch.reset()
assert latch.mask is None
assert (latch.adoptions, latch.held) == (0, 0)
other = _shift(_island(), 5, 5)
assert np.array_equal(latch.update(other), other), (
"a new session kept the previous session's island"
)