如何使用ffmpeg在静态背景图上叠加带透明度的动画图像?

30

我想使用一组带有透明度的PNG图像和静态背景创建视频。

通过阅读很多资料,我发现可以使用filters库来实现这一目标。

我最初制作视频时没有包括背景,代码如下:

ffmpeg -y -qscale 1 -r 1 -b 9600 -loop -i bg.png -i frame_%d.png -s hd720 testvid.mp4

使用 -vf 可以将背景作为叠加层应用:

ffmpeg -y -qscale 1 -r 1 -b 9600 -i frame_%d.png -vf "movie=bg.png [wm];[in][wm] overlay=0:0 [out]" -s hd720 testvid.mp4

然而问题是它会将背景覆盖在输入框上。根据libacfilter,我可以拆分输入并对其内容进行操作。我想知道是否可以以某种方式更改叠加顺序?

非常感谢任何帮助!

更新1:
我正在尝试让以下过滤器工作,但我得到的电影没有背景:

ffmpeg -y -qscale 1 -r 1 -b 9600 -i frame_%d.png -vf "movie=bg.png [bg]; [in] split [T1], fifo, [bg] overlay=0:0, [T2] overlay=0:0 [out]; [T1] fifo [T2]" -s hd720 testvid.mp4

更新2:
使用-vf选项进行视频制作。只需将输入管道分割并在其上应用图像,然后叠加两个分割的源!可能不是最有效的方法...但它起作用了!

ffmpeg -y -r 1 -b 9600 -i frame_%d.png -vf "movie=bg.png, scale=1280:720:0:0 [bg]; [in] format=rgb32, split [T1], fifo, [bg] overlay=0:0, [T2] overlay=0:0 [out]; [T1] fifo [T2]" -s hd720 testvid.mp4

我有一个不太好的解决方案,但是它能够工作。在每张图片之后,将你的背景图片放在其中间。这样可以得到你想要的最终输出效果。 - Sandeep
有趣的方法...问题是如何做到呢? :) - Jona
假设您有n个frame_%d.pngs,在每个frame之后,添加一个bg wih。例如,已经有frame1.png和frame2.png,那么frame2.png就是background_。 - Sandeep
我不确定是否可以在没有多个具有适当交替序列的背景副本的情况下完成此操作。我的要求是使用图像序列和一个背景文件。 - Jona
2个回答

55

覆盖顺序由输入的顺序控制,这是从ffmpeg文档中得到的信息。

[...]使用两个输入和一个输出,第一个输入是“主”视频,在其上覆盖第二个输入。

因此,你的第二个命令变成:

ffmpeg -y -loop 1 -qscale 1 -r 1 -b 9600 -i frame_%d.png -vf "movie=bg.png [wm];[wm][in] overlay=0:0" -s hd720 testvid.mp4

使用最新版本的ffmpeg,新的-filter_complex命令使得相同的过程变得更加简单:

ffmpeg -loop 1 -i bg.png -i frame_%d.png -filter_complex overlay -shortest testvid.mp4

一个完整的工作示例:

我们透明输入图像的来源(为跳舞道歉):
跳舞的香蕉
使用ImageMagick分解为帧:

convert dancingbanana.gif -define png:color-type=6 over.png

设置png:color-type=6(RGB-Matte)非常重要,因为ffmpeg不能正确处理索引透明度。输入文件的名称为:over-0.pngover-1.pngover-2.png等。

我们的背景图片(缩放到香蕉大小):
快乐的小山

使用 ffmpeg version N-40511-g66337bf(昨天的git版本),我们执行以下操作:

ffmpeg -loop 1 -i bg.png -r 5 -i over-%d.png -filter_complex overlay -shortest out.avi

-loop选项将背景图像循环,这样我们就不只有一个帧,这是至关重要的!
-r选项可以稍微减慢跳舞香蕉的速度,可选。
-filter_complex是最近添加到FFmpeg中,使多输入的处理更容易的特性。
-shortest选项在最短的输入结束时停止编码,这是必须的,因为循环背景意味着该输入永远不会结束。

使用略微陈旧一些的构建版本ffmpeg version 0.10.2.git-d3d5e84:

ffmpeg -loop 1 -r 5 -i back.png -vf 'movie=over-%d.png [over], [in][over] overlay' -frames:v 8 out.avi
movie不允许设置速率,因此我们减慢背景的速度,以达到相同的效果。由于叠加的电影不是一个适当的输入,所以我们不能使用-shortest,而是明确地设置要输出的帧数,使其与叠加输入帧的数量相同。

最终结果(将其输出为嵌入式gif):
Dancing banana with background


太棒了!是的,我已经尝试了你的第一个建议,但是我收到了错误信息“叠加区域(...)不在区域(...)内”。所以我尝试缩放bg.png,但是我得到了“AV Filter告诉我们它有一个可用的帧,但未能输出一个”的错误。关于你的第二个解决方案,哪个版本的ffmpeg有这些选项?我尝试了10.3,但好像没有。 - Jona
在我的一些测试中,我也得到了“无法输出”的信息,看起来像是FFmpeg的一个错误。带有“-filter_complex”选项的版本可以在最近的git版本中找到。我不知道它存在多久了或者是哪个补丁版本中包含了它,但这绝对是相当新的。任何使视频滤镜更容易使用的东西都是受欢迎的附加功能。 - blahdiblah
哈哈哈.. 一开始我还以为是垃圾邮件呢!感谢你的帖子和详细信息。它确实可以在最新版本中使用。我也找到了另一种解决方法。请看更新2。不过似乎你的方法可能更省力?我将在移动设备上使用它。 - Jona
避免所有的分割和管道可能是更少的工作,但是测试多个选项而不是仅仅猜测哪个更好是无可替代的。 - blahdiblah
1
'ffmpeg -loop 1 -i bg.png -r 5 -i over-%d.png -filter_complex overlay -shortest out.avi',这会一直循环播放over-%.png的图像,永远不会停止。看起来-shortest标志没有按照预期工作。你能提供一个解决方法吗? - rajat
显示剩余3条评论

6

作为参考,截至2015年2月17日,命令行为:

ffmpeg -loop 1 -i images/background.png -i images/video_overlay%04d.png -filter_complex overlay=shortest=1 testvid.mp4

感谢llogan在此回复:https://trac.ffmpeg.org/ticket/4315#comment:1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接