Sinnvolle Thumbnails für ein Video mit FFmpeg

59414
d33pika

FFmpeg kann Bilder von Videos aufnehmen, die als Miniaturbilder zur Darstellung des Videos verwendet werden können. Die gängigsten Vorgehensweisen sind im FFmpeg-Wiki enthalten .

Aber ich möchte in bestimmten Abständen keine zufälligen Bilder auswählen. Ich habe einige Optionen gefunden, die Filter auf FFmpeg verwenden, um Szenenänderungen zu erfassen:

Der Filter thumbnailversucht, die repräsentativsten Bilder im Video zu finden:

ffmpeg -i input.mp4 -vf "thumbnail,scale=640:360" -frames:v 1 thumb.png 

und der folgende Befehl wählt nur Frames aus, die mehr als 40% der Änderungen im Vergleich zu vorherigen (und wahrscheinlich auch Szenenänderungen) aufweisen, und generiert eine Folge von 5 PNGs.

ffmpeg -i input.mp4 -vf "select=gt(scene\,0.4),scale=640:360" -frames:v 5 thumb%03d.png 

Infogutschrift für die obigen Befehle an Fabio Sonnati . Der zweite schien besser zu sein, da ich n Bilder holen konnte, um die besten auszuwählen. Ich habe es ausprobiert und das gleiche Bild 5 mal erzeugt.

Weitere Untersuchungen führten mich zu:

ffmpeg -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.png 

-vsync vfrsorgt dafür, dass Sie unterschiedliche Bilder erhalten. Dabei wird immer noch das erste Bild des Videos ausgewählt. In den meisten Fällen handelt es sich um das erste Bild und das Logo ist nicht sinnvoll. Daher habe ich eine -ss3 hinzugefügt, um die ersten 3 Sekunden des Videos zu verwerfen.

Mein letzter Befehl sieht so aus:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.5)" -frames:v 5 -vsync vfr out%02d.jpg 

Das war das Beste, was ich tun konnte. Ich habe festgestellt, dass, da ich nur 5 Videos auswähle, alle von Anfang an vom Video stammen und wichtige Szenen, die später im Video auftreten, übersehen werden

Ich möchte Ihr Gehirn für andere bessere Optionen auswählen.

