104 votes

Des vignettes significatives pour une vidéo à l'aide de FFmpeg

FFmpeg peut capturer des images à partir de vidéos qui peuvent être utilisées comme vignettes pour représenter la vidéo. Les méthodes les plus courantes pour ce faire sont décrites dans le fichier FFmpeg Wiki .

Mais, je ne veux pas choisir des images aléatoires à certains intervalles. J'ai trouvé quelques options en utilisant des filtres sur FFmpeg pour capturer les changements de scène :

Le filtre thumbnail essaie de trouver les images les plus représentatives de la vidéo :

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

et la commande suivante sélectionne seulement les images qui ont plus de 40% de changements par rapport à la précédente (et donc probablement des changements de scène) et génère une séquence de 5 PNGs.

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

Crédit d'information pour les commandes ci-dessus à Fabio Sonnati . La seconde semblait meilleure car elle permettait d'obtenir n images et de choisir la meilleure. Je l'ai essayé et il a généré la même image 5 fois.

Quelques recherches supplémentaires m'ont conduit à :

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

-vsync vfr vous permet d'obtenir des images différentes. Cela choisit toujours la première image de la vidéo, dans la plupart des cas, la première image est le générique/logo et n'a pas de sens, donc j'ai ajouté une option -ss 3 pour rejeter les 3 premières secondes de la vidéo.

Ma commande finale ressemble à ceci :

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

C'était le mieux que je pouvais faire. J'ai remarqué que, puisque je n'ai choisi que 5 vidéos, elles sont toutes principalement du début de la vidéo et peuvent manquer des scènes importantes qui se produisent plus tard dans la vidéo.

J'aimerais que vous me fassiez part de toute autre meilleure option.

1voto

upteryx Points 146

Je ne peux pas encore ajouter de commentaires, donc en référence à la solution de @jaygooby qui cause une erreur de syntaxe Des vignettes significatives pour une vidéo en utilisant FFmpeg Le problème est que $N (nombre de captures d'écran) n'a pas été déclaré. La solution est de l'ajouter au début de la commande, comme ceci :

N=30; D=180; for X in $(seq 1 $N); do echo $X; T=$(bc <<< "($X-0.5)*$D/$N"); ffmpeg -y -hide_banner -loglevel panic -ss $T -i in.mp4 -vf select="eq(pict_type\,I)" -vframes 1 $X.jpg; done

De plus, la solution de @jaygooby fonctionne bien et est très rapide (parce qu'on met -ss avant -i dans la commande de ffmpeg). J'ai combiné ses deux suggestions (celle avec mediainfo) plus ma solution :

N=60; INPUT="path/to/filename"; D=$(bc <<< $(mediainfo --Inform="Video;%Duration%" "$INPUT")/1000) ; echo "Duration: $D seconds"; for X in $(seq 1 $N); do echo $X; T=$(bc <<< "($X-0.5)*$D/$N"); ffmpeg -y -hide_banner -loglevel panic -ss $T -i $INPUT -vf select="eq(pict_type\,I)" -vframes 1 $X.jpg; done

où :

N = number of desired screenshots
INPUT = path to the filename

Changez ces deux variables et vous êtes prêt à partir.

0voto

GiaNU Points 101

C'est une tâche très difficile à réaliser. La toute première chose à faire est de définir ce qui est "significatif" dans votre contexte : cherchez-vous l'image la plus uniforme ? une image qui décrit votre vidéo mais ne la gâche pas ?

Dans la plupart des cas, la meilleure vignette est celle qui a.. :

  • Grande luminosité.
  • L'intensité des pixels n'est pas très uniforme.
  • Bon contraste.
  • Grande netteté.

En utilisant ffmpeg, cela signifie supprimer les images noires et ensuite obtenir une vignette (ffmpeg a un joli filtre pour obtenir des vignettes). D'abord, obtenez une liste de cadres noirs :

ffprobe -f lavfi -i "movie=./input.mp4,blackdetect[out0]" -show_entries tags=lavfi.black_start,lavfi.black_end -of default=nw=1 -v quiet

ensuite, supprimez-les de la vidéo et obtenez la miniature :

ffmpeg -i ./input.mp4 -filter_complex "[0:v]trim=start=3.23657:end=32.9329,setpts=PTS-STARTPTS[v1];[0:a]atrim=start=3.23657:end=32.9329,asetpts=PTS-STARTPTS[a1]" -map [v1] -map [a1] output.mp4

et

ffmpeg -i output.mp4 -vf "thumbnail" -frames:v 1 thumb2.png

Vous remarquerez que le résultat n'est pas le meilleur que vous puissiez obtenir, cette méthode ne choisit qu'un cadre qui a un certain "contenu" et ne prend pas en compte les facteurs que j'ai décrits précédemment.

Nous avons rédigé un article de blog décrivant ce même problème qui pourraient être utiles.

Disclaimer : Je suis l'un des co-fondateurs de https://mediamachine.io

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X