ffmpeg 视频合成,使用 alphamerge 对视频进行几何区域裁剪

做过视频合成的人都知道,视频合成的时候,有时候需要对视频进行裁剪,比如只需要视频的一部分,或者只需要视频的某个区域,这个时候就需要对视频进行裁剪。

如果只是要裁剪掉某个时间段,那比较简单,使用 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 来解释一下这行命令:

  1. -i digit.mp4:这是输入文件 digit.mp4,它是我们想要处理的视频文件。

  2. -i digit_mask.mp4:这是输入文件 digit_mask.mp4,它是一个视频文件,作为 digit.mp4 的遮罩(alpha 融合)。

  3. -i mask1920.png:这是输入文件 mask1920.png,它是一个图片文件,作为另一个遮罩。

  4. -i 1920.mp4:这是输入文件 1920.mp4,它是另一个视频文件,我们将在其上叠加遮罩。

  5. -filter_complex:这是复杂滤镜图形的开始。

  6. [0][1]alphamerge[vid]:这一步将 digit.mp4digit_mask.mp4 进行 alpha 融合,生成一个新的视频流 vid

  7. [2][vid]overlay[vid2]:这一步将 mask1920.png 和之前生成的 vid 进行叠加,生成另一个新的视频流 vid2。这一步是为了在数字人头像背后添加颜色形状。

  8. [2]fps=25,loop=999:size=1[mask1920_fps]:这一步将 mask1920.png 设置为持续循环的视频流,生成新的视频流 mask1920_fpsfps=25 设置 mask1920.png 的帧率为 25 帧/秒,loop=999:size=1mask1920.png 循环播放 999 次,但由于 size=1,实际上只有 1 帧。

  9. [mask1920_fps]format=rgba[msk]:这一步将之前生成的 mask1920_fps 转换为带有 alpha 通道的视频流,生成新的视频流 msk

  10. [msk]alphaextract[alfa]:这一步从视频流 msk 中提取 alpha 通道,生成新的视频流 alfa

  11. [vid2][alfa]alphamerge[rid]:这一步将 vid2alfa 进行 alpha 融合,得到一个新的视频流 rid。在这里,alfa 的 alpha 通道将被应用到 vid2 上,实现遮罩效果。

  12. [3:v][rid]overlay[out]:这一步将 1920.mp4rid 进行叠加,得到最终的输出视频流 out。在这里,rid 会覆盖 1920.mp4 的一部分区域,实现叠加效果。

  13. -map 1:a -c:a copy -map [out]:这一部分用于保留输入文件 digit_mask.mp4 的音频流,并将输出视频流 out 作为输出文件的视频流。

  14. -y z.mp4:这是输出文件的设置,z.mp4 是输出的视频文件名。

这样,整个命令实现了将 digit_mask.mp4mask1920.png 作为遮罩应用到 digit.mp41920.mp4 上,并输出为 z.mp4

相关推荐
y先森4 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy4 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189114 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿5 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡6 小时前
commitlint校验git提交信息
前端
虾球xz7 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇7 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒7 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员7 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐7 小时前
前端图像处理(一)
前端