使用复合合并帧(平均//“运动模糊”)来加速视频?

使用复合合并帧(平均//“运动模糊”)来加速视频?

基本上,我想加快视频速度(通常是一些基于数学的东西,例如使用源代码进行弹跳球处理的示例 - 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

相关内容