基本上,我想加快视频速度(通常是一些基于数学的东西,例如使用源代码进行弹跳球处理的示例 - YouTube);但是,我不想只是丢弃帧,而是想“合并”(缺乏更好的术语)帧,如图所示:
+----------+----------+----------+----------+----------+----------+
| Frame 01 | Frame 02 | Frame 03 | Frame 04 | Frame 05 | Frame 06 |
+---+------+-----+----+----+-----+-----+----+-----+----+----------+
| | | | |
| +---+ | | | |
| | +<--+ | | |
+--->+ + +<------------+ | |
| +<------------------------+ |
++--+<-----------------------------------+
|
+-----v-----+
| NFrame 01 |
+-----------+
换句话说:如果我想将视频速度提高 5 倍,而不是仅仅通过每 5 帧进行“抽取”(因此在新的输出流中,原始的第 01 帧之后是第 06 帧),我希望新帧(在新的输出流中)是从 01 到 05 帧的“总和”:
NFrame01 = k*(Frame01 + Frame02 + Frame03 + Frame04 + Frame05)
由于颜色范围有限,我需要一个常数 k 来控制颜色值:比如,我们使用 RGBA 像素,范围从 0.0 到 1.0;然后,如果每个原始 Frame01-Frame05 的位置 x,y 都是全红色(1,0,0,1),我必须将每个输入像素的 alpha 乘以 1/5 = 0.2,以确保输出像素(总和)也是全红色(1,0,0,1)而不会超出颜色范围;粗略地说:
NFrame01(x,y) = [1.0, 1.0, 1.0, 0.2]*(Frame01(x,y) + Frame02(x,y) + Frame03(x,y) + Frame04(x,y) + Frame05(x,y))
(或者,假设 RGB 像素没有 alpha,我们必须将每个 RGB 通道乘以 0.2)
如果我们有一个像弹跳球示例这样的数学视频,其中没有自然的运动模糊,我猜这会导致某种“运动模糊”(即,不是每帧一个球,而是每帧有五个球,追踪运动)。
我想我可以通过将帧提取为图像来实现这一点,并让我自己的自定义代码生成新帧,最后用新帧制作一个新的输出视频 - 但由于这可能需要“永远”的时间,所以我想知道:也许ffmpeg
(或其他开源工具)可以在“一行”中做到这一点?
答案1
来自@Mulvya 的链接https://video.stackexchange.com/q/16552/1871确实回答了这个问题ffmpeg
:
ffmpeg -i input \
-vf "tblend=average,framestep=2,tblend=average,framestep=2,setpts=0.25*PTS" \
-r srcfps -{encoding parameters} output
... 注意 (https://ffmpeg.org/ffmpeg-filters.html):
tblend(时间混合)过滤器从一个单一流中获取两个连续的帧,并输出将新帧混合到旧帧上所获得的结果。
所以仅有的将两帧混合在一起,这意味着要混合四帧,您必须重复tblend=average,framestep=2
两次,如上例所示。
但是,我想将 700 个输入帧图像混合到每个输出帧图像中(而且我怀疑tblend=average,framestep=2
重复 350 次以上是否能被正确解析ffmpeg
)。因此,我决定先解包这些帧,然后使用 Python 进行自己的处理。要解包:
mkdir ofrs # original frames
mkdir outfrs # out frames
ffmpeg -i myvideo.mp4 ofrs/img-%05d.png
...然后我使用这个python脚本python blendManyImages.py
;因为混合中每个图像具有相同的权重并没有产生我需要的图像特征,所以这个脚本使用一个公式,为流中较早的图像提供更大的权重:
python blendManyImages.py
:
# http://stackoverflow.com/questions/25102461/python-rgb-matrix-of-an-image
# http://stackoverflow.com/questions/40810716/how-to-get-a-list-of-float-rgba-pixels-values-using-pillow
from PIL import Image
import numpy
import math
# open an image, to get the data size:
im = Image.open('ofrs/img-00001.png')
#~ data = numpy.asarray(im)
data = numpy.array(im) # same as .asarray
print("Array dimensions: %s"%(repr(data.shape)))
data = data.astype(float)
print("[20, 30]=%s"%(repr(data[20, 30])))
#~ print(data)
#[[[240. 240. 240.]
# [240. 240. 240.] ...
#~ data = numpy.divide(data, 255.0)
#[[[ 0.94117647 0.94117647 0.94117647]
# [ 0.94117647 0.94117647 0.94117647] ...
# erase data:
data.fill(0)
#~ print(data)
inputframes = 44100
outptframes = 60
decimate = inputframes/outptframes # 735
k = 1.0/decimate # 0.001360
print(decimate, k)
i = 1 # input frame counter
o = 1 # output frame counter
while i <= 44100:
data.fill(0)
for dcnt in xrange(0, decimate):
ifname = "ofrs/img-%05d.png"%(i)
#print(ifname)
tdata = numpy.divide(numpy.array(Image.open(ifname)).astype(float), 255.0)
# manually tuned formula: give more weight to earlier frames
data += numpy.multiply(tdata, k*70*pow(math.e,-0.05*dcnt))
i = i+1
# data should be done here; save
ofname = "outfrs/img-%02d.png"%(o)
print(ofname)
oim = Image.fromarray(numpy.multiply(data, 255).astype('uint8')).convert('RGB')
oim.save(ofname)
o = o+1
一旦计算出这个输出帧图像序列,就可以制作视频,同样使用ffmpeg
:
ffmpeg -framerate 60 -i outfrs/img-%02d.png output.mp4