The tool now serves any show — both filling TCM gaps (the original One Pace case) and replacing TMDb stills whose subject collides with the title text. Rename the script to titlecard_stills.py, update the Dockerfile entrypoint, and re-frame the README around the general use case while keeping the One Pace origin story. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| examples | ||
| .gitignore | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
| titlecard_stills.py | ||
title-card-stills-finder
Mine the best candidate title-card stills straight from your video files — for any show where TitleCardMaker (TCM) has no source image, or where the auto-pulled TMDb still has the subject sitting right where your title text prints.
It samples frames from each .mkv, scores them for sharpness, exposure, and composition
(either "action on the right 2/3, clear left" or a clear title band you define),
throws away the duplicates and the junk, and hands you the best few per episode plus a
labeled contact sheet to pick from.
Why this exists
TitleCardMaker builds episode cards from a source image per episode. For normal shows it pulls those from TMDb or Plex. Two cases break that:
- Fan re-cuts like One Pace (a re-edit of One Piece on its own season/episode layout) — TMDb has stills for almost none of it, so every episode comes up blank. This was the original motivation, and the tool's name still nods to it.
- Real shows with the wrong composition — TMDb has a still, but the actor's face is dead-centre where your card design prints the title, so the text lands across their nose.
Either way, this tool pulls a better source image out of the episode itself — the same way you'd pause and screenshot a good frame, but automated and with some taste applied.
What it does
- Finds the gaps. Walks your show library, parses
SxxEyyfrom each filename, and compares against thesXeY.jpgfiles already in your TCMsource/dir(s). What's missing is the work list (or pass--allto re-evaluate every episode). - Samples frames. Fast-seeks one full-res frame every ~12s (keyframe-snapped, so it's quick — not a full re-decode), skipping the intro and end credits.
- Scores them on three things:
- Sharpness — variance of an edge map, so motion-blurred frames lose.
- Brightness sanity — drops near-black scene-transitions, white flashes, and near-blank title cards.
- Composition bias (the bonus you asked for) — rewards detail concentrated in the middle + right two-thirds of the frame while keeping the left third clear, so there's room for the title text. If your card's title sits somewhere other than flush-left, switch to text-zone mode (below) to protect that exact band instead.
- Deduplicates with a perceptual (difference) hash, so you don't get four nearly identical frames from one long shot.
- Outputs the top N candidates per episode into
out/sXeY/, plus a_contactsheet.jpgwith each one labeled by score, timestamp, and right-2/3 ratio.
The "action on the right 2/3" scoring, in plain terms
Each candidate is split into three vertical columns. The tool adds up the visual "edge
energy" (busy-ness) in each. A frame scores well when the middle and right columns hold
most of the detail and the left column is relatively empty — i.e. the subject is
framed to the right and there's calm space on the left for a title. Turn the knob with
--right-bias (0 = pick purely on image quality, 1 = pick almost entirely on
composition; default 0.45).
Text-zone mode — for titles that aren't flush-left
The right-2/3 bias assumes the title hugs the left edge. Plenty of card designs print the
title somewhere else — centered, center-left, lower-third — and there a face can collide
with the text even when the left third is clear. Text-zone mode targets that exact
band: you hand it a rectangle (--text-zone x0,y0,x1,y1 as fractions of width/height),
and the tool rewards frames whose detail lives outside that rectangle, so the subject
gets pushed off the text and the band stays calm. Every contact sheet is drawn with the
box outlined, so a text-over-face collision is obvious at a glance. Tune the strength with
--text-zone-weight. (Tip: to find your rectangle, overlay it on one already-built card
and nudge the numbers until it lines up with the title.)
Setup & usage
It's a single Python script (titlecard_stills.py, needs ffmpeg + pillow + numpy);
the included Dockerfile bundles all of that so you don't need ffmpeg on the host. Full
install steps, every flag, and the end-to-end TitleCardMaker rebuild workflow live in the
wiki. See examples/run.sh for a real invocation.
By default it does not touch your TCM source folder — it only writes candidates to
--out for you to review. Pass --auto-place to drop each #1 pick straight in as
sXeY.jpg, or --all to regenerate the whole library to one consistent composition rule.
Roadmap
- Optional GPU (NVDEC) decode for faster sampling on boxes with an idle card.
- True face/subject detection (the
--text-zoneheuristic avoids busy bands today, but doesn't yet know a face from a control panel). - A tiny web picker to click the winning candidate instead of browsing folders.
Credits
Built for a self-hosted TitleCardMaker setup — originally to fill in One Pace, later generalised to fix bad-composition cards on any show — with help from Claude (Anthropic Opus 4.8). Not affiliated with TitleCardMaker or the One Pace project.
License
GPL-3.0. See LICENSE.