在《moviepy音视频剪辑:moviepy中的剪辑基类Clip详解》和《moviepy音视频剪辑:moviepy中的剪辑基类Clip的属性和方法详解》介绍了剪辑相关类及类关系。可以看到视频剪辑类VideoClip是其中非常重要的一个剪辑类,它主要有六个直接子类(VideofileClip、 ImageSequenceClip、CompositeVideoClip、ImageClip、DataVideoClip、UpdatedVideoClip)和两个间接子类(ColorClip, TextClip)。
__init__(self, make_frame=None, ismask=False, duration=None, has_constant_size=True)
剪辑的大小和分辨率,是一个二元组,内容为:(宽度,高度),单位是像素,直接通过属性名访问。
w,h属性即剪辑的宽和高,单位是像素,实际这两个属性就是从size属性获取的。属性访问直接通过属性名访问。
布尔类型表示剪辑是否为遮罩,该属性在构造方法中传入。
帧的构建方法,通过构造方法传入或set_make_frame方法设置,帧的构建方法用于根据时间构建帧,该方法是get_frame获取帧时调用的方法。帧的构建可以从已有剪辑中获取或变换,也可以代码自己填充。
当一个视频帧有遮罩时,使用该属性记录遮罩的剪辑。如果为None,则视频剪辑完全不透明。可以通过add_mask、set_opacity等方法来构建剪辑的遮罩,也可以通过set_mask来将已有的剪辑设置为视频剪辑的遮罩。
aspect_ratio属性为剪辑的纵横比,实际上就是剪辑的宽/高。注意该属性为浮点数,只读,通过属性名访问。
save_frame方法调用语法如下:
save_frame(self, filename, t=0, withmask=True)
该方法用于将t指定时刻位置的帧保存到指定图像文件,t 表示方法可以是如下四种之一:
如果withmask为True,对应帧的遮罩会被写入图片的alpha通道层,仅对PNG图像有效。
图像的alpha通道一般用作不透明度参数。如果一个像素的alpha通道数值为0%,那它就是完全透明的(也就是看不见的),而数值为100%则意味着一个完全不透明的像素(传统的数字图像)。在0%和100%之间的值则使得像素可以透过背景显示出来,就像透过玻璃(半透明性),它使数码合成变得容易。alpha通道值可以用百分比、整数或者像RGB参数那样用0到1的实数表示。
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')
write_images_sequence方法用于将剪辑输出到一系列文件中,调用语法如下:
write_images_sequence(self, nameformat, fps=None, verbose=True,withmask=True, logger='bar')
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'):
subfx方法用于对剪辑指定时间段进行变换,返回该段剪辑变换后的剪辑和原剪辑其他段拼接后的新剪辑,剪辑的时长会自动调整。语法如下:
subfx(self, fx, ta=0, tb=None, **kwargs)
subfx实际上是调用基类Clip的fx方法来实现的,关于Clip的fx方法请参考《moviepy音视频剪辑:moviepy中的剪辑基类Clip的属性和方法详解》。
fl_image方法是对get_frame方法获取的帧进行变换的方法,本质上是《moviepy音视频剪辑:moviepy中的剪辑基类Clip详解》介绍的fl方法在内容变换方面的一种变种。
fl_image(self, image_func, apply_to=None)
对比fl方法的调用方法fl(self, fun, apply_to=None, keep_duration=True):
fl(lambda gf, t: image_func(gf(t)), apply_to)
image_func参数对应的帧数组是只读的,不能修改,实际上get_frame(t)返回的所有帧数组都是只读的。帧的类型为numpy.ndarray,而numpy.ndarray直接定义的数据是可修改的,为什么帧数据不能修改笔者暂时还没弄明白(报错ValueError: assignment destination is read-only),为了规避该问题,将参数img数据采用如下形式的赋值语句:frame= np.array(img)
就可以对新的变量frame进行修改,所有变换可以针对新变量frame进行,返回也必须是新变量frame。
fill_array方法是用来进行多个视频合成时处理帧的,更多是一个moviepy内部使用的方法,但当应用需要对帧进行变换时也可以调用。fill_array将pre_array的宽和高设置为参数shape对应的数据。
fill_array处理数据时,如果发现shape对应的宽或高大于pre_array本身的宽或高,则扩展pre_array的宽或高,扩展的位置使用[1,1,1]填充。如果shape对应的宽或高小于pre_array本身的宽或高,则对pre_array的宽或高超出的数据进行丢弃处理。
add_mask方法就是给剪辑增加遮罩,遮罩的duration是调用者的duration,遮罩是由完全不透明(全1组成的YUV值)的像素构成。调用语法非常简单:add_mask(self)
add_mask方法就是将给定剪辑完全遮挡,并返回被遮挡后的剪辑。
on_color方法用于将当前剪辑放置到一个指定颜色背景的可能更大的剪辑上,用于在原始剪辑扩展大小时将空白处设置为指定颜色。返回值为处理后的新剪辑。
on_color(self, size=None, color=(0, 0, 0), pos=None, col_opacity=None)
set_make_frame方法用于设置剪辑帧构建的make_frame方法,make_frame方法在get_frame中被调用来返回指定位置的帧内容。set_make_frame方法非常简单,调用语法如下:set_make_frame(self, mf)
,参数mf为剪辑帧的构建方法名,除self外,带一个t参数。
set_audio方法将原剪辑的拷贝剪辑的音频设置为参数指定音频后返回新剪辑。调用语法:set_audio(self, audioclip)
。
set_mask方法将原剪辑的拷贝剪辑的遮罩设置为参数指定剪辑后返回新剪辑。调用语法:set_mask(self, mask)
,参数mask是调用对象用于遮罩的剪辑。
set_opacity方法将原剪辑拷贝剪辑遮罩的每个元素的值与参数值相乘后返回,实际上就是调整遮罩剪辑帧的YUV值。调用语法:set_opacity(self, op)
,其中参数op表示透明度或不透明度,为任何浮点数,一般设置为【0,1】区间的一个值。
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
to_ImageClip方法将剪辑对应时刻t的帧转换成ImageClip图像剪辑,图像剪辑是所有帧都是固定图像数据的剪辑,所有帧都对应为图像数据。
to_ImageClip(self, t=0, with_mask=True, duration=None)
参数非常简单,不单独解释,但注意图像剪辑在输出到文件时需要设置duration和fps值(为1即可),同时可能在输出文时要指定codec类型,否则可能播放失败。
to_mask方法返回一个由调用者剪辑实例构建的遮罩剪辑。
to_mask(self, canal=0)
to_mask方法用于将当前剪辑生成一个遮罩剪辑,处理时如果调用对象本身有遮罩,则直接返回调用剪辑的遮罩,否则根据调用剪辑的数据生成遮罩数据,生成时是将调用剪辑的每一帧数据的具体像素的YUV值中的某个除以255来实现遮罩的效果,具体对YUV哪个数据进行处理由参数canal指定,0代码Y值、1代表U值、2代表V值。
返回一个由遮罩剪辑生成的非遮罩剪辑。
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文件时会调用该方法对剪辑的遮罩进行处理。
without_audio方法就是将剪辑拷贝后的声音去除,除了self不带其他参数,返回一个去除了声音的新剪辑。
afx方法对原剪辑浅拷贝后的拷贝剪辑的声音进行变换,返回新剪辑。
afx(self, fun, *a, **k)
本文详细介绍了视频剪辑基类VideoClip的构造方法、属性和相关处理方法,相关内容参考了moviepy.video.VideoClip.py的文档字符串以及源代码,并针对部分疑难点进行了资料查询和测试,相关内容的探索和写作断断续续持续了一个多星期(_,为了弥补损失,同时为了将相关探索内容更快传播,将一些重要知识点单独成文发布了),作为一个类对象的介绍来说已经比较全面了。
VideoClip很多方法如save_frame、write_videofile、write_images_sequence、write_gif可以用于输出视频中的对应数据,而subfx、fl_image、add_mask、on_color、set_opacity等是进行视频变换的重要方法。
在文中对部分方法举例进行了运用,但在哪些场景怎么去使用这些方法没有系统介绍,将在后面关于运用场景的文章中进行部分方法使用的介绍。
更多moviepy的介绍请参考《PyQt+moviepy音视频剪辑实战文章目录》或《专栏:使用PyQt开发图形界面Python应用》。
老猿关于PyQt的付费专栏《使用PyQt开发图形界面Python应用》只需要9.9元,本专栏《PyQt+moviepy音视频剪辑实战》文档的同样内容在付费专栏上也有相应内容,总体来说付费专栏介绍更详细或案例更多。
本节内容对应付费专栏的《moviepy音视频剪辑:视频剪辑基类VideoClip详解》。如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。