Skip to content

PooriaT/GPX_helper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

200 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GPX Helper

Utilities for aligning GoPro (or other camera) video timestamps with GPX tracks. The primary tool, gpx_splitter.py, crops a GPX track to match a video clip so you can sync footage and GPS data for mapping or overlays. The repository also includes a Svelte + Vite frontend in frontend/ and a Python/FastAPI backend (managed with Poetry) in backend/.

Features

  • Extracts video start time and duration from EXIF metadata via exiftool.
  • Matches GPX track points closest to the video start/end times and writes a cropped GPX.
  • Falls back to file modification time when metadata is missing, with clear warnings.
  • Works with GPX files that include timezone-aware timestamps (UTC recommended).
  • Renders GPX tracks into MP4 map animations with OpenStreetMap tiles.
  • Renders batch GPX route animations into a ZIP when paired with video durations; batch renders are all-or-nothing, so a failed pair prevents ZIP creation.
  • Supports multi-clip trimming and telemetry overlay rendering (heart rate, speed, elevation).

Requirements

  • Python 3.13+
  • exiftool available in your PATH (for gpx_splitter.py)
  • Backend Python dependencies installed via Poetry (gpxpy, matplotlib, pillow, numpy, fastapi, etc.)
  • ffmpeg available in your PATH when exporting video
  • Node.js 20+ and npm (for the frontend)

Installation

Clone or download this repository. Install the system tools, then install project dependencies:

# Core dependency for gpx_splitter.py
brew install exiftool  # macOS
sudo apt-get update && sudo apt-get install -y libimage-exiftool-perl  # Ubuntu/Debian

# ffmpeg is required to write video output
brew install ffmpeg  # macOS
sudo apt-get install -y ffmpeg  # Ubuntu/Debian

# Backend dependencies
cd backend
poetry install

# Frontend dependencies
cd ../frontend
npm ci

Backend usage

Run the splitter by providing the video file and the GPX file. Optionally set an output path.

python3 backend/src/gpx_helper/gpx_splitter.py /path/to/video.MP4 /path/to/track.gpx \
  -o /path/to/track.cropped.gpx

If -o/--output is omitted, the script writes to <input>.cropped.gpx next to the original GPX file.

Local development

Run the backend and frontend together from the frontend directory:

cd frontend
npm run dev

This starts the FastAPI backend at http://localhost:8000 and the Vite frontend at http://localhost:4173. Poetry dependencies must already be installed in backend/, and npm dependencies must already be installed in frontend/.

If you only need the frontend server, run npm run dev:frontend from frontend/. If you only need the backend API, run npm run dev:backend from frontend/.

Backend API (foundation)

The backend includes a FastAPI service for GPX trimming, map animation, and telemetry video rendering. For normal local development, use npm run dev from frontend/ to start the API and frontend together. To run only the API, use:

cd frontend
npm run dev:backend

Example requests:

curl -X POST http://localhost:8000/api/v1/gpx/trim-by-time \
  -F gpx_file=@/path/to/track.gpx \
  -F start_time=2025-11-02T17:02:23Z \
  -F end_time=2025-11-02T17:07:00Z \
  --output trimmed.gpx
curl -X POST http://localhost:8000/api/v1/gpx/trim-by-video \
  -F gpx_file=@/path/to/track.gpx \
  -F start_time=2025-11-02T17:02:23Z \
  -F end_time=2025-11-02T17:07:00Z \
  -F duration_seconds=277 \
  --output trimmed.gpx
curl -X POST http://localhost:8000/api/v1/gpx/trim-by-videos \
  -F gpx_file=@/path/to/track.gpx \
  -F 'clips_json=[{"start_time":"2025-11-02T17:02:23Z","end_time":"2025-11-02T17:07:00Z","duration_seconds":277}]' \
  --output trimmed.zip
curl -X POST http://localhost:8000/api/v1/gpx/map-animate \
  -F gpx_file=@/path/to/track.gpx \
  -F duration_seconds=45 \
  -F resolution=1920x1080 \
  --output route.mp4

