如何在ffmpeg中使用混合滤镜叠加两个视频

时间:2016-04-16 17:37:21

标签: filter ffmpeg blend blending

我需要制作很多具有下一个规格的视频:

  • 背景视频(bg.mp4)
  • 将一系列png图像img1.png叠加到img300.png(img%d.png),速率为30 fps
  • 使用混合调光滤镜(dust.mp4)
  • 覆盖带有防尘效果的视频
  • 将所有输入缩放到1600x900,如果输入没有宽高比,则裁剪它们。
  • 将输出视频的持续时间指定为10秒(图像序列的持续时间为30fps)。

我正在使用不同的命令进行大量测试但总是显示错误。

2 个答案:

答案 0 :(得分:4)

嗯,我想我在下一个命令中得到了它:

ffmpeg -ss 00:00:18.300 -i music.mp3 -loop 1 -i bg.mp4 -i ac%d.png -i dust.mp4 -filter_complex "[1:0]scale=1600:ih*1200/iw, crop=1600:900[a];[a][2:0] overlay=0:0[b]; [3:0] scale=1600:ih*1600/iw, crop=1600:900,setsar=1[c]; [b][c] blend=all_mode='overlay':all_opacity=0.2" -shortest -y output.mp4

我要解释一下,为了分享我发现的东西:

  • 声明输入:

ffmpeg -ss 00:00:18.300 -i music.mp3 -loop 1 -i bg.mp4 -i ac%d.png -i dust.mp4

  • 添加过滤器组合。第一部分:[1,0]是输入的第二个元素(bg.mp4)和缩放以获得最大值,然后使用我需要的大小进行裁剪,这个操作的结果是在[a]元素中

[1:0] scale = 1600:ih * 1600 / iw,crop = 1600:900,setsar = 1 [a];

  • 第二部分:将PNG序列放在已调整大小的视频上(bg.mp4,现在为[a])并将resunt保存在[b]元素中。

[a] [2:0] overlay = 0:0 [b];

  • 缩放和裁剪第四个输入(overlay.mp4)并保存在[c]元素中。

[3:0] scale = 1600:ih * 1600 / iw,crop = 1600:900,setsar = 1 [c];

  • 使用“叠加”混合模式将第一个结果与叠加视频混合,并且不透明度为0.1,因为视频具有灰色调并使结果太暗。

[b] [c] blend = all_mode ='overlay':all_opacity = 0.1

这就是全部。 如果有人可以解释这个缩放过滤器是如何工作的,我会非常感谢!

答案 1 :(得分:0)

我需要处理一堆图像,并且无法使ffmpeg可靠地为我工作,因此我构建了一个Python工具来帮助调解该过程:

#!/usr/bin/env python3
import functools
import numpy as np
import os
from PIL import Image, ImageChops, ImageFont, ImageDraw
import re
import sys
import multiprocessing
import time

def get_trim_box(image_name):
  im = Image.open(image_name)
  bg = Image.new(im.mode, im.size, im.getpixel((0,0)))
  diff = ImageChops.difference(im, bg)
  diff = ImageChops.add(diff, diff, 2.0, -100)
  #The bounding box is returned as a 4-tuple defining the left, upper, right, and lower pixel coordinate. If the image is completely empty, this method returns None.
  return diff.getbbox()



def rect_union(rect1, rect2):
  left1, upper1, right1, lower1 = rect1
  left2, upper2, right2, lower2 = rect2
  return (
    min(left1,left2),
    min(upper1,upper2),
    max(right1,right2),
    max(lower1,lower2)
  )



def blend_images(img1, img2, steps):
  return [Image.blend(img1, img2, alpha) for alpha in np.linspace(0,1,steps)]



def make_blend_group(options):
  print("Working on {0}+{1}".format(options["img1"], options["img2"]))
  font = ImageFont.truetype(options["font"], size=options["fontsize"])
  img1 = Image.open(options["img1"], mode='r').convert('RGB')
  img2 = Image.open(options["img2"], mode='r').convert('RGB')
  img1.crop(options["trimbox"])
  img2.crop(options["trimbox"])
  blends = blend_images(img1, img2, options["blend_steps"])
  for i,img in enumerate(blends):
    draw = ImageDraw.Draw(img)
    draw.text(options["textloc"], options["text"], fill=options["fill"], font=font)
    img.save(os.path.join(options["out_dir"],"out_{0:04}_{1:04}.png".format(options["blendnum"],i)))



if len(sys.argv)<3:
  print("Syntax: {0} <Output Directory> <Images...>".format(sys.argv[0]))
  sys.exit(-1)

out_dir     = sys.argv[1]
image_names = sys.argv[2:]

pool = multiprocessing.Pool()

image_names = sorted(image_names)
image_names.append(image_names[0]) #So we can loop the animation

#Assumes image names are alphabetic with a UNIX timestamp mixed in.
image_times = [re.sub('[^0-9]','', x) for x in image_names]
image_times = [time.strftime('%Y-%m-%d (%a) %H:%M', time.localtime(int(x))) for x in image_times]

#Crop off the edges, assuming upper left pixel is representative of background color
print("Finding trim boxes...")
trimboxes = pool.map(get_trim_box, image_names)
trimboxes = [x for x in trimboxes if x is not None]
trimbox   = functools.reduce(rect_union, trimboxes, trimboxes[0])

# #Put dates on images
testimage = Image.open(image_names[0])
font      = ImageFont.truetype('DejaVuSans.ttf', size=90)
draw      = ImageDraw.Draw(testimage)
tw, th    = draw.textsize("2019-04-04 (Thu) 00:30", font) 
tx, ty    = (50, trimbox[3]-1.1*th)   # starting position of the message

options = {
  "blend_steps": 10,
  "trimbox":     trimbox,
  "fill":        (255,255,255),
  "textloc":     (tx,ty),
  "out_dir":     out_dir,
  "font":        'DejaVuSans.ttf',
  "fontsize":    90
}

#Generate pairs of images to blend
pairs = zip(image_names, image_names[1:])
#Tuple of (Image,Image,BlendGroup,Options)
pairs = [{**options, "img1": x[0], "img2": x[1], "blendnum": i, "text": image_times[i]} for i,x in enumerate(pairs)]

#Run in parallel
pool.map(make_blend_group, pairs)

这会产生一系列图像,可以将其制作成视频,如下所示:

ffmpeg -pattern_type glob -i "/z/out_*.png" -pix_fmt yuv420p -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" -r 30 /z/out.mp4