Spaces:
Running
Running
Download tests/test_motion.py from blambert/movement-tracker: direct link, hf CLI and curl.
- Browser
- Download file 2.41 kB
-
https://huggingface.co/spaces/blambert/movement-tracker/resolve/main/tests/test_motion.py
- Command line
-
hf download hf://spaces/blambert/movement-tracker/tests/test_motion.py
-
curl -L -o test_motion.py https://huggingface.co/spaces/blambert/movement-tracker/resolve/main/tests/test_motion.py
2.41 kB
| import cv2 | |
| import numpy as np | |
| from movement_tracker.motion import MotionDetector, ScanDetector | |
| rng = np.random.default_rng(0) | |
| BG = rng.integers(60, 120, (720, 1280, 3), dtype=np.uint8) | |
| def noisy(frame: np.ndarray) -> np.ndarray: | |
| return np.clip(frame.astype(int) + rng.integers(-6, 7, frame.shape), 0, 255).astype( | |
| np.uint8 | |
| ) | |
| def warmed_up() -> MotionDetector: | |
| d = MotionDetector() | |
| for _ in range(40): | |
| d.detect(noisy(BG)) | |
| return d | |
| def test_static_scene_has_no_motion(): | |
| assert warmed_up().detect(noisy(BG)) is None | |
| def test_picks_largest_blob(): | |
| frame = BG.copy() | |
| frame[100:300, 900:1100] = 250 | |
| frame[500:560, 100:160] = 250 | |
| x, y = warmed_up().detect(noisy(frame)) | |
| assert abs(x - 1000) < 10 and abs(y - 200) < 10 | |
| def test_ignores_motion_during_warmup(): | |
| frame = BG.copy() | |
| frame[100:300, 900:1100] = 250 | |
| assert MotionDetector().detect(frame) is None | |
| def test_detects_object_slightly_darker_than_background(): | |
| # MOG2 shadow detection would discard this as a shadow | |
| bg = np.full((720, 1280, 3), 150, np.uint8) | |
| d = MotionDetector() | |
| for _ in range(30): | |
| d.detect(bg) | |
| frame = bg.copy() | |
| frame[200:500, 400:700] = 110 | |
| x, y = d.detect(frame) | |
| assert abs(x - 550) < 10 and abs(y - 350) < 10 | |
| def textured_world(width: int) -> np.ndarray: | |
| """A scene with enough texture for the scan detector to track features.""" | |
| rng = np.random.default_rng(1) | |
| world = rng.integers(0, 255, (720, width, 3), dtype=np.uint8) | |
| world = cv2.GaussianBlur(world, (0, 0), 6) | |
| return cv2.normalize(world, None, 30, 220, cv2.NORM_MINMAX) | |
| def pan(world: np.ndarray, frames: int, obj_x=None) -> list: | |
| """Detections while the camera pans right 6px per frame across the world.""" | |
| d, hits = ScanDetector(), [] | |
| for i in range(frames): | |
| w = world.copy() | |
| if obj_x is not None: | |
| x = obj_x(i) | |
| w[250:480, x : x + 90] = 240 | |
| hits.append(d.detect(w[:, i * 6 : i * 6 + 1280])) | |
| return hits | |
| def test_scan_ignores_camera_motion(): | |
| assert not any(pan(textured_world(1800), 60)) | |
| def test_scan_finds_moving_object(): | |
| # object walks right 8px/frame; in view coordinates its center is 545 + 2i | |
| hits = pan(textured_world(1800), 40, obj_x=lambda i: 500 + 8 * i) | |
| x, y = hits[-1] | |
| assert abs(x - (545 + 2 * 39)) < 60 and abs(y - 365) < 30 | |