在这个短视频和自媒体大行其道的年代,音视频剪辑成为了大佬们的必备工具,现在有很多音视频剪辑的软件,如剪映、Camtasia、爱拍剪辑、Adobe Premiere、Final Cut Pro、Vegas、快剪辑、爱剪辑、会声会影等,大部分都好用,收费和免费的都有。
但某些情况下,用这些 GUI 的剪辑软件有时不怎么方便,如:
批量处理一批短视频(类似增加片头、片尾或 Logo 等同质性工作)、要将一批图片按照一定规则配音组织成视频等,如果还用现成的 GUI工具,不但枯燥无味,浪费时间,而且批量一个个处理下来不一定都非常精确(如在剪辑尾部 3 秒增加 Logo 标记或语音)
基于某些目的进行视频的个性化定制处理,如基于视频的画面进行直方图均衡变换的灰度调整
这些情况下使用 GUI 工具进行处理会比较麻烦甚至无法支持,最希望的是能自己通过代码或脚本快速定制任务处理,将这些枯燥繁杂的工作快速准确的完成处理。这个时候 Python 的 Moviepy 库就可以大有可为了,下面老猿就为大家介绍一下 Moviepy 进行音视频剪辑的能力。
MoviePy 是一个用于视频编辑的 Python 模块,可用于进行视频的基本操作(如剪切、拼接、标题插入)、视频合成(也称非线性编辑)、视频处理或创建高级效果。
它可以读写最常见的视频格式,MoviePy 能处理的视频是 ffmpeg 格式的,老猿理解支持的文件类型至少包括:*.mp4 *.wmv *.rm *.avi *.flv *.webm *.wav *.rmvb 等 。
MoviePy 使用 ffmpeg 读取、导出视频和音频文件,使用 ImageMagick 生成文本和输出 GIF 文件。Python 的快速数字库 Numpy 保证了不同媒体的处理。高级效果和增强使用了 Python 的许多图像处理库(PIL、Scikit-image、scipy 等)。
moviepy 的核心对象是剪辑(clips),包括 AudioClips 和 VideoClips。它们可以修改(剪切、减速、变暗…)或与剪辑混合以形成新剪辑,可以使用 PyGame 或 IPython Notebook 预览,并可以输出到对应类型的文件(如 MP4、GIF、 MP3 等)。例如,VideoClips 可以从视频文件、图像、文本或自定义动画创建。VideoClips 可以有一个音频轨道(这是一个 AudioClip)和一个 mask 遮罩(一个特殊的 VideoClip,指示当剪辑与其他剪辑混合时要隐藏哪些部分)。
目前 moviepy 库最新版本是 1.0.3,安装非常简单,使用 pip 安装时,请将站点指向国内的镜像站点,否则下载很慢或者下载不下来,老猿使用清华的镜像,指令是:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple moviepy
注意:
1、moviepy 全小写,安装时会自动安装相关依赖包;
2、建议安装最新的版本 1.0.3,因为 1.0.2 中有个比较大的 bug;
3、如果没有安装最新版本,可以执行版本升级,指令:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple moviepy --upgrade
一般音视频都是从文件读入的,视频文件的装载使用类 VideoFileClip 的构造方法,音频文件的装载使用类 AudioFileClip 的构造方法,两者都可以带多个参数,但最简单的调用方法就是传入一个文件名作为参数调用即可。
视频可以输出成其他格式视频、GIF 动画、一系列图片,对应输出函数分别为 write_videofile、write_gif、write_images_sequence,可以只带一个输出文件名参数。
注意:输出方法是 VideoFileClip 的父类 VideoClip 的方法。
另外视频文件通过属性 audio 获取视频的音频。音频可以使用 write_audiofile 输出成其他格式音频,该方法是 AudioFileClip 的父类 AudioClip 的方法。
当音频或视频输出需要转换格式时,注意一定要带 codec 参数。
下面代码加载一个视频和一个音频,然后输出成各种文件:
from moviepy.editor import *
clipA = AudioFileClip(r"F:\video\fansNote.mp3")
clipV = VideoFileClip(r"F:\video\rahdms.mp4")
clipV.write_videofile(r"F:\video\temp\rahdmsBak.avi",codec='png') #视频转成avi格式输出
clipV.audio.write_audiofile(r"F:\video\temp\rahdms.wav", codec='pcm_s16le') #视频中的音频转成wav格式输出
clipV.write_gif(r"F:\video\temp\rahdms.gif") #视频输出成gif文件
clipV.write_images_sequence(r"F:\video\temp\fansNote%02d.jpg",0.5) #视频输出成图片,0.5表示2秒输出一张图片
clipA.write_audiofile(r"F:\video\temp\fansNoteBak.mp3") #音频输出到其他文件
音视频剪辑在 Moviepy 中为 AudioClip、VideoClip 对象,对音视频剪辑数据的访问主要是通过 AudioClip、VideoClip 的父类 Clip 的相关属性进行的:
下面代码加载一个视频和一个音频,然后输出剪辑的时长和帧率,并取两个剪辑的前 2 秒输出到对应文件:
from moviepy.editor import *
clipA = AudioFileClip(r"F:\video\fansNote.mp3")
clipV = VideoFileClip(r"F:\video\rahdms.mp4").subclip(0, 4)
print(f"视频剪辑时长以及帧率为:{
clipV.duration}、{
clipV.fps}")
print(f"音频剪辑时长以及帧率为:{
clipA.duration}、{
clipA.fps}")
clipV.subclip(0, 2).write_videofile(r"F:\video\temp\rahdms.avi",codec='png') #视频前2秒转成avi格式输出
clipA.subclip(0, 2).write_audiofile(r"F:\video\temp\fansNote.wav", codec='pcm_s16le') #音频前2秒转成wav格式输出
音视频的变换老猿将其分为 4 类,包括颜色变换、时间线变换、大小变换、内容变换。所有变换都是基于 Clip 类的 fl 方法来进行的,其他方法最终都要调用 fl 方法来完成剪辑变换。不过在 Clip 类内还提供了时间线的变换方法 fl_time,这是因为对音频和视频都可以基于时间线进行变换。
下面的代码将一个 h 像素高剪辑的视频内容帧的下半部部分剪辑掉,newclip 剪辑的高度变为 h/2。
src = VideoFileClip(r"F:\video\抖音-爱拼才会赢.mp4")
h = src.size[1]
fl = lambda gf,t : gf(t)[int(t):int(t)+h/2, :]
newclip = src.fl(fl, apply_to='mask')
newclip.write_videofile(r"F:\video\抖音-爱拼才会赢_re.mp4"
下面的代码将剪辑变成原剪辑的 n 倍速:
clipVideo = VideoFileClip(r"F:\video\WinBasedWorkHard_src.mp4")
end = clipVideo.end
newclip = clipVideo.fl_time(lambda t: t*n, apply_to=['mask','audio'])
剪辑的颜色或亮度变换函数包括:
blackwhite 将彩色视频变成灰度视频,语法:blackwhite(clip, RGB = None,
preserve_luminosity=True)
colorx 将剪辑中每个帧的每个像素的 RGB 值与参数 factor 相乘,使得明度增大(参数 factor 大于 1)或降低(参数factor 小于 1),语法:colorx(clip, factor)
fadein 使剪辑在开始播放后的指定时间内从某种颜色(默认为黑色)逐渐显示出来,语法:fadein(clip, duration, initial_color=None)
fadeout 函数使剪辑在剪辑快结束前的指定时间内逐渐淡隐于某种颜色(默认为黑色),语法:fadeout(clip, duration, final_color=None)
invert_colors 将像素对应颜色进行反转,语法:invert_colors(clip)
um_contrast 用于对剪辑的亮度对比度(luminosity-contrast )进行校正,语法:lum_contrast(clip, lum = 0, contrast=0, contrast_thr=127)
gamma_corr 用于对屏幕图像的色彩进行 gamma 修正,语法: gamma_corr(clip, gamma)
部分示例代码:
下面的代码是对视频剪辑加载后,将其明度乘以 2 和除以 2 分别生成 2 个新剪辑:
from moviepy.editor import *
clipVideo1 = VideoFileClip(r"F:\video\yyzg.mp4")
clipVideo2 = clipVideo1.fx(vfx.colorx, 2)
clipVideo1 = clipVideo1.fx(vfx.colorx, 0.5)
下面代码在剪辑首尾各设了 5 秒的淡入和淡出时间并输出变更后的新剪辑:
from moviepy.editor import *
clipVideo = VideoFileClip(r"F:\video\WinBasedWorkHard_src.mp4").fx(vfx.fadein,5,(0,0,255)).fx(vfx.fadeout,5,(0,0,0))
clipVideo.write_videofile(r"F:\video\fadeinout.mp4", threads=8)
剪辑大小变换函数包括:
示例代码:
下面的代码将剪辑的 260 行像素以上的部分去除,值保留 260 行以下的像素内容对应的视频,并将新剪辑增加一个 3 个像素的蓝色边框:
from moviepy.editor import *
clipVideo = VideoFileClip(r"F:\video\WinBasedWorkHard_src.mp4").fx(vfx.crop,0,260)
clipVideo = clipVideo.fx(vfx.margin, 3, color=(0, 0, 255), opacity=0.5)
clipVideo.write_videofile(r"F:\video\crop.mp4")
剪辑内容变换函数包括:
部分示例代码:
下面的代码实现视频左右颠倒和上下颠倒:
from moviepy.editor import *
clip = VideoFileClip(r"F:\video\WinBasedWorkHard_src.mp4").crop(0, 300, 540, 660).subclip(0,15)
newclip1 = clip.fx(vfx.mirror_x)
newclip2 = clip.fx(vfx.mirror_y)
newclip1.write_videofile(r"F:\video\WinBasedWorkHard_mirrorx.mp4", threads=8)
newclip2.write_videofile(r"F:\video\WinBasedWorkHard_mirrory.mp4", threads=8)
下面的案例随时间线变换将视频内容旋转不同的角度,且将剪辑的的高和宽度调整为原剪辑对角线的大小,剪辑的画面内容不会丢失,旋转角度由 angleF 函数确认:
from moviepy.editor import *
def angleF(t):
ret = (10*int(t))%360
return ret*-1
if __name__=='__main__':
clip = VideoFileClip(r"F:\video\WinBasedWorkHard_src.mp4",audio=False).crop(0, 300, 540, 840)
newclip = clip.rotate(angleF,expand=True).fx(vfx.resize,(764,764))
音视频除了变换和取剪辑片段以外,还可以创造新剪辑,相关方法包括:
视频的拼接使用方法 concatenate_videoclips,调用语法:
concatenate_videoclips(clips, method="chain", transition=None, bg_color=None, ismask=False, padding = 0)
其中 clips 为需要拼接的多个视频。
下面的案例代码将三个视频连接成一个视频:
from moviepy.editor import *
fileList = ['F:\\video\\1.mp4', 'F:\\video\\2.mp4','F:\\video\\3.mp4']
tmpClip = []
for fileName in fileList:
clip = VideoFileClip(fileName)
tmpClip.append(clip)
destClip = concatenate_videoclips(tmpClip)
destClip.write_videofile("F:\\video\\dest.mp4")
同屏播放视频需要使用 clips_array 函数,调用语法如下:
clips_array(array, rows_widths=None, cols_widths=None, bg_color = None)
参数array为视频剪辑数组。
下面的案例代码将 tmpClip 保存的多个视频连接成一个同屏播放视频,其中 lines、columns 表示一个屏幕分成几行每行几个视频:
from moviepy.editor import *
print(f"视频将排列成{lines}行{columns}列")
clipArrays = []
tmpClipArray = []
column = 0
for clip in tmpClip:
tmpClipArray.append(clip)
column += 1
if column == columns:
clipArrays.append(tmpClipArray)
column = 0
tmpClipArray = []
destClip = mpe.clips_array(clipArrays)
前面第三部分介绍的 write_images_sequence 方法用于将剪辑输出到一系列图像文件中,而 ImageSequenceClip 则基本上与 write_images_sequence 过程可逆,用于将一系列图像生成剪辑。
ImageSequenceClip 是 VideoClip 的直接子类,其构造方法语法为:
__init__(self, sequence, fps=None, durations=None, with_mask=True, ismask=False, load_images=False)
下面代码将 F:\temp\img 目录下的所有同样大小的图像合成一个每秒播放一个图像的剪辑:
imsClip = ImageSequenceClip(r"F:\temp\img",fps=1)
imsClip.write_videofile(r"F:\video\imgs.mp4", threads=threads)
部分示例代码:
生成一副红色背景的静态视频:
colClip = ColorClip((360,360),color = (255,0,0),ismask=False,duration=5).set_fps(1)
colClip.write_videofile(r"F:\video\red.mp4", codec='mpeg4')
生成一文字构成的视频:
fps = 3
inf = r"text clip test"
txtclip = TextClip(inf ,font='Courier',fontsize=36,color='red',bg_color='white',transparent=True,tempfilename=r'F:\temp\img\txtjpg.png',remove_temp=False).set_duration(15).set_fps(3)
txtclip.write_videofile(r"F:\video\text.avi", codec='rawvideo', threads=threads)
本文介绍了 Python Moviepy 音视频剪辑库的安装、主要功能以及部分示例代码,可以看到 Moviepy 能从文件或音视频流中装载音视频剪辑,并对装载的音视频剪辑进行各种变换和合成,代码开发简单易懂,很容易掌握,感兴趣的朋友不妨尝试一下。
更多关于 Moviepy 的介绍请大家参考《Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载》。
如对文章内容存在疑问或需要相关资料,可在博客评论区留言,或关注:老猿Python 微信公号发消息咨询,可通过扫二维码加微信公众号。
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!
前两个专栏都适合有一定Python基础但无相关知识的小白读者学习,第三个专栏请大家结合《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python图形图像处理 》的学习使用。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《https://blog.csdn.net/laoyuanpython/category_9831699.html 专栏:Python基础教程目录)从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。