from __future__ import annotations import importlib.util import json import math import sys from pathlib import Path from types import ModuleType import numpy as np import pytest def _worker_module() -> ModuleType: worker_root = Path(__file__).parents[1] / "experiments" / "perception" / "worker" path = worker_root / "run_e5_instance_tracking.py" sys.path.insert(0, str(worker_root)) try: spec = importlib.util.spec_from_file_location("e5_instance_tracking_worker", path) assert spec is not None and spec.loader is not None module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) return module finally: sys.path.pop(0) def _profile_path() -> Path: return ( Path(__file__).parents[1] / "experiments" / "perception" / "worker" / "e5_yolox_bytetrack_profile.json" ) def _detection(*, score: float, x: float = 100, class_id: int = 0) -> dict[str, object]: return { "class_id": class_id, "label": "person" if class_id == 0 else "car", "score": score, "bbox_xyxy": [x, 100.0, x + 60.0, 220.0], "valid_fov_fraction": 1.0, } def test_profile_is_pinned_and_semantically_valid() -> None: worker = _worker_module() profile, digest = worker._read_profile(_profile_path()) assert len(digest) == 64 assert profile["model"]["id"] == "yolox_s" assert profile["model"]["model_sha256"] == ( "c5c2d13e59ae883e6af3b45daea64af4833a4951c92d116ec270d9ddbe998063" ) assert profile["tracking"]["algorithm"] == "bytetrack-style-two-stage-iou/v1" assert profile["detection"]["target_class_ids"] == [0, 1, 2, 3, 5, 7] def test_profile_rejects_duplicate_target_classes(tmp_path: Path) -> None: worker = _worker_module() profile = json.loads(_profile_path().read_text(encoding="utf-8")) profile["detection"]["target_class_ids"] = [0, 0] path = tmp_path / "profile.json" path.write_text(json.dumps(profile), encoding="utf-8") with pytest.raises(RuntimeError, match="target class"): worker._read_profile(path) def test_valid_fraction_uses_box_area_and_center_gate() -> None: worker = _worker_module() mask = np.zeros((10, 10), dtype=bool) mask[2:8, 2:8] = True integral = np.pad(mask.astype(np.int64), ((1, 0), (1, 0))).cumsum(0).cumsum(1) fraction, center_inside, area = worker._valid_fraction( np.asarray([1.0, 1.0, 5.0, 5.0]), integral ) assert area == 16 assert fraction == pytest.approx(9 / 16) assert center_inside is True def test_yolox_decode_and_fov_filter_admit_one_person() -> None: worker = _worker_module() profile = json.loads(_profile_path().read_text(encoding="utf-8")) output = np.zeros((1, 8400, 85), dtype=np.float32) output[0, 0, :4] = [40.0, 30.0, math.log(10.0), math.log(10.0)] output[0, 0, 4] = 0.9 output[0, 0, 5] = 0.9 detections, rejected = worker._detections( output, profile, np.ones((600, 800), dtype=bool), ) assert rejected == {} assert len(detections) == 1 assert detections[0]["label"] == "person" assert detections[0]["score"] == pytest.approx(0.81) assert detections[0]["bbox_xyxy"] == pytest.approx([350.0, 250.0, 450.0, 350.0]) def test_nms_suppresses_lower_score_box_contained_inside_object() -> None: worker = _worker_module() boxes = np.asarray( [ [0.0, 0.0, 100.0, 100.0], [10.0, 10.0, 60.0, 60.0], ] ) scores = np.asarray([0.9, 0.5]) assert worker._nms(boxes, scores, 0.45, 0.8) == [0] def test_two_stage_tracker_keeps_id_through_low_score_detection() -> None: worker = _worker_module() profile = json.loads(_profile_path().read_text(encoding="utf-8")) tracker = worker.TwoStageTracker(profile["tracking"]) assert tracker.update([_detection(score=0.8)], 0) == [] second = tracker.update([_detection(score=0.7, x=103)], 1) third = tracker.update([_detection(score=0.15, x=106)], 2) assert [track.track_id for track in second] == [1] assert [track.track_id for track in third] == [1] assert third[0].hits == 3 assert tracker.created == 1 def test_tracker_does_not_cross_match_classes() -> None: worker = _worker_module() profile = json.loads(_profile_path().read_text(encoding="utf-8")) tracker = worker.TwoStageTracker(profile["tracking"]) tracker.update([_detection(score=0.8)], 0) tracks = tracker.update([_detection(score=0.8, class_id=2)], 1) assert tracks == [] assert tracker.created == 2 assert {track.class_id for track in tracker.tracks} == {0, 2} def test_clip_timeline_may_start_at_nonzero_source_index(tmp_path: Path) -> None: worker = _worker_module() path = tmp_path / "timeline.jsonl" rows = [ {"frame_index": 0, "source_frame_index": 1000, "session_seconds": 135.1}, {"frame_index": 1, "source_frame_index": 1001, "session_seconds": 135.2}, ] path.write_text("\n".join(json.dumps(row) for row in rows) + "\n", encoding="utf-8") assert worker._read_timeline(path, 2) == rows