Fast 3D trajectory video renderer using NumPy + OpenCV
Project description
trajviz
Fast 3D camera trajectory video renderer using NumPy + OpenCV.
Renders animated top-down trajectory visualizations from 3D camera positions, with configurable ghost trails, color-coded markers, glow effects, and camera frustum overlays. Frames are piped directly to ffmpeg as raw RGB — no intermediate files.
Spiral trajectory with wedge frustum overlay. Colors encode time progression: blue at the start, magenta at the end. Generated by
scripts/generate_demo.py.
Colors are user-provided as RGBA per position (n, 4), so they can encode anything. The renderer draws each segment with its assigned color and smoothly advances through the trajectory.
Coloring strategies
Time gradient — show trajectory progression:
t = np.linspace(0, 1, n, dtype=np.float32)
colors = np.stack([t, np.zeros(n), 1 - t, np.ones(n)], axis=1, dtype=np.float32)
Floor / zone coloring — assign colors by vertical position:
colors = np.zeros((n, 4), dtype=np.float32)
colors[:, 3] = 1.0 # full opacity
for i, z in enumerate(positions[:, 2]):
if z < 3.0:
colors[i, :3] = [0.2, 0.5, 0.9] # blue = ground floor
elif z < 6.0:
colors[i, :3] = [0.9, 0.5, 0.1] # orange = first floor
else:
colors[i, :3] = [0.1, 0.8, 0.4] # green = second floor
Speed-based — highlight fast vs slow movement:
deltas = np.linalg.norm(np.diff(positions, axis=0), axis=1)
speed = np.concatenate([[deltas[0]], deltas])
speed_norm = (speed - speed.min()) / (speed.max() - speed.min() + 1e-8)
colors = plt.get_cmap("coolwarm")(speed_norm).astype(np.float32)
Uniform — single color for the entire trajectory:
colors = np.tile([0.2, 0.8, 0.4, 1.0], (n, 1)).astype(np.float32)
Installation
pip install git+https://github.com/affromero/trajviz.git
Usage
import numpy as np
from trajviz import render_trajectory_video, TrajectoryRenderConfig
# Random 3D trajectory
positions = np.random.randn(120, 3).astype(np.float32)
positions = np.cumsum(positions * 0.1, axis=0)
# RGBA colors per frame (e.g., gradient from blue to red)
t = np.linspace(0, 1, 120)
colors = np.stack([t, np.zeros(120), 1 - t, np.ones(120)], axis=1).astype(np.float32)
render_trajectory_video(
positions=positions,
colors_rgba=colors,
output_path="trajectory.mp4",
)
Configuration
All rendering options are controlled via TrajectoryRenderConfig:
from trajviz import TrajectoryRenderConfig, FrustumStyle
config = TrajectoryRenderConfig(
width=1080,
height=1080,
elevation_deg=45.0,
frustum_style=FrustumStyle.WEDGE,
fps=30,
)
render_trajectory_video(positions, colors, "out.mp4", config=config)
Side-by-side comparison
Combine a recording with its trajectory overlay:
from trajviz import combine_videos_side_by_side
combine_videos_side_by_side(
left_path="recording.mp4",
right_path="trajectory.mp4",
output_path="combined.mp4",
fps=30,
)
Development
pip install -e ".[dev]"
pre-commit install
# Run tests
pytest tests/ -v
# Run linting
pre-commit run --all-files
Requirements
- Python >= 3.10
- ffmpeg on PATH
- numpy, opencv-python-headless, pydantic, jaxtyping, beartype, difflogtest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file trajviz-0.0.1.tar.gz.
File metadata
- Download URL: trajviz-0.0.1.tar.gz
- Upload date:
- Size: 475.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e16e184ab8170ace9befba3167ac79f04c8c1724ff44b90ab051a333a746a031
|
|
| MD5 |
c8ba8cce65d89e8f4ba9381ff59e960a
|
|
| BLAKE2b-256 |
31b330b7cc00cde0b9e5c6a729ca8fbb2b98333bf0f54a1cdd82ae36207186c6
|
Provenance
The following attestation bundles were made for trajviz-0.0.1.tar.gz:
Publisher:
publish.yml on affromero/trajviz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trajviz-0.0.1.tar.gz -
Subject digest:
e16e184ab8170ace9befba3167ac79f04c8c1724ff44b90ab051a333a746a031 - Sigstore transparency entry: 943897686
- Sigstore integration time:
-
Permalink:
affromero/trajviz@44981d65ac856b4a751f8beafcdf12c22ee3e742 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/affromero
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@44981d65ac856b4a751f8beafcdf12c22ee3e742 -
Trigger Event:
push
-
Statement type:
File details
Details for the file trajviz-0.0.1-py3-none-any.whl.
File metadata
- Download URL: trajviz-0.0.1-py3-none-any.whl
- Upload date:
- Size: 11.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
94736882a8bd252f72f0304eec50b4230f8dd43b4b0021d2150e48915e4d0744
|
|
| MD5 |
09abed4792f763fd86d74c247db1a0d0
|
|
| BLAKE2b-256 |
359384212cbf5468b90a39695d716dc3c682491295766c0992efb1d146ff0299
|
Provenance
The following attestation bundles were made for trajviz-0.0.1-py3-none-any.whl:
Publisher:
publish.yml on affromero/trajviz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
trajviz-0.0.1-py3-none-any.whl -
Subject digest:
94736882a8bd252f72f0304eec50b4230f8dd43b4b0021d2150e48915e4d0744 - Sigstore transparency entry: 943897689
- Sigstore integration time:
-
Permalink:
affromero/trajviz@44981d65ac856b4a751f8beafcdf12c22ee3e742 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/affromero
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@44981d65ac856b4a751f8beafcdf12c22ee3e742 -
Trigger Event:
push
-
Statement type: