- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .gitignore | ||
| LICENSE | ||
| README.md | ||
| requirements.txt | ||
| speaker_track.py | ||
speaker-track
Lokales, offline Speaker-Tracking für Konferenz- und Vortragsaufzeichnungen.
Das Tool erkennt die vortragende Person in einer Weitwinkelaufnahme, folgt ihr geglättet und rendert daraus einen fertigen Hochformat-Clip, der sich direkt neben die Folien legen lässt, zum Beispiel in Final Cut Pro oder DaVinci Resolve.
Alles läuft auf dem eigenen Rechner. Kein Cloud-Upload, keine externen Dienste, kein Abo.
Ein Befehl, fertig
python speaker_track.py /pfad/zum/ordner
Das verarbeitet alle Videos in dem Ordner und legt die fertigen Clips in den Unterordner speaker/ daneben. Dateien, die schon ein Ergebnis haben, werden übersprungen, man kann den Befehl also jederzeit erneut starten. Dateien, an denen gerade noch geschrieben wird (etwa ein laufender Export), werden erkannt und beim nächsten Lauf nachgeholt. Mit --watch bleibt das Tool laufen und verarbeitet neue Dateien automatisch, sobald sie auftauchen.
Funktionen
- Personenerkennung mit Pose-Keypoints (Ultralytics YOLO11,
yolo11n-pose), lokal auf GPU oder CPU. - Robust gegen Schatten an der Wand und Personen im Publikum: Auswahl über einen globalen Tracker (Viterbi) aus Erkennungssicherheit, Gesichts-Keypoints, Farbsättigung und Textur, Personengröße, Standlinie und Bewegungskontinuität. Keine gierige Auswahl pro Frame mehr.
- Ruhige Kamerafahrt: feste Ausschnittsgröße (kein Zoom-Zittern), geglättete Bahn plus Totzone. Gestikulieren bewegt das Bild nicht, Umhergehen wird ohne Nachlauf verfolgt.
- Decodieren, Zuschneiden, Skalieren und Encodieren laufen komplett in ffmpeg. Auf Apple Silicon über VideoToolbox (Media Engine), Python verarbeitet nur kleine Analyse-Frames.
- Frame-genau: Zeitstempel bleiben unangetastet, Audio wird 1:1 kopiert. Der Clip liegt deckungsgleich auf dem Original, kein Versatz.
- Pipeline: die Analyse der nächsten Datei läuft, während die vorige noch rendert, mehrere Renders parallel.
- Ausgabegröße automatisch passend zur Quelle (1080p-Quelle: 600x900, 4K-Quelle: 1200x1800).
- Preview-Modus mit eingezeichnetem Ausschnitt, Statuszeile mit Restzeit, Logdatei, optional Einstellungen als JSON im Ordner.
Voraussetzungen
- Python 3.9 oder neuer
- ffmpeg, auf dem Mac über Homebrew (
brew install ffmpeg). Die Homebrew-Version bringt VideoToolbox mit, also Hardware-Decoder und -Encoder. - Beim ersten Lauf lädt Ultralytics einmalig das Modell
yolo11n-pose.pt(rund 6 MB) herunter, danach läuft alles offline.
Entwickelt für Apple Silicon (dort GPU über MPS plus Media Engine), läuft aber ebenso auf CPU oder NVIDIA-GPUs. Ohne VideoToolbox werden automatisch Software-Encoder verwendet.
Installation
brew install ffmpeg
python3 -m venv venv
source venv/bin/activate
pip install ultralytics opencv-python numpy
python speaker_track.py --diag # zeigt, was auf diesem Rechner genutzt wird
--diag sollte auf dem Mac HW-Decode (VideoToolbox): ja und die *_videotoolbox-Encoder anzeigen.
Typischer Ablauf
Rahmung an einer Datei prüfen (nur die ersten zwei Minuten, mit eingezeichnetem Ausschnitt):
python speaker_track.py /ordner/talk.mov --mode preview --max-frames 3000
Das ergibt speaker/talk_preview.mov. Der gelbe Rahmen ist der spätere Ausschnitt. Zu eng oder zu weit? --zoom anpassen (Standard 1.2 = Kopf bis Fuß mit wenig Luft).
Dann alles rendern:
python speaker_track.py /ordner --zoom 1.2
Während Final Cut noch exportiert, einfach laufen lassen:
python speaker_track.py /ordner --watch
Für ein 1080p-Projekt aus 4K-Material die Ausgabegröße festlegen:
python speaker_track.py /ordner --out-size 600x900
Optionen
| Option | Beschreibung | Standard |
|---|---|---|
folder |
Ordner mit den Aufnahmen (oder eine einzelne Datei) | Pflicht |
-o, --out |
Unterordner oder absoluter Pfad für die Ergebnisse | speaker |
--mode {render,preview} |
render erzeugt den Clip, preview zeichnet den Ausschnitt ein | render |
--watch |
laufen lassen, neue Dateien automatisch verarbeiten | aus |
--watch-interval |
Sekunden zwischen zwei Ordner-Checks | 30 |
--zoom |
Ausschnitthöhe = Personenhöhe mal Faktor, kleiner ist enger | 1.2 |
--out-size |
auto oder Breite x Höhe, z. B. 1200x1800 |
auto |
--aspect |
Seitenverhältnis des Ausschnitts | 2:3 |
--codec {h264,hevc,prores} |
Ausgabecodec, Hardware-Encoder wenn vorhanden | h264 |
--smooth |
Glättung der Bahn in Sekunden | 1.2 |
--deadband |
Totzone als Anteil der Ausschnittbreite | 0.03 |
--track-y |
auch vertikal mitführen | aus |
--step |
jede n-te Frame analysieren, größer ist schneller | 8 |
--max-frames |
nur die ersten n Frames (für Tests) | alle |
--exclude |
Dateimuster überspringen, mehrfach möglich, z. B. '*Master*' |
keine |
--force |
vorhandene Ergebnisse neu rendern | aus |
--parallel-renders |
gleichzeitige ffmpeg-Renders | 2 |
--model |
Ultralytics-Modell | yolo11n-pose.pt |
--imgsz |
Eingabegröße der Erkennung | 960 |
--device |
auto, mps, cuda oder cpu |
auto |
--sw |
nur Software-Decoder und -Encoder | aus |
--keep-tracks |
Bahn (CSV), Kandidaten (JSON) und ffmpeg-Logs behalten | aus |
--diag |
Umgebung prüfen |
Einstellungen pro Ordner
Liegt im Ordner eine Datei speaker_track.json, werden die Werte darin als Voreinstellung genommen. Kommandozeilen-Optionen gewinnen trotzdem.
{"zoom": 1.2, "out_size": "1200x1800", "exclude": ["*Master*"]}
Ausgabedateien
Im Ausgabeordner entstehen pro Eingabedatei name.ext:
name_speaker.mov, der fertige Hochformat-Clip mit kopierter Tonspur (Render-Modus).name_preview.mov, das Kontrollvideo mit eingezeichnetem Ausschnitt (Preview-Modus).speaker_track.log, Protokoll aller Läufe.- Mit
--keep-trackszusätzlich_tracks/name_track.csv(Ausschnitt pro Frame) und_tracks/name_candidates.json(alle erkannten Kandidaten mit Bewertung, hilfreich, wenn die Auswahl einmal danebenliegt).
Während des Renderns heißen die Dateien name_speaker.part.mov. Bleibt so eine Datei nach einem Abbruch liegen, kann sie gelöscht werden.
Beispielausgabe
speaker_track 3.0 | HW-Decode (VideoToolbox): ja, HW-Encoder: h264_videotoolbox, hevc_videotoolbox, prores_videotoolbox
Modus render | zoom 1.2 | Ausgabe auto | codec h264 | step 8
Modell yolo11n-pose.pt auf mps
19 Datei(en) zu verarbeiten, 0 schon fertig -> /Volumes/T7/LDAPCon/Tag1/speaker
[1/19] 01_opening: Analyse 02:10, Person in 2820/2840 Samples, Ausschnitt 1392x2088 @ 25.000 fps -> Render laeuft
ok 01_opening_speaker.mov (03:40)
[3/19] 03_keynote Analyse 41% ETA 01:20 | Render 02_welcome 63%
Wie es funktioniert
- Analyse. ffmpeg decodiert das Video (auf dem Mac in Hardware), gibt jede n-te Frame verkleinert an Python und meldet dabei die exakten Zeitstempel. YOLO erkennt alle Personen samt Keypoints, pro Kandidat werden Sicherheit, Gesichts-Keypoints sowie Sättigung und Textur im Oberkörperbereich bestimmt.
- Auswahl. Ein Viterbi-Tracker wählt über die gesamte Aufnahme pro Sample einen Kandidaten (oder „fehlt"). Belohnt werden sichere, texturierte Boxen in plausibler Größe und mit plausibler Standlinie, bestraft werden Sprünge. Schatten sind flau, stehen meist auf einer anderen Standlinie und verlieren dadurch, auch wenn sie gelegentlich eine höhere Erkennungssicherheit haben.
- Bahn. Aus der Auswahl entsteht eine geglättete Mittelpunktbahn mit Totzone. Die Ausschnittsgröße ist fest (mittlere Personenhöhe mal
--zoom). - Render. Die Bahn geht als Befehlsdatei an ffmpeg (
sendcmdsteuert dascrop-Filter pro Frame). ffmpeg decodiert, schneidet, skaliert und encodiert in einem Durchlauf, Audio wird kopiert. Frames und Zeitstempel entsprechen exakt der Quelle.
Einsatz in Final Cut Pro
Der gerenderte Clip ist bereits zugeschnitten und folgt der Person, ein separates Tracking oder Keyframen entfällt. Den Clip auf die unterste Spur legen und unter „Räumliche Anpassung" auf „Keine" stellen, sonst skaliert Final Cut den Clip auf die Projekthöhe. Danach per Position neben die Folien schieben. Da der Clip dieselben Zeitstempel wie die Quelle hat, liegt er bei gleichem Startpunkt deckungsgleich auf der Totale.
Performance
Die Arbeit teilt sich auf: Erkennung auf der GPU (MPS), Decodieren und Encodieren in der Media Engine (VideoToolbox), Zuschnitt in ffmpeg. Python bewegt nur noch kleine Analyse-Frames. Standardmäßig laufen zwei Renders parallel, während die nächste Datei analysiert wird. Wer mehr Durchsatz braucht, erhöht --parallel-renders oder --step. Ohne VideoToolbox (Linux, Windows, --sw) wird mit libx264 bzw. prores_ks in Software encodiert, das ist deutlich langsamer, aber funktional identisch.
Grenzen
- Panels und Diskussionsrunden: Bei mehreren Personen auf der Bühne folgt das Tool einer davon. Es warnt, wenn es häufig mehrere plausible Personen sieht. Für solche Aufnahmen ist ein fester Ausschnitt meist besser.
- Starke Kameraschwenks und -zooms: Die Ausschnittsgröße bleibt bewusst fest. Bei einem heftigen Zoom kann die Person den Rahmen kurz füllen. Deshalb vorher im Preview-Modus prüfen.
- Quellauflösung: Der Ausschnitt wird aus der Totale geschnitten. Für einen scharfen 4K-Clip sollte die Quelle echtes 4K sein, aus 1080p wird hochskaliert und damit weicher.
Warum lokal
Das Tool verarbeitet alles auf dem eigenen Rechner. Aufnahmen von Vortragenden müssen nicht zu einem Cloud-Dienst hochgeladen werden, was Datenschutz, Persönlichkeitsrechte und die eigene digitale Souveränität wahrt.
Lizenz
MIT, siehe LICENSE.