You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
3.9 KiB
Python
151 lines
3.9 KiB
Python
from pathlib import Path
|
|
import sys
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
if str(PROJECT_ROOT) not in sys.path:
|
|
sys.path.insert(0, str(PROJECT_ROOT))
|
|
|
|
from target_handoff import (
|
|
HandoffDecision,
|
|
compute_fast_handoff_hits,
|
|
evaluate_stale_lock,
|
|
pick_guidance_override_box,
|
|
should_override_guidance,
|
|
update_guidance_override_latch,
|
|
)
|
|
|
|
|
|
def test_evaluate_stale_lock_requires_fresh_candidate_and_weak_anchor():
|
|
decision = evaluate_stale_lock(
|
|
confirmed=True,
|
|
have_fresh_candidate=True,
|
|
target_has_fresh_update=False,
|
|
candidate_dist_px=420.0,
|
|
pred_diag_px=70.0,
|
|
miss_streak=8,
|
|
klt_valid=False,
|
|
klt_quality=0.18,
|
|
klt_iou=0.12,
|
|
candidate_motion_ok=True,
|
|
target_motion_ok=False,
|
|
stale_break_dist_diag=3.5,
|
|
stale_break_min_miss=2,
|
|
stale_break_klt_quality=0.35,
|
|
stale_break_klt_iou=0.25,
|
|
)
|
|
|
|
assert decision.stale_lock_active is True
|
|
assert "target_not_fresh" in decision.reasons
|
|
assert "weak_klt_quality" in decision.reasons
|
|
|
|
|
|
def test_evaluate_stale_lock_rejects_close_candidate_when_anchor_is_healthy():
|
|
decision = evaluate_stale_lock(
|
|
confirmed=True,
|
|
have_fresh_candidate=True,
|
|
target_has_fresh_update=True,
|
|
candidate_dist_px=90.0,
|
|
pred_diag_px=70.0,
|
|
miss_streak=0,
|
|
klt_valid=True,
|
|
klt_quality=0.92,
|
|
klt_iou=0.71,
|
|
candidate_motion_ok=True,
|
|
target_motion_ok=True,
|
|
stale_break_dist_diag=3.5,
|
|
stale_break_min_miss=2,
|
|
stale_break_klt_quality=0.35,
|
|
stale_break_klt_iou=0.25,
|
|
)
|
|
|
|
assert decision.stale_lock_active is False
|
|
assert decision.reasons == []
|
|
|
|
|
|
def test_compute_fast_handoff_hits_reduces_confirmation_under_stale_lock():
|
|
hits = compute_fast_handoff_hits(
|
|
stale_lock_active=True,
|
|
motion_switch_mode=False,
|
|
approach_extra_hits=2,
|
|
fast_maneuver_extra_hits=2,
|
|
default_switch_hits=4,
|
|
fast_handoff_hits=2,
|
|
motion_switch_hits=6,
|
|
)
|
|
|
|
assert hits == 2
|
|
|
|
|
|
def test_handoff_decision_repr_is_stable_for_logging():
|
|
decision = HandoffDecision(
|
|
stale_lock_active=True,
|
|
allow_fast_handoff=True,
|
|
required_switch_hits=2,
|
|
disable_prediction_hold=True,
|
|
reasons=["target_not_fresh", "weak_klt_quality"],
|
|
)
|
|
|
|
assert decision.reason_text() == "target_not_fresh|weak_klt_quality"
|
|
|
|
|
|
def test_should_override_guidance_when_target_is_missing_but_fresh_candidate_exists():
|
|
assert should_override_guidance(
|
|
confirmed=True,
|
|
target_track_missing=True,
|
|
have_fresh_candidate=True,
|
|
candidate_matches_target=False,
|
|
miss_streak=10,
|
|
override_miss_ge=2,
|
|
)
|
|
|
|
|
|
def test_should_not_override_guidance_before_miss_threshold():
|
|
assert not should_override_guidance(
|
|
confirmed=True,
|
|
target_track_missing=True,
|
|
have_fresh_candidate=True,
|
|
candidate_matches_target=False,
|
|
miss_streak=1,
|
|
override_miss_ge=2,
|
|
)
|
|
|
|
|
|
def test_pick_guidance_override_box_falls_back_to_raw_yolo_box():
|
|
yolo_box = [100.0, 120.0, 180.0, 200.0]
|
|
|
|
picked = pick_guidance_override_box(
|
|
track_candidate_box=None,
|
|
raw_yolo_box=yolo_box,
|
|
)
|
|
|
|
assert picked == yolo_box
|
|
|
|
|
|
def test_update_guidance_override_latch_keeps_recent_box_when_new_candidate_is_missing():
|
|
prev_box = [100.0, 120.0, 180.0, 200.0]
|
|
|
|
latched_box, ttl = update_guidance_override_latch(
|
|
new_box=None,
|
|
prev_box=prev_box,
|
|
prev_ttl=2,
|
|
max_ttl=2,
|
|
)
|
|
|
|
assert latched_box == prev_box
|
|
assert ttl == 1
|
|
|
|
|
|
def test_update_guidance_override_latch_replaces_memory_when_new_candidate_arrives():
|
|
new_box = [300.0, 320.0, 380.0, 400.0]
|
|
|
|
latched_box, ttl = update_guidance_override_latch(
|
|
new_box=new_box,
|
|
prev_box=None,
|
|
prev_ttl=0,
|
|
max_ttl=2,
|
|
)
|
|
|
|
assert latched_box == new_box
|
|
assert ttl == 2
|