This project builds film colour visualisations from extracted frames, then composes print-style posters using a circular colour fingerprint plus TMDB-enriched metadata.
For each film folder, the pipeline can generate:
vertical_classic.pngvertical_cinematic.pnglinear_hq.pngradial_hq.pngcircle_full.pngcircle_donut_poster.png(only ifcircle_data/<film>/strip_*.pngexists)shot_palette_strip.pngshot_palettes.jsoncircle_full_ozonelab_light.pngcircle_full_ozonelab_dark.pngdotstrip_light.pngdotstrip_dark.png
colours_of_motion_processing.py- interactive source processing (frame extraction + metadata / strip extraction)
colours_of_motion_processing_experimental.py- experimental 1 fps processing that writes to
_experimentalfolders
- experimental 1 fps processing that writes to
colours_of_motion_radial.py- builds
linear_hq.pngandradial_hq.png
- builds
colours_of_motion_vertical.py- builds
vertical_classic.pngandvertical_cinematic.png
- builds
colours_of_motion_circle.py- builds
circle_full.pngfromframes/<film>/data.json
- builds
colours_of_motion_donut.py- builds
circle_donut_poster.pngfromcircle_data/<film>/strip_*.png
- builds
colours_of_motion_shots.py- detects shot boundaries and writes
shot_palettes.jsonplusshot_palette_strip.png
- detects shot boundaries and writes
ozonelab_style.py- builds final light/dark posters with TMDB-backed metadata and encoded dot strips
com-py/
├── frames/<film>/ # frame_*.jpg + data.json
├── circle_data/<film>/ # strip_*.png for donut generation
├── outputs/<film>/ # all rendered assets
├── metadata/poster_metadata.json # shared metadata catalog for all films
├── logs/tmdb_run_*.jsonl # per-run TMDB request/response logs
├── .env # local secrets (ignored)
└── *.py # generation scripts
python3 -m venv .venv
source .venv/bin/activate
pip install pillow numpy opencv-pythonInstall ffmpeg (required for extraction scripts):
brew install ffmpegCreate .env:
TMDB_API_KEY=
TMDB_READ_ACCESS_TOKEN=your_tmdb_read_access_tokenEither TMDB_API_KEY (v3 key) or TMDB_READ_ACCESS_TOKEN (v4 bearer token) is supported.
Run the generation scripts (interactive):
.venv/bin/python colours_of_motion_processing.py
.venv/bin/python colours_of_motion_vertical.py --poster_mode
.venv/bin/python colours_of_motion_radial.py --poster_mode
.venv/bin/python colours_of_motion_circle.py --poster_mode
.venv/bin/python colours_of_motion_donut.py --poster_mode.venv/bin/python ozonelab_style.py --input "outputs/Aliens (1986) - tt0090605/circle_full.png" --refresh-metadata --metadata-only.venv/bin/python ozonelab_style.py --input "outputs/Aliens (1986) - tt0090605/circle_full.png" --theme both.venv/bin/python colours_of_motion_shots.py --folder "Aliens (1986) - tt0090605"This writes to suffixed folders such as frames/<film>_experimental so the main dataset stays untouched.
.venv/bin/python colours_of_motion_processing_experimental.pyStored in metadata/poster_metadata.json as a shared catalog:
{
"films": {
"tt0090605": {
"source": "tmdb|local",
"schema_version": 2,
"tmdb_id": 679,
"imdb_id": "tt0090605",
"title": "Aliens",
"year": 1986,
"release_date": "1986-08-29T00:00:00.000Z",
"runtime_min": 137,
"aspect_ratio": "2.20:1",
"production_category": "MOTION PICTURE",
"project_resolution": "FILM PROJECT",
"color_profile": "COLOUR",
"tagline": "This time it's war.",
"overview": "....",
"headline": "This time it's war.",
"summary": "...."
}
}
}Notes:
taglineandovervieware explicit TMDB fields.headlineandsummaryare the render fields used in posters.- Release date is formatted UK-style in output (
DD.MM.YYYY). - Refresh failures preserve existing metadata (no destructive fallback overwrite).
ozonelab_style.py replaces the previous decorative dots with an encoded two-row dot strip:
A = frames_processed(actual frames used)B = runtime_seconds(runtime_min * 60, or0if runtime missing)
Bit rendering:
1-> top row dot0-> bottom row dot- MSB -> LSB, left to right
- stream format:
[lenA:8][A bits] | [lenB:8][B bits]|is a wider horizontal gap
Theme assets:
dotstrip_light.png(black dots on transparent)dotstrip_dark.png(white dots on transparent)
Every run writes a per-run log:
logs/tmdb_run_<timestamp>.jsonl
Log entries include:
- request path + params (sanitized)
- auth mode (
api_keyorbearer) - full response payload on success
- structured HTTP / network errors
nodename nor servname provided, or not known- DNS/network resolution issue to
api.themoviedb.org, not a rate-limit error.
- DNS/network resolution issue to
- Missing runtime/release/tagline/summary in metadata
- run
--refresh-metadata --metadata-onlyin a terminal with internet access.
- run
Concept inspired by The Colours of Motion. Poster style reference inspired by TheOzoneLab.
%20-%20tt0090605/circle_full_ozonelab_light.png)
%20-%20tt0090605/circle_full_ozonelab_dark.png)
%20-%20tt0090605/linear_hq.png)
%20-%20tt0090605/radial_hq.png)
%20-%20tt0090605/circle_full.png)
%20-%20tt0090605/vertical_cinematic.png)