Clean, tracked clips of their face
Everything the face stages learn comes from this: short stretches of video where we know, frame by frame, the 3D shape and position of the creator's head. Getting there from an edited YouTube video is mostly about throwing the right footage away.
What "tracked" means
The tracker is VHAP. It fits FLAME, a standard 3D model of a human head, to every frame. FLAME is a mesh whose shape is set by a few hundred numbers: some fixed for the person (how wide the jaw is), some changing every frame (mouth open, brow raised), plus where the head is and which way it points.
Why a YouTube video cannot go straight in
VHAP expects one unbroken shot from one fixed camera. An edited video has cuts, side panels, graphics and screenshots with other people's faces. None of these makes the tracker fail; each makes it return a confident wrong answer.
How it is built
Why the crop fixes two problems at once
Commands
./alive build <creator> --stage clips runs it, stopping where a person must look. By hand, from
engines/audio2face/, with the tracker's environment:
~/miniconda3/envs/vhap/bin/python corpus/status.py --takes takes/<folder> # every video: done so far, next command
~/miniconda3/envs/vhap/bin/python corpus/status.py --seq <take> # one video
A new creator starts as a copy of recipes/face-clips/profiles/_template.py. Its numbers (how
transparent a graphic is, where a side panel sits, how short a shot can be) are read off the creator's own
footage, because they differ between channels: corpus/derive_constants.py --seq <take> prints each
measured distribution with a suggested cut-off, and you type the value you choose into the profile. A suggestion is a
starting point: on Dr K's second video it suggested 0.325 for one value where 0.62 was right. The full recipe, with every
measurement from Dr K's three videos and Huberman's one, is
engines/audio2face/corpus/recipes/face-clips/RECIPE.md.
Labelling the groups
The grouping step writes one sheet per group to data/face/corpus/chunks/<take>/clusters_full/: 8 frames,
with the face detector's box in red. Open them in any image viewer and write, by hand, one line per group into
creators/<id>/build/clips/<take>/verdicts.json:
{
"0": {"verdict": "keep", "kind": "centred", "note": "clean full-frame talking head"},
"3": {"verdict": "drop", "kind": "graphic", "note": "title card"},
"7": {"verdict": "keep", "kind": "panel", "note": "him on the right, screenshot left"},
"11": {"verdict": "drop", "kind": "wrong_face", "note": "red box on a man in a screenshot"}
}
Every group gets a line. kind is centred or panel for kept groups.
Where the decisions are kept
| decision | stored in |
|---|---|
| which videos to track | creators/<id>/build.json, clips.takes |
| keep / drop per group, with the reason | creators/<id>/build/clips/<take>/verdicts.json |
| how the groups were made, so the labels point at the same frames next time | creators/<id>/build/clips/<take>/cluster_config.json |
Things that go wrong
| you see | why, and the fix |
|---|---|
| a group's 8 frames show two different things | split just that group: cluster_frames.py --subcluster <id> --sub-k 3. Re-grouping everything renumbers the groups and breaks every label |
| the red box in a group sits on someone else | drop the group as wrong_face |
| "no donor candidate" after hours of tracking | the donor is the chunk whose head shape every other chunk borrows, chosen by its fit score (residual: how far the fitted head drifts, in mm). The scores were not written; look in the tracking log for residual extraction FAILED |
| the machine runs out of memory while tracking | each chunk starts several face-point workers (2 by default). Run with LMK_JOBS=1 in front of the command |
| the disk fills | reclaim was not run. About 4 GB per tracked video after reclaim, more while it is being tracked; only the tracked videos count |