使用FFmpeg的视频的有意义的缩略图


80

FFmpeg可以从视频中捕获图像,这些图像可用作缩略图来表示视频。FFmpeg Wiki中捕获了最常用的方法。

但是,我不想每隔一段时间选择随机帧。我发现在FFmpeg上使用过滤器捕获场景更改的一些选项:

过滤器thumbnail尝试查找视频中最具代表性的帧:

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

并且以下命令仅选择与前一个相比变化超过40%(可能是场景变化)的帧,并生成5个PNG序列。

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

以上命令的信息提供给Fabio Sonnati。第二个似乎更好,因为我可以得到n张图像并选择最佳图像。我尝试了一下,并生成了5次相同的图像。

经过更多调查,我得出以下结论:

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

-vsync vfr确保您获得不同的图像。这仍然总是选择视频的第一帧,在大多数情况下,第一帧是点数/徽标,并且没有意义,因此我添加了-ss3来丢弃视频的前3秒。

我的最终命令如下所示:

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

这是我能做的最好的。我注意到,由于我只选择了5个视频,所以它们大多数都是从视频开头开始的,因此可能会错过视频稍后出现的重要场景

我想为其他更好的选择而绞尽脑汁。


漂亮的命令示例。FWIW,在OS X(10.8,FFmpeg 1.1及更低版本)上,FFmpeg生成的JPEG图片没有遇到任何问题。您倒数第二个命令对我来说效果很好-最后一个命令对我也很好-并且这些都不导致空白JPG文件。我确实用libopenjpeg.. 进行编译,不确定是否会有所不同。
slhck

谢谢slhck。使用ffmpeg配置/版本详细信息编辑了问题。我尚未在此计算机上升级到1.1。我将这样做,看看它是否会改变任何结果。
d33pika

1
所以您正在使用Ubuntu?您可以尝试通过静态版本尝试最新的Git Master版本,还是可以自己编译并再次运行?还是最新的稳定版。我刚刚检查了一下,它也mjpeg为我使用了编码器,并且我还检查了jpegoptimexiv2,这对于我的示例命令中的所有JPG结果都对我来说都很好。
slhck

1
我更新了,现在可以使用!我猜以前的版本有一些错误。
d33pika

您可以继续发布解决方案的新版本,最好是带有指向更改日志的链接,该链接显示您遇到的错误并随后使用新版本修复了吗?
Lizz

Answers:


29

理想情况下,如何在5个时间跨度中的每个时间跨度中查找变化率大于40%的第一个帧,其中时间跨度是视频的1%,2nd,3rd,4th和5th 20%。

您也可以将其分为6个时间段,而忽略第1个时间段以避免记分。

实际上,这意味着在应用场景更改检查和参数以丢弃视频的第一位时,将fps设置为一个较低的数字。

...就像是:

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

1
完全拾取黑白图像。如何避免这些图像?
d33pika