71
Schöne Befehlsbeispiele. FWIW, ich habe keine Probleme mit von FFmpeg generierten JPEG-Bildern unter OS X (10.8, FFmpeg 1.1 und darunter) gefunden. Ihr vorletzter Befehl funktioniert gut für mich - und der letzte Befehl auch - und keines dieser Ergebnisse führt zu leeren JPG-Dateien. Ich habe mit `libopenjpeg` kompiliert .. nicht sicher, ob das einen Unterschied macht. slhck vor 11 Jahren 0
Danke slhck Die Frage wurde mit ffmpeg config / Versionsdetails bearbeitet. Ich habe auf diesem Rechner kein Update auf 1.1 durchgeführt. Ich werde das tun und sehen, ob es irgendwelche Ergebnisse ändert. d33pika vor 11 Jahren 0
Du bist also auf Ubuntu? Können Sie die neueste Git Master-Version von einem [statischen Build] (http://ffmpeg.org/download.html) ausprobieren oder sich selbst kompilieren und erneut ausführen? Oder der neueste Stall. Ich habe gerade überprüft, dass er den `mjpeg`-Encoder für mich verwendet, und ich habe auch 'jpegoptim' und` exiv2 'überprüft, die beide für mich mit allen JPG-Ergebnissen Ihrer Beispielbefehle funktionieren. slhck vor 11 Jahren 1
Ich habe aktualisiert und es funktioniert jetzt! Ich denke, die vorherige Version hatte einige Fehler. d33pika vor 11 Jahren 1
Können Sie die neue Version der Lösung veröffentlichen, vorzugsweise mit einem Link zum Änderungsprotokoll, das den aufgetretenen Fehler anzeigt und anschließend mit der neuen Version behoben wurde? Lizz vor 11 Jahren 0
Hi @Lizz, die gleichen Befehle oben haben leere Bilder in der älteren Version von FFmpeg zurückgegeben. Nein, ich bin auf den neuesten Versionen und alle Befehle funktionieren! d33pika vor 11 Jahren 0
Mein Ansatz ist es, vielleicht ein Dutzend JPEG-Miniaturbilder zu unterschiedlichen Zeitpunkten zu erstellen und die mit der größten Dateigröße auszuwählen. Die größte Datei ist tendenziell "komplexer" und interessanter, es würde selten ein verschwommenes Bild sein, und es wird niemals ein langweiliges Bild wie ein einfacher schwarzer Rahmen sein. Dieser Ansatz ist möglicherweise nicht ideal für Sie, aber Sie können ihn möglicherweise zusammen mit anderen Methoden verwenden. Sam Watkins vor 9 Jahren 0
Dies sind großartige Befehle, aber gibt es trotzdem eine weitere Verringerung der Qualität? Ich mag die Abmessungen, aber es sind immer noch 400 KB zum Herunterladen. Vielleicht wäre etwas von 100 KB groß. chovy vor 8 Jahren 0
Ich suche nach einer entgegengesetzten Lösung: Wählen Sie mehr Bilder aus Perioden aus, in denen die Kamera stabiler ist und sich nicht bewegt? (wo der Unterschied zwischen aufeinander folgenden Frames geringer ist, nicht höher). Gibt es eine Möglichkeit, dies zu tun? Tina J vor 6 Jahren 0

5 Antworten auf die Frage

23
A.M.

Wie wäre es, wenn Sie idealerweise nach dem ersten Frame mit mehr als 40% innerhalb von fünf Zeitspannen suchen, wobei die Zeitspannen die ersten, zweiten, dritten, vierten und fünften 20% des Videos sind.

Sie können es auch in 6 Zeitspannen aufteilen und die erste Zeit ignorieren, um Gutschriften zu vermeiden.

In der Praxis würde dies bedeuten, dass die fps auf einen niedrigen Wert gesetzt werden, während Sie die Szenenüberprüfung durchführen und Ihr Argument das erste Bit des Videos auswerfen.

...so etwas wie:

ffmpeg -ss 3 -i input.mp4 -vf "select=gt(scene\,0.4)" -frames:v 5 -vsync vfr -vf fps=fps=1/600 out%02d.jpg 
Ja, dies hilft beim Auswählen von Miniaturen aus verschiedenen Abschnitten des Videos. Vielen Dank! d33pika vor 11 Jahren 0
Es werden komplett schwarze oder weiße Bilder aufgenommen. Wie vermeide ich diese? d33pika vor 11 Jahren 1
Es gibt Filter zum Erkennen von schwarzen Frames und Sequenzen (http://www.ffmpeg.org/ffmpeg-filters.html#blackframe oder http://www.ffmpeg.org/ffmpeg-filters.html#blackdetect). Sie können nicht in der Lage sein, beides in Ihren wachsenden One-Liner einzuarbeiten, aber Sie sollten auf jeden Fall in der Lage sein, die schwarzen Frames zu entfernen (separater Schritt) und Miniaturbilder aus dem resultierenden Video zu extrahieren. A.M. vor 11 Jahren 0
Was weiße Rahmen angeht, so wird es jetzt kompliziert, aber es sieht immer noch so aus: 1. Schwarze Rahmen herausnehmen 2. Negieren (Weiß wird schwarz) 3. Weiße Rahmen herausnehmen 4. Erneut negieren 5. Thumbnails extrahieren (Wenn Sie es schaffen, die schwarzen oder weißen Rahmen vor allem in einer Zeile zu entfernen, können Sie sie hier posten? Ich kann sie der Antwort für zukünftige Leser hinzufügen. ... oder Sie könnten tatsächlich eine neue Frage und Antwort erstellen Ich würde es definitiv bestätigen.) A.M. vor 11 Jahren 5
Wäre es auch möglich, ein paar Sekunden nach dem Beginn jeder ausgewählten Szene Bilder aufzunehmen? Liam vor 11 Jahren 0
So vermeiden Sie langweilige Bilder wie Schwarzweiß: Erstellen Sie mehr Miniaturansichten als Sie benötigen, komprimieren Sie sie mit JPEG und wählen Sie die Bilder mit einer größeren Dateigröße aus. Dies funktioniert überraschend gut, um anständige Thumbnails zu erhalten. Sam Watkins vor 9 Jahren 3
@SamWatkins ist eine großartige Idee! vor 8 Jahren 0
Dieser Befehl hat nicht funktioniert, ich habe den Fehler `Es wurde kein geeignetes Ausgabeformat für 'fps = fps = 1/600' gefunden. Die Lösung ist, vor diesem Argument "-vf" hinzuzufügen (siehe http://stackoverflow.com/questions/28519403/ffmpeg-command-issue). John Wiseman vor 8 Jahren 2
Ich sehe jemanden, der meine Antwort bearbeitet hat, um diesen Leckerbissen zu meinem ursprünglichen Stich hinzuzufügen. Es sollte jetzt so funktionieren, wie es in der Antwort steht. A.M. vor 6 Jahren 0
Kennen Sie einen Weg, auf dem ich auch die Sekunden im Ausgabedateinamen haben könnte, dh die Anzahl der in einem Video verstrichenen Sekunden? Ich habe es auch über SO gefragt: https://stackoverflow.com/questions/51007328/get-the-second-on-was-the-the-thumbnail-was-generated Suhail Gupta vor 6 Jahren 0
Ich suche nach einer entgegengesetzten Lösung: Wählen Sie mehr Bilder aus Perioden aus, in denen die Kamera stabiler ist und sich nicht bewegt? (wo der Unterschied zwischen aufeinander folgenden Frames geringer ist, nicht höher). Gibt es eine Möglichkeit, dies zu tun? Tina J vor 6 Jahren 0
6
gertas

Das Definieren von Bedeutung ist schwer, aber wenn Sie N Miniaturansichten effizient erstellen möchten, die die gesamte Videodatei überspannen, verwende ich dies, um Miniaturansichten der Produktion mit vom Benutzer hochgeladenen Inhalten zu erstellen.

Pseudocode

for X in 1..N T = integer( (X - 0.5) * D / N )  run `ffmpeg -ss <T> -i <movie> -vf select="eq(pict_type\,I)" -vframes 1 image<X>.jpg` 

Woher:

  • D - Videodauer, die von ffmpeg -i <movie>alleine gelesen wird oder ffprobedie einen schönen JSON - Ausgabeschreiber hat
  • N - Gesamtzahl der gewünschten Miniaturansichten
  • X - Miniaturbildnummer von 1 bis N
  • T - Zeitpunkt für Miniaturbild

Einfach das obige notiert den mittleren Keyframe jeder Partition des Films. Wenn der Film beispielsweise 300 Sekunden lang ist und Sie 3 Miniaturbilder wünschen, dauert es nach 50s, 150s und 250s ein Schlüsselbild. Für 5 Miniaturbilder wären es 30s, 90s, 150s, 210s, 270s. Sie können N in Abhängigkeit von der Filmdauer D einstellen, dh für einen 5-minütigen Film gibt es 3 Thumbnails, über 1 Stunde jedoch 20 Thumbnails.

Performance

Jeder Aufruf des obigen ffmpegBefehls dauert für ~ 1 GB H.264 einen Bruchteil der Sekunde (!). Das ist, weil es sofort springt <time>zu positionieren (mind -ssvor -i) und nimmt ersten Schlüsselrahmen, der praktisch vollständige JPEG ist. Es wird keine Zeit verschwendet, um den Film an die genaue Zeitposition zu rendern.

Nachbearbeitung

Sie können oben scaleoder mit einer anderen Größenänderungsmethode mischen . Sie können auch einfarbige Rahmen entfernen oder mit anderen Filtern wie z thumbnail.

wow, wenn Sie `-ss N` vor` -i` verschieben, ist ein erstaunlicher Tipp. Danke dir! apinstein vor 8 Jahren 2
3
Eran Ben-Natan

Ich habe einmal etwas Ähnliches gemacht, aber ich habe alle Frames des Videos (in 1 fps) exportiert und mit einem Perl-Dienstprogramm verglichen, das ich gefunden habe, das den Unterschied zwischen Bildern berechnet. Ich habe jeden Frame mit den vorherigen Miniaturen verglichen, und wenn er sich von allen Thumbnails unterschied, fügte ich ihn der Thumbnails-Sammlung hinzu. Der Vorteil hier ist, dass ffmpeg 2 Frames von A exportiert, wenn sich Ihr Video von Szene A nach B bewegt und sie nach A zurückkehren.

Welche Faktoren haben Sie verwendet, um 2 Bilder zu vergleichen? d33pika vor 11 Jahren 0
Ich kann mich leider nicht erinnern, es ist schon lange her. Sie müssen zuerst entscheiden, welche Vergleichsmethode verwendet werden soll, und dann einige Tests durchführen, um den korrekten Faktor zu finden. Das sollte nicht lange dauern. Eran Ben-Natan vor 11 Jahren 0
Ich denke hier nur laut nach, aber ist das nicht die schlechtere Option? Beim Vergleich von zwei exportierten Bildern aus einem Video haben Sie bereits einige Informationen verloren. Ich meine, es ist einfacher, Ähnlichkeit anhand von Codec-Informationen zu berechnen als aus zwei Bildern, oder? Vor kurzem habe ich mir einige Algorithmen / Bibliotheken angesehen, um Bilder zu vergleichen, und sie funktionieren nicht so, wie es erforderlich ist. Samuel vor 11 Jahren 0
Nun, mit ffmpeg können Sie Frames ohne Qualitätsverlust mit dem Flag same_quality extrahieren. Wenn Sie Codec-Informationen verwenden, müssen Sie überprüfen, ob Sie nicht nur die Iframes erhalten. Wie auch immer, dieses Perl-Utility hat für mich gut funktioniert und ist sehr konfigurierbar. Schauen Sie hier: http://search.cpan.org/~avif/Image-Compare-0.3/Compare.pm Eran Ben-Natan vor 11 Jahren 0
2
LostPuppy

Versuche dies

 ffmpeg -i input.mp4 -vf fps= no_of_thumbs_req/total_video_time out%d.png 

Mit diesem Befehl kann ich die erforderliche Anzahl von Miniaturen erstellen, die für das gesamte Video repräsentativ sind.

Wäre die korrekte Formel für "fps" nicht "(no_of_frames_req * fps_of_vid) / total_video_frames"? flolilolilo vor 7 Jahren 0
Ich suche nach einer entgegengesetzten Lösung: Wählen Sie mehr Bilder aus Perioden aus, in denen die Kamera stabiler ist und sich nicht bewegt? (wo der Unterschied zwischen aufeinander folgenden Frames geringer ist, nicht höher). Gibt es eine Möglichkeit, dies zu tun? Tina J vor 6 Jahren 0
1
chovy

So mache ich eine periodische Miniaturansicht für Live-Streams von m3u8, die als Poster verwendet werden kann. Ich habe festgestellt, dass das Ausführen einer fortlaufenden ffmpeg-Aufgabe nur zum Erzeugen von Miniaturansichten meine gesamte CPU verbraucht. Daher führe ich stattdessen alle 60 Sekunden einen Cronjob aus, der alle Miniaturansichten für meine Streams generiert.

#!/usr/bin/env bash  ## this is slow but gives better thumbnails (takes about 1+ minutes for 20 files) #-vf thumbnail,scale=640:360 -frames:v 1 poster.png  ## this is faster but thumbnails are random (takes about 8 seconds for 20 files) #-vf scale=640:360 -frames:v 1 poster.png cd ~/path/to/streams  find . -type f \ -name "*.m3u8" \ -execdir sh -c 'ffmpeg -y -i "$0" -vf scale=640:360 -frames:v 1 "poster.png"' \ {} \; 

Wenn Sie häufiger als 60 Sekunden vorgehen müssen (Einschränkung von Cronjob), können Sie eine whileSchleife in Ihrem Skript ausführen, und es wird für immer ausgeführt. Fügen Sie einfach a hinzu sleep 30, um die Frequenz auf 30 Sekunden zu ändern. Ich empfehle es jedoch nicht, dies mit einer großen Anzahl von Videos zu tun, da der vorherige Lauf möglicherweise nicht abgeschlossen wird, bevor der nächste gestartet wird.

Idealerweise mache ich es mit Cronjob alle 5 Minuten.