介绍一个python视频处理库:moviepy

   处理视频是一个常见的需求。那么在python中如何用代码处理视频呢?最近我无意间发现了一个很好用的python视频处理库moviepy,其使用起来简单易用,而且功能比较强大,这里记录一下分享给大家。

  • What is moviepy?

   以下的介绍来自moviepy的官方文档

moviepy是一个用于视频编辑的python模块,其可以用来对视频进行一些基础的操作(比如剪切,连接,插入标题等),视频创作(比如非线性编辑),视频处理以及给视频增加一些炫酷的特效等。它可以读写大多数常见的视频格式,包括GIF。

  • How to install moviepy?

   moviepy的安装非常简单,直接使用命令pip install moviepy即可。当然你也可以选择从源码安装,下载源码包,解压缩,然后切换到含有setup.py的目录,执行 python setup.py install 即可。

   moviepy的底层依赖于Numpy(用于高效数值处理),imageio(图像处理), Decorator,tqdm(用于显示进度条)。它在Windows/Mac/Unix环境下应该都是可以工作的,支持python2.7+以及python3。moviepy底层的视频读写依赖于ffmpeg,它会在你安装moviepy的时候自动下载,如果你已经安装了ffmpeg或者想使用特定版本的ffmpeg,你可以从moviepy/config_defaults.py中指定。

   需要注意的是,还有一些可选模块可以安装,比如ImageMagic。这是一个开源的图像处理库,支持对超过200种格式的图像进行编辑处理,详细的用法可以自行参考官网文档。如果你希望向视频中添加文字,就必须安装这个库。它也可以作为生成GIF的后端,但不是必须的。如果你在Windows下安装这个库就比较简单,可以直接使用可执行文件安装;如果是Unix用户,可以选择源码编译安装,官网文档有详细的说明,不再赘述。

  • When to use moviepy?

   如果你属于以下情况,可以考虑使用moviepy:

  1. 你有很多视频需要处理,或者你需要用很复杂的方式处理;
  2. 你希望在web服务器上自动生成videos或者GIF(Django,Flask等);
  3. 你希望能够自动化一些冗长乏味的工作,比如插入标题,图像场景分割,做一些视频结尾的特效,添加副标题等;
  4. 你希望可以使用code实现一些新奇的,其他视频编辑软件都无法做到的特效;
  5. 你希望可以从其他python库(比如matplotlib,mayavi,gizeh,scikit-images等)生成的图像中生成动画。

   如果你是属于下面的这些情况,使用moviepy未必是最好的选择:

  1. 你仅仅需要做逐帧的视频分析(比如面部检测等),这种情况下你也是可以使用moviepy的,但是更建议使用imageio,opencv,simplecv等,因为这些库就是专门干这件事情的。
  2. 你仅仅想对视频进行转化,或者想把一系列的图片转化为视频,你最好直接使用ffmpeg(或者avconv,mencoder等),因为这些工具做这些转化会更快,而且更省内存。

   moviepy的优点和缺点

  1. 优点:
    简单和直观。基础的操作一行代码就可以搞定,对于新手来说非常友好。
    灵活。你对于视频或者音频的每一帧都有着完全的控制权,创作你自己的特效非常容易。
    便携。代码主要依赖numpy和ffmpeg(这两者都是跨平台的),所以moviepy几乎可以在所有的平台以及几乎所有的python版本上运行。
  2. 局限性:
    无法处理视频流。比如无法实时处理来自摄像头的视频流等。当然,本来这就不是moviepy定位要解决的问题。
    *处理大量视频,音频可能会很吃力**。在同时处理大量(>100)的视频,音频,图片的时候可能会有内存问题,这个后面应该会修复。
  • Basic operations of moviepy
  1. Example code
  1. How moviepy works?

   moviepy底层使用ffmpeg读取和导出视频以及音频文件。它使用ImageMagic对视频插入文字以及生成GIF(可选)。对于不同的媒体文件的处理是通过python高效的数值计算库numpy来完成的。一些特效处理等使用到了python的图像处理库比如PIL,scikit-images以及科学计算库scipy等。下图1简单说明了moviepy的工作流程:

moviepy的工作流程 图1

   关于moviepy的一些基础概念。moviepy的核心概念是clips,可以是AudioCLips 和 VideoClips 。这些clips可以被修改(剪切,降低播放速度,调整亮度等)或者和其他的clips混合到一起组成新的clips。然后这些clips可以通过pygame或者Ipython(jupyter notebook)预览,或者导出为videos文件或者GIF。VideoClips可以通过一个视频文件,图像文件或者文字以及动画来创建,这些VideoClips还可以有音轨(audio track)即 AudioCLips以及mask(这种一种特殊的VideoClips,当其他的clips混合在一起的时候,这个mask决定哪些clips可以显示出来)。具体操作下面我们主要以代码的形式展示。

3.Show how use moviepy with codes

   在进行下面的实验之前,你最好准备一些短小的视频以及音频片段(可以随意从网络下载)。

下面是我们使用到的一些视频,音频文件。

视频播放器

00:00
00:03

视频1 girl.mp4

视频播放器

00:00
00:05

视频2 xq.mp4

视频播放器

00:14
00:14

视频3 dogs.mp4
音频播放器

音频1 22.mp3

  • 堆叠和连接clips

上面代码的意图应该是很明显了,就是将两个视频(VideoCLip)顺序连接到一起,连接之后得到的视频concatenate.mp4如下:

视频播放器

00:07
00:08

视频4 concatenate.mp4

  • clip_array的使用

上面的代码得到的视频如下:

视频播放器

00:00
00:05

视频5 stack.mp4

  • CompositeVideoClips

