BladeSzaSza's picture
fix: define REPO_NAME in hf_upload.sh (ensure_blade_space referenced it)
4948993 verified
Raw
History Blame Contribute Delete
7.47 kB
"""Tests for PoseVisualizer — no GPU, no model downloads."""
import numpy as np
import pytest
from formscout.types import IngestResult, Pose2DResult
def _make_ingest(n=5, h=480, w=640, fps=30.0):
frames = [np.zeros((h, w, 3), dtype=np.uint8) for _ in range(n)]
return IngestResult(frames=frames, fps=fps, duration=n / fps, n_people=1, width=w, height=h)
def _make_pose(n=5, w=640, h=480):
"""Synthetic Pose2DResult: 17 joints at fixed pixel positions, conf=0.9."""
kps_per_frame = []
for i in range(n):
frame_kps = {}
for j in range(17):
frame_kps[j] = {
"x": float(50 + j * 30 + i * 2),
"y": float(100 + j * 20),
"conf": 0.9,
}
kps_per_frame.append(frame_kps)
return Pose2DResult(keypoints=kps_per_frame, fps=30.0, confidence=0.9, notes="")
class TestComputeJointVelocity:
def test_returns_17_joints(self):
from formscout.agents.visualizer import compute_joint_velocity
pose = _make_pose(n=5)
result = compute_joint_velocity(pose.keypoints, fps=30.0)
assert len(result) == 17
def test_each_list_has_n_frames(self):
from formscout.agents.visualizer import compute_joint_velocity
pose = _make_pose(n=5)
result = compute_joint_velocity(pose.keypoints, fps=30.0)
for joint_idx, speeds in result.items():
assert len(speeds) == 5, f"joint {joint_idx} has {len(speeds)} speeds, expected 5"
def test_speeds_are_non_negative(self):
from formscout.agents.visualizer import compute_joint_velocity
pose = _make_pose(n=5)
result = compute_joint_velocity(pose.keypoints, fps=30.0)
for speeds in result.values():
assert all(s >= 0.0 for s in speeds)
def test_missing_keypoints_give_zero_speed(self):
from formscout.agents.visualizer import compute_joint_velocity
empty_kps = [{} for _ in range(5)]
result = compute_joint_velocity(empty_kps, fps=30.0)
for speeds in result.values():
assert all(s == 0.0 for s in speeds)
class TestDrawSkeleton:
def test_skeleton_draws_without_error(self):
from formscout.agents.visualizer import PoseVisualizer
vis = PoseVisualizer()
frame = np.zeros((480, 640, 3), dtype=np.uint8)
kps = {j: {"x": float(50 + j * 30), "y": float(100 + j * 20), "conf": 0.9}
for j in range(17)}
result = vis._draw_skeleton(frame.copy(), kps)
assert result.shape == frame.shape
assert not np.array_equal(result, frame)
def test_low_confidence_keypoints_not_drawn(self):
from formscout.agents.visualizer import PoseVisualizer
vis = PoseVisualizer()
frame = np.zeros((480, 640, 3), dtype=np.uint8)
kps = {j: {"x": float(50 + j * 30), "y": 100.0, "conf": 0.1} for j in range(17)}
result = vis._draw_skeleton(frame.copy(), kps)
assert np.array_equal(result, frame)
class TestDrawTrails:
def test_trails_draw_without_error(self):
from formscout.agents.visualizer import PoseVisualizer, TRAIL_LENGTH
from collections import deque
vis = PoseVisualizer()
frame = np.zeros((480, 640, 3), dtype=np.uint8)
trail_history = {
0: deque([(100 + i * 5, 200 + i * 3) for i in range(5)], maxlen=TRAIL_LENGTH)
}
result = vis._draw_trails(frame.copy(), trail_history)
assert result.shape == frame.shape
assert not np.array_equal(result, frame)
def test_short_trail_no_crash(self):
from formscout.agents.visualizer import PoseVisualizer, TRAIL_LENGTH
from collections import deque
vis = PoseVisualizer()
frame = np.zeros((480, 640, 3), dtype=np.uint8)
trail_history = {0: deque([(100, 200)], maxlen=TRAIL_LENGTH)}
result = vis._draw_trails(frame.copy(), trail_history)
assert np.array_equal(result, frame)
class TestDrawVelocityArrows:
def test_arrows_draw_without_error(self):
from formscout.agents.visualizer import PoseVisualizer
vis = PoseVisualizer()
frame = np.zeros((480, 640, 3), dtype=np.uint8)
kps = {j: {"x": float(50 + j * 30), "y": float(100 + j * 20), "conf": 0.9}
for j in range(17)}
prev_kps = {j: {"x": float(48 + j * 30), "y": float(98 + j * 20), "conf": 0.9}
for j in range(17)}
velocities = {j: [0.0] * 5 for j in range(17)}
velocities[5] = [0.0, 10.0, 50.0, 80.0, 120.0]
result = vis._draw_velocity_arrows(frame.copy(), kps, prev_kps, velocities, frame_idx=4)
assert result.shape == frame.shape
def test_no_prev_kps_no_crash(self):
from formscout.agents.visualizer import PoseVisualizer
vis = PoseVisualizer()
frame = np.zeros((480, 640, 3), dtype=np.uint8)
kps = {j: {"x": float(50 + j * 30), "y": 100.0, "conf": 0.9} for j in range(17)}
velocities = {j: [50.0] * 5 for j in range(17)}
result = vis._draw_velocity_arrows(frame.copy(), kps, None, velocities, frame_idx=0)
assert result.shape == frame.shape
class TestRenderVideo:
def test_creates_mp4_file(self, tmp_path):
from formscout.agents.visualizer import PoseVisualizer
vis = PoseVisualizer()
ingest = _make_ingest(n=5)
pose = _make_pose(n=5)
out = str(tmp_path / "out.mp4")
result = vis.render_video(ingest, pose, {"skeleton"}, out)
assert result is not None
import os
assert os.path.exists(result)
assert os.path.getsize(result) > 0
def test_empty_layers_returns_none(self, tmp_path):
from formscout.agents.visualizer import PoseVisualizer
vis = PoseVisualizer()
out = str(tmp_path / "out.mp4")
result = vis.render_video(_make_ingest(), _make_pose(), set(), out)
assert result is None
def test_no_detections_returns_none(self, tmp_path):
from formscout.agents.visualizer import PoseVisualizer
vis = PoseVisualizer()
ingest = _make_ingest(n=5)
empty_pose = Pose2DResult(
keypoints=[{} for _ in range(5)], fps=30.0, confidence=0.0, notes=""
)
out = str(tmp_path / "out.mp4")
result = vis.render_video(ingest, empty_pose, {"skeleton"}, out)
assert result is None
def test_last_velocities_set_after_render(self, tmp_path):
from formscout.agents.visualizer import PoseVisualizer
vis = PoseVisualizer()
out = str(tmp_path / "out.mp4")
vis.render_video(_make_ingest(n=5), _make_pose(n=5), {"skeleton"}, out)
assert len(vis.last_velocities) == 17
class TestBuildVelocitySummary:
def test_returns_markdown_table(self):
from formscout.agents.visualizer import build_velocity_summary, compute_joint_velocity
pose = _make_pose(n=10)
vels = compute_joint_velocity(pose.keypoints, fps=30.0)
result = build_velocity_summary(pose.keypoints, vels)
assert "|" in result
assert any(name in result for name in ["knee", "shoulder", "hip", "ankle"])
def test_empty_keypoints_returns_empty_string(self):
from formscout.agents.visualizer import build_velocity_summary
empty_kps = [{} for _ in range(5)]
vels = {j: [0.0] * 5 for j in range(17)}
result = build_velocity_summary(empty_kps, vels)
assert result == ""