写点什么

moviepy 音视频剪辑:视频剪辑基类 VideoClip 的属性及方法详解

用户头像
老猿Python
关注
发布于: 2021 年 03 月 22 日
moviepy音视频剪辑:视频剪辑基类VideoClip的属性及方法详解

、概述

在《moviepy音视频剪辑:moviepy中的剪辑基类Clip详解》和《[moviepy 音视频剪辑:moviepy 中的剪辑基类 Clip 的属性和方法详解](https://blog.csdn.net/LaoYuanPython/article/details/106452603)》介绍了剪辑相关类及类关系。可以看到视频剪辑类 VideoClip 是其中非常重要的一个剪辑类,它主要有六个直接子类(VideofileClip、 ImageSequenceClip、CompositeVideoClip、ImageClip、DataVideoClip、UpdatedVideoClip)和两个间接子类(ColorClip, TextClip)。


二、VideoClip 的构造方法和属性

2.1、构造方法

2.1.1、构造方法语法:

__init__(self, make_frame=None, ismask=False, duration=None, has_constant_size=True)


2.1.2、参数释义

- [ ] makeframe:帧的构建方法,帧的构建方法用于根据时间构建帧,该方法是 getframe 获取帧时调用的方法。帧的构建可以从已有剪辑中获取或变换,也可以代码自己填充;

- [ ] ismask:是否作为遮罩使用

- [ ] duration:构建剪辑的时长

- [ ] hasconstantsize:表示是否所有帧大小都是相同,如果是动态图像,该值必须为 False,该值用于增加遮罩时使用,如果固定大小,遮罩大小就是剪辑的大小,如果不是,则遮罩大小需要加遮罩的视频帧取对应帧的大小。


2.2、size 属性

剪辑的大小和分辨率,是一个二元组,内容为:(宽度,高度),单位是像素,直接通过属性名访问。


2.3、w,h 属性

w,h 属性即剪辑的宽和高,单位是像素,实际这两个属性就是从 size 属性获取的。属性访问直接通过属性名访问。


2.4、ismask 属性

布尔类型表示剪辑是否为遮罩,该属性在构造方法中传入。


2.5、make_frame 属性

帧的构建方法,通过构造方法传入或 setmakeframe 方法设置,帧的构建方法用于根据时间构建帧,该方法是 get_frame 获取帧时调用的方法。帧的构建可以从已有剪辑中获取或变换,也可以代码自己填充。


2.6、mask 属性

当一个视频帧有遮罩时,使用该属性记录遮罩的剪辑。如果为 None,则视频剪辑完全不透明。可以通过 addmask、setopacity 等方法来构建剪辑的遮罩,也可以通过 set_mask 来将已有的剪辑设置为视频剪辑的遮罩。


2.7、aspect_ratio 属性

aspect_ratio 属性为剪辑的纵横比,实际上就是剪辑的宽/高。注意该属性为浮点数,只读,通过属性名访问。


三、VideoClip 的访问方法

3.1、save_frame 方法

save_frame 方法调用语法如下:

save_frame(self, filename, t=0, withmask=True)


该方法用于将 t 指定时刻位置的帧保存到指定图像文件,t 表示方法可以是如下四种之一:


1. 秒,为一个浮点数数字,如 75.35

2. 分钟和秒组成的元组,如(1,15.35)

3. 时、分、秒组成的元组,如(0,1,15.35)

4. 用冒号分隔的时间字符串,如‘0:1:15.35’


如果 withmask 为 True,对应帧的遮罩会被写入图片的 alpha 通道层,仅对 PNG 图像有效。

###### 注:

图像的 alpha 通道一般用作不透明度参数。如果一个像素的 alpha 通道数值为 0%,那它就是完全透明的(也就是看不见的),而数值为 100%则意味着一个完全不透明的像素(传统的数字图像)。在 0%和 100%之间的值则使得像素可以透过背景显示出来,就像透过玻璃(半透明性),它使数码合成变得容易。alpha 通道值可以用百分比、整数或者像 RGB 参数那样用 0 到 1 的实数表示。


3.2、write_videofile 方法

write_videofile 方法用于将视频剪辑输出到文件,调用语法如下:

write_videofile(self, filename, fps=None, codec=None,                        bitrate=None, audio=True, audio_fps=44100,                        preset="medium",                        audio_nbytes=4, audio_codec=None,                        audio_bitrate=None, audio_bufsize=2000,                        temp_audiofile=None,                        rewrite_audio=True, remove_temp=True,                        write_logfile=False, verbose=True,                        threads=None, ffmpeg_params=None,                        logger='bar')
复制代码

###### 参数说明如下:


- filename:视频文件名,只要是 ffmpeg 支持的视频文件如 .ogv, .mp4, .mpeg, .avi, .mov 等都可以

- fps:帧率,每秒编码的帧数

- codec:用于图像编码的编解码器,可以是 ffmpeg 支持的任何编解码器。如果文件名的扩展名为“.mp4”、“.ogv”、“.webm”,则会相应地设置编解码器,但如果不喜欢默认值,则仍可以进行设置。对于其他扩展名,必须相应地设置输出文件名。一些常用的编解码器如下:

- 'libx264':视频压缩效果好的一款编解码器,MP4 的缺省编解码器,视频质量通过 bitrate 参数调节

- 'mpeg4':一种可选的 MP4 编解码器,可以替代'libx264',可以获得更好的视频质量

- 'rawvideo':完美的视频质量,但文件会巨大,对应视频文件为'.avi'

- 'png':完美的视频质量,对应视频文件为'.avi',但文件大小比'rawvideo'小

- 'libvorbis':是一种完全开放、免费的编解码器,有不错的视频格式,但是要不广,对应视频文件为'.ogv'

- 'libvpx':一种很适合在 HTML5 中使用的网络视频轻量级编开源解码器,对应视频文件为'.webm'

- bitrate:输出视频的比特率,也即码率 BPS(Bits Per Second),指每秒传送的数据位数

- audio:可以为 True、False 或文件名,如果 True 且剪辑附加了音频,则音频将作为视频的音频保存,如果为 False 则不保存音频,如果为音频文件名则将此音频文件将作为视频的音频

- audio_fps:声音的采样频

- preset:设置 FFMPEG 用于优化压缩的时间。字符串类型,可选值有:ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、 placebo。请注意,这不会影响视频的质量,只影响视频文件的大小。所以如果赶时间而文件大小不是很重要可以设置为 ultrafast

- audio_nbytes:音频的采用的位数,对应基于字节为单位就是声道数;

- audiocodec:音频解码器,例如'.mp3'的'libmp3lame'、'ogg'的'libvorbis'、 'm4a'的'libfdkaac'、 'pcms16le' 16 位声音和'pcms32le'的 32 位声音。默认值为“libmp3lame”,除非视频扩展名为“ogv”或“webm”,在这 2 种情况下,默认值为“libvorbis”。

- audio_bitrate:音频比特率,字符串形式,如“50k”、“500k”、“3000k”,用于将确定输出文件中音频的大小/质量。请注意,这主要是一个指示性目标,输出文件的比特率不一定会按此设置。

- audio_bufsize:音频缓冲区大小

- temp_audiofile:如果输出由音频,则该参数用于指定要生成并合并到电影中的临时音频文件的名称,如果没有指定则用缺省模式的临时文件名

- rewrite_audio:这个参数目前没有作用,估计是为了兼容以前的版本

- remove_temp:是否删除临时文件

- write_logfile:如果为 True,将为音频和视频输出记录日志文件。日志文件将以“.log”结尾,包含输出文件的名称

- verbose:已经废弃使用,留下来是为了兼容性,以前用于打开/关闭消息。现在使用 logger=None。

- threads:用于 ffmpeg 的线程数,可以加快多核计算机上视频输出的速度

- ffmpeg_params:需额外传递的其他 ffmpeg 参数,用列表传递,形如:['-option1','value1','-option2','value2']

- logger:字符串类型,"bar"表示进度条、None 表示不设置、或任何程序日志记录器的名字


3.3、writeimagessequence 方法

writeimagessequence 方法用于将剪辑输出到一系列文件中,调用语法如下:


write_images_sequence(self, nameformat, fps=None, verbose=True,withmask=True, logger='bar')
复制代码


参数说明如下


  • nameformat:输出格式和文件名规则,指定了文件系列序号的数字格式和图片类型扩展名的文件名,例如文件名的“frame%03d.png”表示文件名开头为“frame”,后面“%03d”表示文件顺序号以 3 位数字来顺序编号,文件名后缀“png”表示编码格式为 PNG。文件名格式还可以带路径方式,如“目录名\\f%04d.jpeg”等。但要求目录名必须已存在,另外如果输出的文件数比设置的序列号范围要多,则会自动往上加 1 扩展,直到所有内容都输出完成

  • fps:每秒输出帧数,如果没指定则按剪辑的 fps 进行输出

  • withmask:是否将遮罩作为图像的 alpha 通道输出,仅对 png 图像格式有效

  • verbose:是否输出处理信息

  • logger:字符串类型,"bar"表示进度条、None 表示不设置、或任何程序日志记录器的名字


3.4、write_gif 方法

write_gif 将剪辑转换成 gif 动画输出到文件中,调用语法:


def write_gif(self, filename, fps=None, program='imageio',                  opt='nq', fuzz=1, verbose=True,                  loop=0, dispose=False, colors=None, tempfiles=False,                  logger='bar'):
复制代码


###### 参数说明如下:


  • program:用于转换的软件,可以是“imageio”(这将通过 imageio 使用 FreeImage 库),或者是“ImageMagick”,或者是“ffmpeg”

  • opt:应用优化的选项,如果 program 参数是'imageio',opt 必须是'wu'(Wu)或“nq”(Neuquant),。如果 program='ImageMagick',opt 可以是“optimizeplus”或“OptimizeTransparency”

  • fuzz:仅当 program='ImageMagick'时需要,通过考虑小于 fuzz%的颜色差异实际上是相同的来压缩 GIF 文件大小

  • loop:表示 GIF 文件播放时循环播放多少次,如果为 0 就一直不停地播放,否则播放设定次数后就停止,该参数由 GIF 文件头控制

  • dispose:表示播放动画时渲染当前帧时,如何处理前一帧,该参数由 GIF 文件头控制,moviepy 没有说明该参数怎么使用,缺省值为 False,老猿查阅了相关资料,才基本确认该参数的作用,但 GIF 中该控制参数有四个取值,不知道是否都支持,取值及含义如下:

- 为 0 表示绘制一个完整大小的、不透明的 GIF 帧来替换上一帧,就算连续的两帧只在局部上有细微的差异,每一帧依然是完整独立的绘制

- 为 1 表示未被当前帧覆盖的前一帧像素将继续显示,这种方式常用于对 GIF 动画进行优化,当前帧只需在上一帧的基础上做局部刷新,上一帧中没有被当前帧覆盖的像素区域将继续展示。这种方式既能节省内存,也能提高解码速度

- 为 2 表示绘制当前帧之前,会先把前一帧的绘制区域恢复成背景色,这种方式常用于优化很多帧背景相同的情况,上一帧的背景色能通过当前帧的透明区域显示

- 为 3 表示绘制当前帧时,会先恢复到最近一个设置为 False 或 1 的帧,然后再将当前帧叠加到上面,这种方式性能比较差,已经被慢慢废弃

  • colors:关于这个参数 moviepy 没有说明,老猿将该值设置为一个比较大的值,结果报错“ValueError: GIF quantize param must be 2..256”,最后查阅资料确认该参数表示色彩量化使用的调色板索引,取值为 2 到 256。GIF 最高支持 8 位 256 色,那么如果原图是真彩色的,则在生成最终效果图时,就涉及到真彩色到 256 的降色。真彩色是 24 位的,有 2 的 24 种颜色,每个像素用 3 个字节标识一个颜色,R、G、B 各占一个字节,而 256 色每个像素只用一个字节从调色板中索引一种颜色,调色板最多有 256 种颜色。将 2^24 种颜色降为 256 种颜色,降色的过程被成为色彩量化。色彩量化过程分两步:1、根据图片定制调色板;2、遍历像素,对于每一个像素,从调色板中找最接近的颜色,记录该颜色索引。关于调色板请参考《调色板详解

  • tempfiles:将每个帧写入一个文件,而不是将它们传递到 RAM 中。在内存很少的计算机上很有用,只能与 ImageMagick 或 ffmpeg 一起使用。


3.5、subfx 方法

subfx 方法用于对剪辑指定时间段进行变换,返回该段剪辑变换后的剪辑和原剪辑其他段拼接后的新剪辑,剪辑的时长会自动调整。语法如下:

subfx(self, fx, ta=0, tb=None, **kwargs)

参数说明:

- fx:用于对剪辑进行变换处理的函数名,这些函数可以是自定义函数,也可以是 moviepy.video.fx 包下的模块内定义好的可以直接使用的函数,以及其他可能的函数

- ta:剪辑段开始位置

- tb:剪辑段结束位置,如果 tb 为 None,则 tb 被设置为原剪辑的 duration,如果 tb 为负数,则 tb 被设置为剪辑的 duration + tb

- kwargs,调用 fx 函数时需要传入的关键字参数


subfx 实际上是调用基类 Clip 的 fx 方法来实现的,关于 Clip 的 fx 方法请参考《moviepy音视频剪辑:moviepy中的剪辑基类Clip的属性和方法详解》。


3.6、fl_image 方法

flimage 方法是对 getframe 方法获取的帧进行变换的方法,本质上是《moviepy音视频剪辑:moviepy中的剪辑基类Clip详解》介绍的 fl 方法在内容变换方面的一种变种。

###### 调用语法:fl_image(self, image_func, apply_to=None)

###### 参数说明:

- imagefunc:参数 imagefunc 是对剪辑帧进行图像变换的函数,带一个参数,参数就是要处理的帧,这个帧直接通过 getframe 去获取,imagefunc 函数的返回值为经过变换后的帧

- applyto:applyto 表示变换是否需要同时作用于剪辑的音频和遮罩,其值可以为’mask’、‘audio’、[‘mask’,‘audio’]


对比 fl 方法的调用方法 fl(self, fun, applyto=None, keepduration=True):


- flimage 由于只变换内容,因此不涉及时间的变换,keepduration 就是默认为 True

- imagefunc 不带时间参数,这是因为系统默认调用 getframe(t)来获取帧,无需 image_func 带时间参数

- fl_image 本质上是执行如下语句来完成帧内容的变换:fl(lambda gf, t: image_func(gf(t)), apply_to)


注意:

imagefunc 参数对应的帧数组是只读的,不能修改,实际上 getframe(t)返回的所有帧数组都是只读的。帧的类型为 numpy.ndarray,而 numpy.ndarray 直接定义的数据是可修改的,为什么帧数据不能修改笔者暂时还没弄明白(报错 ValueError: assignment destination is read-only),为了规避该问题,将参数 img 数据采用如下形式的赋值语句:frame= np.array(img)就可以对新的变量 frame 进行修改,所有变换可以针对新变量 frame 进行,返回也必须是新变量 frame。


3.7、fill_array 方法

fillarray 方法是用来进行多个视频合成时处理帧的,更多是一个 moviepy 内部使用的方法,但当应用需要对帧进行变换时也可以调用。fillarray 将 pre_array 的宽和高设置为参数 shape 对应的数据。

调用语法:fillarray(self, prearray, shape=(0, 0))

参数说明


- prearray:要处理的数据,结构必须为类似帧的三维数组,其对应的宽和高在 prearray.shape[0::1]内

- shape:需要将 pre_array 变换到的数组维度,shape 实际上对应帧的新的宽和高


说明

fillarray 处理数据时,如果发现 shape 对应的宽或高大于 prearray 本身的宽或高,则扩展 prearray 的宽或高,扩展的位置使用[1,1,1]填充。如果 shape 对应的宽或高小于 prearray 本身的宽或高,则对 pre_array 的宽或高超出的数据进行丢弃处理。


3.8、add_mask 方法

add_mask 方法就是给剪辑增加遮罩,遮罩的 duration 是调用者的 duration,遮罩是由完全不透明(全 1 组成的 YUV 值)的像素构成。调用语法非常简单:add_mask(self)


add_mask 方法就是将给定剪辑完全遮挡,并返回被遮挡后的剪辑。


3.9、on_color 方法

on_color 方法用于将当前剪辑放置到一个指定颜色背景的可能更大的剪辑上,用于在原始剪辑扩展大小时将空白处设置为指定颜色。返回值为处理后的新剪辑。

调用语法如下


on_color(self, size=None, color=(0, 0, 0), pos=None,   col_opacity=None)
复制代码

参数说明

- size:是(宽度,高度)的二元组,如果没有设置缺省为调用剪辑的大小

- color:设定的背景色 RGB 颜色组

- pos:原剪辑对应的剪辑在新剪辑的框架上的位置,请见下面函数 set_position 的说明

- col_opacity:以背景色构造的底部剪辑的不透明度,取值为 0 到 1 的浮点数,如果为 0 表示完全透明,为 1 表示完全不透明,其他表示不透明度的比率。这个参数对新剪辑中原剪辑对应内容没有作用,仅用于底部背景色构造的剪辑,下图蓝色边框是透明度为 0.6 时背景色案例



3.10、setmakeframe 方法

setmakeframe 方法用于设置剪辑帧构建的 makeframe 方法,makeframe 方法在 getframe 中被调用来返回指定位置的帧内容。setmake_frame 方法非常简单,调用语法如下:set_make_frame(self, mf),参数 mf 为剪辑帧的构建方法名,除 self 外,带一个 t 参数。


注意


  • setmakeframe 方法在父类 Clip 中也有,在此重写除了实现父类相同的功能外,同时在设置 makeframe 方法,马上会调用 getframe 更新剪辑的 size 属性

  • 修改 makeframe 改动的不是原剪辑,而是返回一个设置了 makeframe 方法的原剪辑的拷贝对应的新剪辑,这是 moviepy 几乎所有设置方法的特点,一定要用返回的新剪辑覆盖到操作的剪辑变量!不过开发团队也准备在后续版本中进行改变,但至少到现在最新的 1.03 版本这点是没有变化的。


3.11、set_audio 方法

set_audio 方法将原剪辑的拷贝剪辑的音频设置为参数指定音频后返回新剪辑。调用语法:set_audio(self, audioclip)


3.12、set_mask 方法

set_mask 方法将原剪辑的拷贝剪辑的遮罩设置为参数指定剪辑后返回新剪辑。调用语法:set_mask(self, mask),参数 mask 是调用对象用于遮罩的剪辑。


3.13、set_opacity 方法

set_opacity 方法将原剪辑拷贝剪辑遮罩的每个元素的值与参数值相乘后返回,实际上就是调整遮罩剪辑帧的 YUV 值。调用语法:set_opacity(self, op),其中参数 op 表示透明度或不透明度,为任何浮点数,一般设置为【0,1】区间的一个值。


3.14、set_position 方法

set_position 方法用于多个剪辑合成一个剪辑时设置调用剪辑实例的拷贝在合成剪辑的位置。

调用语法

set_position(self, pos, relative=False)

参数说明


  • pos:剪辑需要放置的位置,可以是如下方式取值:

- (x,y):x,y 用于指定剪辑左上角在合成剪辑的坐标位置

- ("center","top"):设定水平居中,垂直位置到顶部,类似的设置还有'bottom'、'right'、'left'

- (factorX,factorY):基于剪辑的大小设置相对位置, factorX 和 factorY 为(0,1)之间的浮点数,计算位置时是以 factorX 乘以剪辑的宽,factorY 乘以剪辑的高来计算位置,这里剪辑的宽和高是老猿认为应该是最终生成剪辑的宽和高

- x 和 y 的=的值可以是前三种的组合,x 和 y 可以用不同的方式来设置

- f(t)->(x,y):为一个通过时间计算该时刻指定剪辑左上角在合成剪辑的坐标位置


  • relative:是否相对位置,如果 pos 使用 factorX 或 factorY 时,relative 需要设置为 True


3.15、to_ImageClip 方法

to_ImageClip 方法将剪辑对应时刻 t 的帧转换成 ImageClip 图像剪辑,图像剪辑是所有帧都是固定图像数据的剪辑,所有帧都对应为图像数据。


调用语法

to_ImageClip(self, t=0, with_mask=True, duration=None)


说明

参数非常简单,不单独解释,但注意图像剪辑在输出到文件时需要设置 duration 和 fps 值(为 1 即可),同时可能在输出文时要指定 codec 类型,否则可能播放失败。


3.16、to_mask 方法

to_mask 方法返回一个由调用者剪辑实例构建的遮罩剪辑。

调用语法

to_mask(self, canal=0)

说明

to_mask 方法用于将当前剪辑生成一个遮罩剪辑,处理时如果调用对象本身有遮罩,则直接返回调用剪辑的遮罩,否则根据调用剪辑的数据生成遮罩数据,生成时是将调用剪辑的每一帧数据的具体像素的 YUV 值中的某个除以 255 来实现遮罩的效果,具体对 YUV 哪个数据进行处理由参数 canal 指定,0 代码 Y 值、1 代表 U 值、2 代表 V 值。


3.17、to_RGB 方法

返回一个由遮罩剪辑生成的非遮罩剪辑。

调用语法

to_RGB(self)

说明

该方法的处理过程是,如果调用剪辑不是遮罩,则直接返回自身,否则将剪辑的帧像素 YUV 各乘以 255,再将每个像素的 YUV 三元组变成一个九元组,其元素是 YUV 值重复 3 遍。


这样变换的原因老猿并不十分清楚,查阅了一些资料,估计是因为 YUV 到 RGB 并不是简单 YUV 到 RGB 的一个转换,而是到 24 位真彩色的转换,因为一般来说直接采集到的视频数据是 RGB24 的格式,其位数是 YUV 的三倍,当 RGB24 变为 YUV 时其实是进行了降色处理,现在要恢复到 RGB24 因此需要进行乘以 3。


但这里有些原理没说清楚,比如 RGB24 是用三个字节来表示颜色,YUV 在这里也用了三个字节,RGB 为什么变成了 9 个字节?这个问题一时无解,先留着。


另外这个方法在 moviepy 中只是对遮罩进行处理,当带遮罩的剪辑输出到文件或将剪辑的帧保存到图像或 gif 文件时会调用该方法对剪辑的遮罩进行处理。


3.18、without_audio 方法

without_audio 方法就是将剪辑拷贝后的声音去除,除了 self 不带其他参数,返回一个去除了声音的新剪辑。


3.19、afx 方法

afx 方法对原剪辑浅拷贝后的拷贝剪辑的声音进行变换,返回新剪辑。


调用语法

afx(self, fun, *a, **k)


说明

  • 声音变换由函数 fun 进行

  • a 和 k 是 fun 变换函数需要带的可变参数和关键字参数

  • afx 实际上是调用父类 Clip 的 fx 方法去执行 fun 函数的


四、小结

本文详细介绍了视频剪辑基类 VideoClip 的构造方法、属性和相关处理方法,相关内容参考了 moviepy.video.VideoClip.py 的文档字符串以及源代码,并针对部分疑难点进行了资料查询和测试,相关内容的探索和写作断断续续持续了一个多星期,作为一个类对象的介绍来说已经比较全面了。


VideoClip 很多方法如 saveframe、writevideofile、writeimagessequence、writegif 可以用于输出视频中的对应数据,而 subfx、flimage、addmask、oncolor、set_opacity 等是进行视频变换的重要方法。


在文中对部分方法举例进行了运用,但在哪些场景怎么去使用这些方法没有系统介绍,将在后面关于运用场景的文章中进行部分方法使用的介绍。


更多 moviepy 的介绍请参考《PyQt+moviepy音视频剪辑实战文章目录》或《[moviepy 音视频开发专栏](https://blog.csdn.net/laoyuanpython/category_10232926.html)》。


如果对文章内容存在疑问,可以在博客评论区留言,或关注:老猿 Python 微信公号发消息咨询。


发布于: 2021 年 03 月 22 日阅读数: 15
用户头像

老猿Python

关注

学问无遗力,功夫老始成。 2020.08.21 加入

CSDN 2020年博客之星季军、高级程序员、超50万行C语言项目开发经验 擅长领域:Python语言、PyQt界面程序开发、Moviepy音视频剪辑、OpenCV-Python图像处理、爬虫、5G、区块链、人工智能数学基础

评论

发布
暂无评论
moviepy音视频剪辑:视频剪辑基类VideoClip的属性及方法详解