1
有一些用于检测黑框及其序列的过滤器(ffmpeg.org/ffmpeg-filters.html#blackframeffmpeg.org/ffmpeg-filters.html#blackdetect)。您无法将它们中的任何一个都融入到不断增长的一线模式中,但是您绝对应该能够去除黑框(单独的步骤)并从生成的视频中提取缩略图。
AM

5
至于白框,现在情况变得越来越复杂,但看起来仍然有一种方法:1.去除黑框2.取反(白色变成黑色)3.去除白框4.再次取反5.提取缩略图(如果您确实设法去除了黑框或白框,特别是在一行上,可以将其发布回这里吗?我可以将其添加到答案中以供将来的读者使用。...或者实际上您可以创建一个新的问题和答案。这我肯定会给予好评的话)。
AM

3
为避免使黑白图像变得无聊:生成比您所需更多的缩略图,用jpeg压缩它们,然后选择文件大小更大的图像。单独获得令人赞叹的缩略图效果很好。
山姆·沃特金斯

2
该命令无效,出现错误Unable to find a suitable output format for 'fps=fps=1/600'。该解决方案是增加-vf这样的说法之前(见stackoverflow.com/questions/28519403/ffmpeg-command-issue
约翰·怀斯曼

7

定义有意义的内容很困难,但是如果要使N个缩略图有效地覆盖整个视频文件,这就是我用来生成带有用户上传内容的缩略图的方法。

伪码

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`

哪里:

  • D- ffmpeg -i <movie>单独读取视频时长,或者ffprobe具有不错的JSON输出编写器btw
  • N-您想要的缩略图总数
  • X-缩略图编号,从1到N
  • T-指甲的时间点

上面只是简单地写下了影片每个分区的中心关键帧。例如,如果电影长300秒,而您想要3张缩略图,则在50秒,150秒和250秒之后需要一帧关键帧。对于5张缩略图,分别是30s,90s,150s,210s,270s。您可以根据电影时长D调整N,例如5分钟的电影将具有3个缩略图,而超过1小时的电影将具有20个缩略图。

性能

上面ffmpeg命令的每次调用花费的时间约为一秒(!),约为1GB H.264。那是因为它立即跳到<time>位置(-ss在之前要注意-i),并获取实际上是完整JPEG的第一个关键帧。渲染影片以匹配准确的时间位置不会浪费时间。

后期处理

您可以在上面混合使用scale或任何其他调整大小的方法。您也可以删除纯色框架,或尝试将其与其他滤镜混合使用thumbnail


2
哇,搬到-ss N以前-i是一个了不起的技巧。谢谢!
apinstein '16

2

我曾经做过类似的事情,但是我导出了视频的所有帧(以1 fps),并将它们与我发现的perl实用程序进行了比较,该实用程序可以计算图像之间的差异。我将每个帧与以前的缩略图进行了比较,如果它与所有缩略图都不相同,则将其添加到缩略图集合中。这样做的好处是,如果您的视频从场景A移到场景B,然后又返回场景A,则ffmpeg将导出2帧A。


您使用什么因素比较了2张图片?
d33pika

不幸的是我不记得了,那是很久以前的事了。您需要先决定要使用哪种比较方法,然后再进行一些测试以找到正确的因子。这不应该花很长时间。
伊兰·本·纳坦

我只是在这里大声思考,但这不是更糟糕的选择吗?比较视频中的2张导出图像时,您已经丢失了一些信息。我的意思是,从编解码器信息计算相似度比从2张图片计算相似度高,不是吗?最近,我一直在研究一些算法/库来比较图像,但是它们不能像人们要求的那样有效。
塞缪尔

好了,使用ffmpeg,您可以使用same_quality标志提取帧而不会降低质量。如果您使用编解码器信息,则需要检查您是否仅获得了iframe。无论如何,perl实用程序对我来说效果很好,并且是可配置的。请看这里:search.cpan.org/~avif/Image-Compare-0.3/Compare.pm
Eran Ben-Natan

2

尝试这个

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

使用此命令,我可以生成所需数量的缩略图,这些缩略图代表整个视频。


正确的公式fps(no_of_frames_req * fps_of_vid) / total_video_frames吗?
flolilo

我正在寻找相反的解决方案:从摄像机更稳定且不动的时段中选择更多帧?(连续帧之间的差异较小,而不是较高)。有没有办法做到这一点?
蒂娜(Tina J)

1

这是我为实时m3u8流生成周期性缩略图以用作海报的工作。我发现运行连续的ffmpeg任务只是为了生成缩略图会耗尽我的所有CPU,因此我每60秒运行一次cronjob来生成流的所有缩略图。

#!/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"' \
  {} \;

如果您需要执行超过60秒的时间(cronjob的限制),则可以while在脚本中执行循环,它将永远执行。只需添加sleep 30即可将频率更改为30秒。不过,我不建议您对大量视频进行此操作,因为上一次运行可能无法在下一个视频开始之前完成。

理想情况下,使用cronjob我每5分钟运行一次。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.