Lokales, offline Speaker-Tracking für Konferenz- und Vortragsaufnahmen.
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-10-08 12:24:17 +02:00
.gitignore speaker_track v3: ffmpeg/VideoToolbox-Pipeline, Viterbi-Auswahl gegen Schatten, frame-genaue Ausgabe, Ordner-Intake 2026-10-08 12:24:17 +02:00
LICENSE speaker_track v3: ffmpeg/VideoToolbox-Pipeline, Viterbi-Auswahl gegen Schatten, frame-genaue Ausgabe, Ordner-Intake 2026-10-08 12:24:17 +02:00
README.md speaker_track v3: ffmpeg/VideoToolbox-Pipeline, Viterbi-Auswahl gegen Schatten, frame-genaue Ausgabe, Ordner-Intake 2026-10-08 12:24:17 +02:00
requirements.txt speaker_track v3: ffmpeg/VideoToolbox-Pipeline, Viterbi-Auswahl gegen Schatten, frame-genaue Ausgabe, Ordner-Intake 2026-10-08 12:24:17 +02:00
speaker_track.py speaker_track v3: ffmpeg/VideoToolbox-Pipeline, Viterbi-Auswahl gegen Schatten, frame-genaue Ausgabe, Ordner-Intake 2026-10-08 12:24:17 +02:00

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-tracks zusä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

  1. 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.
  2. 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.
  3. Bahn. Aus der Auswahl entsteht eine geglättete Mittelpunktbahn mit Totzone. Die Ausschnittsgröße ist fest (mittlere Personenhöhe mal --zoom).
  4. Render. Die Bahn geht als Befehlsdatei an ffmpeg (sendcmd steuert das crop-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.