如何使用FFmpeg中的混合滤镜叠加两个视频

3

我需要按照以下规格制作很多视频:

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

我已经尝试了许多不同的命令进行测试,但总是出现错误。


1
展示你的命令和控制台输出。 - Gyan
2个回答

10

好的,我认为我在下一个命令中明白了:

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])上,并将结果保存在[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

就这些了。 如果有人能够解释一下这个缩放过滤器是如何工作的,我会非常感谢!


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

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