# Ask the backend for an ETA before rendering (JSON response)
curl -X POST http://localhost:8000/api/v1/gpx/map-animate/estimate \
  -F gpx_file=@/path/to/track.gpx \
  -F duration_seconds=45 \
  -F resolution=1920x1080
curl -X POST http://localhost:8000/api/v1/gpx/telemetry-video \
  -F gpx_file=@/path/to/track.gpx \
  -F duration_seconds=45 \
  -F resolution=1080x1080 \
  -F telemetry_type=heart_rate \
  -F background_color=transparent \
  --output telemetry.webm

# Transparent telemetry overlays use WebM with alpha. Use an opaque custom
# background_color such as #000000 when you want an MP4 export.

# Ask for telemetry render ETA (JSON response)
curl -X POST http://localhost:8000/api/v1/gpx/telemetry-video/estimate \
  -F gpx_file=@/path/to/track.gpx \
  -F duration_seconds=45 \
  -F resolution=1080x1080 \
  -F telemetry_type=heart_rate

Animate a GPX route on a map

map_animator.py turns a GPX track into an MP4 that draws the route over token-free built-in map layers, including OpenStreetMap and Satellite (Esri World Imagery). It converts coordinates to Web Mercator (EPSG:3857) so they align with the basemap and hides chart axes for a clean map view.

Usage:

python3 backend/src/gpx_helper/map_animator.py route.gpx 45 1920x1080 -o route.mp4
  • route.gpx: input GPX track
  • 45: duration in seconds
  • 1920x1080: output resolution (width x height)
  • -o route.mp4 (optional): output file name; defaults to output.mp4

The script fetches the selected built-in map tiles via folium and writes MP4 video with ffmpeg.

What gpx_splitter.py does

  1. Reads creation and duration metadata from the video (UTC) using exiftool.
  2. Parses the GPX track, finds the points closest to the video start and end times, and keeps only that segment.
  3. Writes the cropped GPX file to the requested location.

Example output

Video start (Local): 2025-11-02T17:02:23+00:00
Video end   (Local): 2025-11-02T17:07:00+00:00
Start time HH:MM:SS: 17:02:23
End time   HH:MM:SS: 17:07:00
Cropped GPX written to: /path/to/track.cropped.gpx

Adjusting timestamps for split GoPro videos

If GoPro splits a recording into multiple files and their timestamps need correction, update the metadata (UTC) with exiftool:

exiftool -overwrite_original -P -api QuickTimeUTC=0 \
  -CreateDate="2025:11:29 18:42:49" \
  -ModifyDate="2025:11:29 18:42:49" \
  -MediaCreateDate="2025:11:29 18:42:49" \
  -MediaModifyDate="2025:11:29 18:42:49" \
  -TrackCreateDate="2025:11:29 18:42:49" \
  -TrackModifyDate="2025:11:29 18:42:49" \
  GX020427.MP4

Troubleshooting

  • exiftool not found: Ensure it is installed and available in your PATH.
  • Missing or incomplete metadata: The script will fall back to the file's modification time and print a warning; verify your video metadata when accuracy matters.
  • No timestamps in GPX: The crop requires GPX points with valid <time> elements that include timezone information (e.g., a trailing Z for UTC).

Frontend landing page

The Svelte-based landing page lives in frontend/. To run it with the backend locally:

cd frontend
npm install
npm run dev

Then open the local Vite URL: http://localhost:4173.

Contributing

Feel free to open issues or submit pull requests with improvements or bug fixes. PRs are validated with the GitHub Actions workflow in .github/workflows/pr-structure-check.yml, which runs backend tests (poetry run python -m unittest discover -s tests) and frontend checks/tests/build (npm run check, npm test -- --run, npm run build).

License

This repository is available for use without limitations.

About

This repo includes some script for utalizing GPX for content creation.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors