Was ist das?
Der sogenannte Rolling-Shutter-Effekt ist ein Bildfehler, der bei der Aufzeichnung von digitalen Photos oder Videos auftritt. Er wird durch die Tatsache verursacht, daß ein digitales Bild nicht auf einen Schlag aufgenommen, sondern zeilenweise abgetastet wird. In abgeschwächter Form tritt derselbe Effekt auch in der analogen Photographie bei Schlitzverschlüssen auf, bei analogem Video, und nicht zuletzt auch bei Flachbett-Kopiergeräten und -Scannern.
Allgemeine Bekanntheit hat der Effekt aber vor allem durch die Verbreitung von Mobiltelefonvideos per YouTube erlangt. Entsprechend viele Diskussionen und Erklärungen zu Ursache, Wirkung und Vermeidung des Effekts finden sich im Netz. Ein meiner Meinung nach besonders gelungenes Beispiel stammt von Matt Parker.
Sein Video hat mich an einen experimentellen Film aus einer Zeit erinnert, zu der Videokameras noch ausschließlich in den Händen von "Fernsehmenschen" waren. In diesem Film wurde der Effekt künstlich erzeugt und stark übertrieben angewandt um interessante visuelle Effekte zu erzeugen. Leider konnte ich kein Beispiel davon online finden. Mir ist aber der Gedanke gekommen, daß es mit digitalem Video und Computern recht einfach sein sollte, ihn zu reproduzieren.
Das Ergebnis ist Timewarp, der Code dazu steht auf Github zur Begutachtung.
Beispiele
Im Beispiel wurde ein Ausschnitt aus einem Poledancing-Tutorial so verändert, daß die letzte Zeile des Videos um 20 Bilder verzögert ist. Bei 30 Bildern/s ist es unten im Bild also zwei Drittel einer Sekunde später als oben. Das macht gruselige Dinge mit der Tänzerin:
(Original von https://www.youtube.com/watch?v=y2Ps1YbHQD4)
Hier startet eine Rakete, unten ist es fast 5 Sekunden später als oben, die Spitze der Rakete ist also weiter als ihr unteres Ende.
(Original von https://www.youtube.com/watch?v=nVZJbFXYCFU)
Und hier öffnet ein automatisches Tor. Seine Unterkante liegt mehr als 10s gegenüber der Oberkante zurück.
Wie funktioniert das?
Das Programm besteht aus einem einzigen sehr überschaubaren Python-Skript, timewarp.py. Das Skript verwendet numpy und scikit-video für die eigentliche Arbeit.
Es öffnet das Zielvideo und lädt Einzelbild für Einzelbild. Für eine gegebene Verschiebung um n Einzelbilder werden jeweils die jüngsten n in einem Ringpuffer gehalten.
Für jeden Zeilenindex im Bildformat, also zum Beispiel 0..719 wird nun bestimmt aus welchem Quellbild relativ zum aktuellen Bild die Bildinformation für diese Zeile stammen soll. Dies passiert schlicht mit einer linearen Interpolation zwischen Zeilenindex 0..719 und "von-hinten-Arrayindex" in den Puffer -1..-n. Die oberste Zeile stammt also immer aus dem aktuellsten Bild, die unterste aus dem, das n Einzelbilder älter ist und alle anderen Zeilen aus Bildern zwischen diesen Extrema.
Diese Interpolation geht natürlich normalerweise nicht zu einem exakten ganzzahligen Bildindex auf, sondern liegt für die meisten Zeilen irgendwo zwischen zwei Quellbildern. Deshalb wird die endgültige neue Bildzeile als gewichteter Durchschnitt zwischen derselben Zeile aus zwei Einzelbildern berechnet.
Das so bestimmte neue Bild wird in die Ausgabe geschrieben, das nächste Einzelbild der Quelle geladen und hinten in den Puffer gehängt und dafür eines vorne verworfen.
Ist das Quellvideo auf diese Weise fertig verarbeitet, so werden aus den im Puffer verbleibenden Bildern noch neue Ergebnisframes erzeugt, so daß der untere Bildrand "aufholen" kann.
Fazit: Es war noch nie so leicht mit digitalen Medien kreativ zu arbeiten. Ich hätte nie gedacht, daß unter 200 Zeilen Code und zwei Stunden Arbeit (das schließt googlen von Python-Trivialitäten ein) so ein solides Ergebnis liefern können.
Ausblick
Als Spielprojekt endet die Beschäftigung hier, es gibt aber noch weitere Anschluss-Ideen:
- Performance: Man sollte das Programm profilen und optimieren. Ich bin sicher, daß gegenüber dem extrem naiven Ansatz bestimmt viel an Leistung herauszuholen wäre.
- Schönheit: Außer der einfachen linearen Interpolation zwischen Quellzeilen kann man sicher noch schlauere Methoden finden und so das "zerreissen" der Zeilen verringern. Das Problem ist dem Deinterlacing verwandt, Algorithmen aus diesem Bereich lassen sich sicher anwenden.
- Features: Man sollte das Zeitdelta in Zeit statt in Bildern angeben können um so von der Bildrate des Quellvideos zu abstrahieren. Und außer der reinen zeilenweisen Verarbeitung wäre es bestimmt interessant den Zeitunterschied entlang einer anderen Achse im Bild angeben zu können. Im Allgemeinen Fall bedeutet das, die relative Zeit pro Pixel zu berechnen.