做过视频合成的人都知道,视频合成的时候,有时候需要对视频进行裁剪,比如只需要视频的一部分,或者只需要视频的某个区域,这个时候就需要对视频进行裁剪。
如果只是要裁剪掉某个时间段,那比较简单,使用 ffmpeg 的 -ss 和 -t 参数就可以了,比如:
shell
ffmpeg -i input.mp4 -ss 00:00:10 -t 00:00:20 -c copy output.mp4
如果是只需要视频中的某个区域怎么办呢?比如做绿幕视频合成,例如下面这个绿幕视频,其中内容是一只老虎,如果要将老虎叠加到另一个森林视频中合成。
这种视频可以使用 ffmpeg chromakey 滤镜来处理,根据色键来去除绿幕,然后叠加到其他视频上。
shell
ffmpeg -i tiger.mp4 -i forest.mp4 -shortest -filter_complex "[1:v]scale=1920:1080,chromakey=0x15ff09:0.08:0.0[ckout];[0:v][ckout]overlay[out]" -map "[out]" -y output.mp4
这个命令中的 chromakey=0x15ff09:0.08:0.0 是一个 FFmpeg 中的滤镜,用于将视频中的某个颜色替换成透明。其中 0x15ff09 是要替换的颜色,0.08 是颜色的容差,0.0 是透明度。具体来说,这个滤镜会将颜色值为 0x15ff09 的像素替换成透明像素,容差为 0.08,透明度为 0.0。
但是这种方式的处理效果通常不太理想,如果主体形象中有绿色的部分,那么这部分也会被去除,导致主体形象出现空洞。
一般更建议使用 ffmpeg 的 alphamerge 滤镜来处理,如果要将 A.mp4 和 B.mp4 两个视频叠加合成。一般需要提供 A_mask.mp4 这样的视频,这个视频中的内容和 A.mp4 类似,包含其中的透明通道信息,如下所示:
可以使用下面的命令来合成视频:
shell
ffmpeg -i digit.mp4 -i digit_mask.mp4 -i 1920.mp4 -filter_complex '[1][0]scale2ref[mask][main];[main][mask]alphamerge[vid];[vid][2:v]scale2ref=w=iw/2:h=ih/2[origin][digit];[digit][origin]overlay=x=-200:y=540[out]' -map 1:a -c:a copy -map [out] -y output.mp4
这种 mask 视频一般是和原视频一起生成的,时长也相同,这种 mask 视频就是专门用来抠像的,将视频中的绿幕去除,然后叠加到其他视频上。
那么如果我需要在视频中裁剪出一个区域,然后叠加到其他视频上,又该如何实现呢?
比如在人物的头部区域增加一个灰色的圆形区域,或者是圆角矩形,正方形等几何图形等。
依然可以使用 alphamerge 滤镜来实现, 在上一个命令的基础上,我们还需要动态生成一个包含几何区域的 PNG 图片来裁剪图形,除几何区域外,其他内容都是透明的。
现在,除了有 mask 视频之外,还有一个图片作为遮罩,需要使用两次 alphamerge 滤镜。现将人像抠出来,再在人像头部区域后面添加一个圆形区域,ffmpeg 合成命令如下:
shell
ffmpeg -i digit.mp4 -i digit_mask.mp4 -i mask1920.png -i 1920.mp4 -filter_complex '[0][1]alphamerge[vid];[2][vid]overlay[vid2];[2]fps=25,loop=999:size=1[mask1920_fps];[mask1920_fps]format=rgba[msk];[msk]alphaextract[alfa];[vid2][alfa]alphamerge[rid];[3:v][rid]overlay[out]' -map 1:a -c:a copy -map [out] -y z.mp4
上面的命令需要的全部资源都在这里:
我们再借助 ChatGPT 来解释一下这行命令:
-
-i digit.mp4
:这是输入文件digit.mp4
,它是我们想要处理的视频文件。 -
-i digit_mask.mp4
:这是输入文件digit_mask.mp4
,它是一个视频文件,作为digit.mp4
的遮罩(alpha 融合)。 -
-i mask1920.png
:这是输入文件mask1920.png
,它是一个图片文件,作为另一个遮罩。 -
-i 1920.mp4
:这是输入文件1920.mp4
,它是另一个视频文件,我们将在其上叠加遮罩。 -
-filter_complex
:这是复杂滤镜图形的开始。 -
[0][1]alphamerge[vid]
:这一步将digit.mp4
和digit_mask.mp4
进行 alpha 融合,生成一个新的视频流vid
。 -
[2][vid]overlay[vid2]
:这一步将mask1920.png
和之前生成的vid
进行叠加,生成另一个新的视频流vid2
。这一步是为了在数字人头像背后添加颜色形状。 -
[2]fps=25,loop=999:size=1[mask1920_fps]
:这一步将mask1920.png
设置为持续循环的视频流,生成新的视频流mask1920_fps
。fps=25
设置mask1920.png
的帧率为 25 帧/秒,loop=999:size=1
将mask1920.png
循环播放 999 次,但由于size=1
,实际上只有 1 帧。 -
[mask1920_fps]format=rgba[msk]
:这一步将之前生成的mask1920_fps
转换为带有 alpha 通道的视频流,生成新的视频流msk
。 -
[msk]alphaextract[alfa]
:这一步从视频流msk
中提取 alpha 通道,生成新的视频流alfa
。 -
[vid2][alfa]alphamerge[rid]
:这一步将vid2
和alfa
进行 alpha 融合,得到一个新的视频流rid
。在这里,alfa
的 alpha 通道将被应用到vid2
上,实现遮罩效果。 -
[3:v][rid]overlay[out]
:这一步将1920.mp4
和rid
进行叠加,得到最终的输出视频流out
。在这里,rid
会覆盖1920.mp4
的一部分区域,实现叠加效果。 -
-map 1:a -c:a copy -map [out]
:这一部分用于保留输入文件digit_mask.mp4
的音频流,并将输出视频流out
作为输出文件的视频流。 -
-y z.mp4
:这是输出文件的设置,z.mp4
是输出的视频文件名。
这样,整个命令实现了将 digit_mask.mp4
和 mask1920.png
作为遮罩应用到 digit.mp4
和 1920.mp4
上,并输出为 z.mp4
。