上面的代码还是将三个clip组合到一起形成一个新的clip,只不过这次对每一个clip都做了一些操作,比如上面的 set_start 方法就是设置视频开始播放的时间, set_position 是设置clip的位置, crossfadein 是设置连接视频渐变的时间,还有很多其他的方法可以具体参考文档,使用这些方法,我们就可以将视频剪辑的更加丰富多彩,符合我们的要求。上面得到的视频如下:

视频播放器

00:11
00:20

视频6 composite.mp4

  • Compositing audio clips
    我们还可以使用moviepy对音频进行编辑以及给视频添加音频,一个实例代码如下:

上面的代码逻辑不难理解。首先构建了一个 VideoClip 对象,然后使用 subclip 方法截取音频50-55秒,然后保存为新的音频文件。接着对视频clip对象采用 set_audio 方法设置audio track,这里需要注意的是clip的很多方法都是采用”流式”操作,即 clip.set_xxx 放回的仍然是一个clip,因此可以连续使用set_xxx方法,所以需要注意使用set_xxx之后需要将结果保存到一个新的对象,否则设置是无效的。最后需要注意 clip.fx 是通用的设置clip的方法,具体用法可以查看文档。经过上面一系列的处理之后,得到的音频、视频文件如下:
音频播放器

音频2 22_clip.mp3

视频播放器

00:00
00:03

视频7 set_xq.mp4

视频播放器

00:00
00:02

视频8 xq1.mp4

  • Methods to create custom effects

上面的代码展示了如何使用clip的 fl 和 fl_time 以及 fl_image 方法来生成一些特效。
fl_time方法接收一个函数,对video的时间轴进行修改,该函数接收的是视频的时间属性t,所以上面的clip.fl_time(lambda x:3*x) 会让视频的播放速度加快3倍,而
clip.fl_time(lambda x:1+sin(x)) 则让视频按照正弦的timeline播放,视频会有些抖动。 fl_image 对视频每一帧图像进行修改,其接收的也是一个函数作为参数,该函数的参数为image(ndarray),所以上面的 invert_green_blue 函数做的工作就是将图片的green channel 和 blue channel 转换。而 fl函数是一个更一般的函数,其也是接收一个函数作为参数,该函数的参数有两个,一个是 get_frame 函数,一个是当前帧的时间t,函数需要返回一个image(ndarray),而不难看出上面的scroll 函数就是让视频随着时间的变化在水平方向向下移(展示图片的一部分,高度始终不变),在竖直方向上不改变。这里只展示得到的xq4.mp4和xq5.mp4这两个视频。

视频播放器

00:00
00:05

视频9 xq4.mp4

视频播放器

00:00
00:05

视频10 xq5.mp4

  • Show and preview
    在剪辑视频的时候,对于一些复杂的操作,我们很难一下就完成,往往需要多次尝试,调整,才能得到一个更好的结果。如果我们每次都把操作的结果导出到视频然后再打开查看,可以想象这是多么麻烦的一件事情。特别是当视频比较长的时候,也很浪费时间。所以我们要是能一边处理一边预览就好了。虽然moviepy没有GUI界面,但是仍然可以通过pygame以及Ipython进行预览。
  1. 通过pygame进行预览

要想通过pygame进行预览,首先你当然得到安装好pygame(pip install pygame)。上面其实主要展示了三个method:show(t) 用来展示视频在第t秒的帧图像, interactive = True 表示开启交互式模式。 save_frame(img,t) 表示将第t秒的帧图像保存到img。 preview(audio,fps) 就是预览视频的方法啦,audio参数可以设定要不要显示音频,fps参数用于设定帧速率。

  1. 使用Ipython进行预览
    ipython_display demo 图1 使用Ipython进行预览的小例子。
    除了使用 clip.ipython_display() 这种方式之外,还可以使用 ipython_display(clip,autoplay=1,loop=1) 这种方式进行播放,这里 autoplay=1 表示自动播放, loop=1 表示无限循环播放。使用在ipython中预览的一个好处是视频是内嵌在浏览器里的,所以你可以直接携带的notebook文件进行演示,十分方便。但是这样做也有一个缺点,那就是当视频很大的时候,notebook文件的体积会变得非常大。
  • 和matplotlib进行交互

上面的代码展示了如何将matplotlib绘制的图像保存为GIF。首先导入 VideoClip(make_frame,duration) 类, make_frame是一个函数,这个函数默认参数为时间t,表示当前帧的时间,返回时间t时的image(ndarray)。这里自定义的make_frame函数利用matplotlib构造了一个随时间t变化的复杂函数,最后通过 mplfig_to_npimage 函数将matplotlib的fig对象转化为ndarray。要将clip保存为gif,直接使用
write_gif 函数即可。最后得到的matplotlib.gif如下:
 图2 matplotlib.gif

  • funny scripts using moviepy
    最后展示一些使用moviepy写的有趣的脚本(主要来自官方给的demos)
  1. moving circle(跳动的太阳)

 图3 circle.gif

  1. make videos from list of images
    除了之前提到的使用 VideoClip 类可以将一系列的图片转化为视频之外,还有一个 ImageSequenceClip 类也可以实现这个功能。具体代码如下:

不难发现,使用 ImageSequenceClip更为简单一点,但是要求所有的图片必须具有相同的大小,上面的 preprocess_imgs函数就是将所有的图片resize成相同的大小。

  1. moving letter(跳动的字母)
    这个脚本实现了英文字母的跳动特效。

coolTextEffects 视频11 coolTextEffects.avi

  • the end effects
    给视频的结尾增加”the end”字幕特效。
视频播放器

00:00
00:05

视频12 theEnd.mp4

  • blur for videos
    将图片的每一帧都变模糊(比如对视频的每一帧使用gaussian blur)。