如何用 Python 做視頻自動化剪輯?

來源:古明地覺的編程教室

隨着自媒體時代,現在對視頻的處理變得越來越常見。我們可以使用 Adobe 的一些專業工具,但是效率不高;如果只是對視頻進行一些簡單的處理,或者視頻的數量非常多的話,那麼使用專業軟件顯然就不太適合了。

而 Python 有一個專門用於處理視頻的第三方庫:moviepy,可以非常方便地對視頻進行一些簡單處理,下面我們就來看一看。

首先是安裝:

pip install moviepy -i https://pypi.tuna.tsinghua.edu.cn/simple

個人推薦安裝的時候使用清華源,因爲 moviepy 需要依賴另一個庫:imageio_ffmpeg,這個庫裏面包含了一個 50 多 MB 的 ffmpeg 二進制文件,如果網絡不行的話,直接從 pypi 上拉取會花很長時間。當然安裝 moviepy 的時候,imageio_ffmpeg 就順帶安裝了。

從這裏我們也可以看到,moviepy 底層依賴 ffmpeg,而 ffmpeg 是跨平臺的,所以 moviepy 也可以在任意平臺上使用。

moviepy 的簡單使用

我們來看 moviepy 都提供了哪些功能,不過在使用之前我們需要一個視頻,就使用 you-get 工具從 bilibili 下載一個吧。

下面就使用這個下載的視頻進行演示。

視頻截取

如果一個視頻比較長,我們可以截取感興趣的片段。

from moviepy import editor

# 調用 `VideoFileClip(文件名)` 即可將視頻加載進來
# 並且支持不同的視頻格式,比如 flv、mp4 等等
video_clip = editor.VideoFileClip(
    "空城計,但是7Ki7Ki醬醬.mp4")

# 調用subclip方法,傳入起始時間和結束時間
# 即可截取視頻中的指定部分
"""
video_clip.subclip(): 
   截取視頻全部,相當於沒做處理
video_clip.subclip(10): 
   從視頻的 `第10秒` 截取到 `結尾`
video_clip.subclip(10, -2): 
   從視頻的 `第10秒` 截取到結尾的 `前兩秒`
video_clip.subclip((1, 35), (3, 10)): 
   從視頻的 `第1分35秒` 截取到 `第3分10秒` 
video_clip.subclip((1, 2, 18), (2, 1, 34)): 
   從視頻的 `第1小時2分18秒` 截取到 `第2小時1分34秒`
"""

# subclip 會返回一個新的 VideoFileClip 對象
# 所以它支持鏈式操作
video_clip = video_clip.subclip(30)

音量調整

一個視頻,我們也可以調整它的音量。

from moviepy import editor

video_clip = editor.VideoFileClip(
    "空城計,但是7Ki7Ki醬醬.mp4")

# 調整音量,變爲原來的0.5
# 同樣會返回一個新的對象
video_clip = video_clip.volumex(0.5)

在視頻上添加文字

如果你想在視頻裏面寫上一些內容,moviepy 也是支持的。

from moviepy import editor

video_clip = editor.VideoFileClip(
    "空城計,但是7Ki7Ki醬醬.mp4")

# 做一個文本剪貼板,自定義樣式、顏色。
text_clip = editor.TextClip("7ki7ki 棒棒",
                            fontsize=40, color="blue")
# 讓文本在屏幕的正中間顯示
# 持續10秒,設置透明度爲 0.6
"""
屏幕左上角的座標爲 (0, 0),右下角的座標爲 (屏幕寬度, 屏幕高度)
set_position((800, 500)): 
    顯示在800, 500的位置上
set_position(("center", "center")): 
    顯示在屏幕的正中央
set_position((0.4, 0.6), True): 
    顯示在距離左邊百分之40、距離上邊百分之60的位置上

set_duration(10): 持續10秒
set_opacity(0.6): 設置透明度爲0.6
"""

text_clip = text_clip.set_position(("center""center")).\
    set_duration(10).set_opacity(0.8)

# 然後把 `文本剪貼板` 貼在視頻上
video_clip = editor.CompositeVideoClip([video_clip, text_clip])

如果你是 Windows 系統,不出意外的話,當你在執行 editor.TextClip() 的時候,會報出如下錯誤:

這個錯誤是由於你的電腦上缺少 ImageMagick 造成的,我們需要去官網下載對應操作系統的 ImageMagick。

官網:http://www.imagemagick.org/script/download.php

下載完之後,安裝在指定的目錄,然後修改 site-packages\moviepy\config_defaults.py,在文件的尾部有如下內容:

import os

FFMPEG_BINARY = os.getenv('FFMPEG_BINARY''ffmpeg-imageio')
IMAGEMAGICK_BINARY = os.getenv('IMAGEMAGICK_BINARY''auto-detect')

# 把 `IMAGEMAGICK_BINARY = ` 後面的內容
# 換成 ImageMagick 安裝路徑下 magick.exe 的絕對路徑:
import os

FFMPEG_BINARY = os.getenv('FFMPEG_BINARY''ffmpeg-imageio')
IMAGEMAGICK_BINARY = r'E:\ImageMagick-7.0.10-Q16\magick.exe'

替換完之後,再執行就沒有問題了。

我們將上面的幾個部分,組合起來演示一下:

from moviepy import editor

video_clip = editor.VideoFileClip(
    "空城計,但是7Ki7Ki醬醬.mp4")

video_clip = (
    # 截取 5 到 20 秒
    video_clip.subclip(5, 20).
    # 設置音量爲原來的 0.8
    volumex(0.8)
)

text_clip = (
    editor.TextClip("7ki7ki",
                   fontsize=40, color="blue").
    set_position(("center""center")).
    set_duration(10).
    set_opacity(0.8)
)

# 把 `文本剪貼板` 貼在視頻上
video_clip = editor.CompositeVideoClip([video_clip, text_clip])

# 然後將視頻導出
video_clip.write_videofile("空城計,但是7Ki7Ki醬醬_2.mp4")

執行代碼,會看到以下輸出:

表示正在調用 ffmpeg 處理視頻,而視頻處理完畢大概需要十幾秒鐘的時間。處理完畢之後,我們打開看一下。

我們看到此時文字就添加進去了,並且該視頻只有 15 秒,也就是我們截取的 5 到 20 秒的部分。

總結一下整個流程,首先使用 VideoFileClip 對視頻進行讀取,得到 VideoFileClip 對象,記作 video_clip。我們可以對這個 video_clip 進行任意的操作(剪切、合併、調整亮度、速度、和其它的 video_clip 拼接在一起等等)。

並且需要注意的是,這些操作是可以鏈式調用的,因爲每一次操作都會得到一個新的 video_clip,不會影響原來的。我們上面演示了視頻的讀取、以及指定部分的截取、音量的調整、以及添加文字等等,下面還會介紹更多操作。

最後我們調用 video_clip 的 write_videofile 方法,可以將處理之後的視頻寫入本地。當然也可以使用 pygame,或者 jupyter notebook 進行展示。爲了方便,我們後面就使用 jupyter notebook。

但是要清楚,moviepy 處理視頻使用的是 ffmpeg,生成文字使用的是 ImageMagick。

獲取視頻屬性

一個視頻,肯定有大小、寬高、fps、時長等屬性,那麼 moviepy 要如何獲取這些屬性呢。

from moviepy import editor

video_clip = editor.VideoFileClip(r"空城計,但是7Ki7Ki醬醬.mp4")
# 獲取寬度和高度
print(video_clip.size)
print(video_clip.w, video_clip.h)
"""
[2160, 1080]
2160 1080
"""

# 獲取 fps
print(video_clip.fps)
"""
30.0
"""

# 獲取時長,單位是秒
print(video_clip.duration)
"""
110.92
"""

# 獲取大小,可以直接使用 os 模塊
import os
# 大概 13MB
size = os.stat(r"空城計,但是7Ki7Ki醬醬.mp4").st_size
print(size)
print(size / 1024 ** 2)
"""
13324402
12.70713996887207
"""

視頻合成

視頻合成有兩種方式:

1)多個視頻按照先後順序拼接起來,比如一個一分鐘和一個兩分鐘的視頻組合起來,變成三分鐘。

2)多個視頻在同一個畫面上顯示。

先來看看第一種:

from moviepy import editor
video_clip = editor.VideoFileClip(r"D:\satori\空城計,但是7Ki7Ki醬醬.mp4")

# 截取10到20秒
video_clip1 = video_clip.subclip(10, 20)
# 截取結尾的前兩秒
video_clip2 = video_clip.subclip(-2)
# 然後前後拼接起來
video_clip = editor.concatenate_videoclips([video_clip1, video_clip2])
# 使用jupyter進行展示,設置一個寬度
video_clip.ipython_display(width=360)

執行完之後,視頻就展示在 jupyter 上了,而且是兩個視頻拼接在一起的,總共 12 秒鐘。此外 concatenate_videoclips 中還可以指定一個 transition 參數 (也是一個 VideoFileClip 對象),作爲銜接之間的過渡。

還是比較簡單的,假設我們有 5 個視頻,如果只是簡單的前後拼接就可以這麼做。

from moviepy import editor

videos = ["1.mp4""2.mp4""3.flv",
          "4.mp4""5.flv"]
video_clips = []

for video in videos:
    video_clips.append(editor.VideoFileClip(video))

editor.concatenate_videoclips(
    video_clips).write_videofile("xxx.mp4")

這裏值得一提的是,多個 video_clip 進行拼接,並不需要這些 video_clip 之間有相同的尺寸、時長什麼的,僅僅是將它們按照順序拼接起來而已。

另外,當你用 jupyter 進行展示時,視頻不要過長,否則報錯。當然你也可以給 ipython_display 函數傳遞一個 maxduration 參數,讓它支持顯示更大時長的視頻文件。但是注意:如果文件過大,在 jupyter 上可能會耗光你的內存。

然後是第二種拼接

有多個視頻,可以讓它們在同一個畫面上顯示。

from moviepy import editor

# margin: 設置外邊距
video_clip = editor.VideoFileClip(
    r"D:\satori\空城計,但是7Ki7Ki醬醬.mp4").margin(10)

# 截取 10 到 20 秒
video_clip1 = video_clip.subclip(10, 20)
# x 軸鏡像
video_clip2 = video_clip1.fx(editor.vfx.mirror_x)
# y 軸鏡像
video_clip3 = video_clip1.fx(editor.vfx.mirror_y)
# resize: 等比縮放
video_clip4 = video_clip1.resize(0.5)

# 列表裏面有兩個列表,所以會將屏幕上下等分
# 上半部分顯示 video_clip1, video_clip2
# 下半部分顯示video_clip3, video_clip4
video_clip = editor.clips_array([[video_clip1, video_clip2],
                                 [video_clip3, video_clip4]])
video_clip.ipython_display(width=600)

所以 concatenate_videoclips 是將多個視頻前後拼接,而 clips_array 則是將多個視頻同時顯示在一個畫面裏面。

修改視頻屬性

from moviepy import editor

video_clip = editor.VideoFileClip(
    r"D:\satori\空城計,但是7Ki7Ki醬醬.mp4").subclip(10, 20)

video_clip = (
    # 調整尺寸,保持比例
    video_clip.fx(editor.vfx.resize, width=460)
        # 倍數播放
        .fx(editor.vfx.speedx, 2)
        # 畫面調暗
        .fx(editor.vfx.colorx, 0.5)
)
video_clip.ipython_display(width=600)

雖然截取了 10 秒鐘,但是 2 倍數播放,所以變成了 5 秒鐘。

視頻音頻合成

假設有一個視頻 A 和一個視頻 B,現在要將視頻 B 的音頻和視頻 A 組合起來,怎麼做呢?

from moviepy import editor

video_clipA = editor.VideoFileClip(r"A.mp4")
video_clipB = editor.VideoFileClip(r"B.mp4")

# 獲取 B 的音頻
audioB = video_clipB.audio
"""
# 如果已經是音頻格式,那麼也可以直接加載
audioB = editor.AudioFileClip("b.mp3")
"""

# 將 B 的音頻和 A 組合起來
video_clipA = video_clipA.set_audio(audioB)

小結

以上就是 moviepy 的一些基本用法,通過 moviepy 可以對視頻做一些簡單的批處理。至於視頻(以及音頻)背後的原理就是一門複雜的學問了,有興趣的話可以深入研究一下,現在短視頻那麼火,相關的技術人員也比較短缺,所以前景還是很不錯的。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/CDumuJU7H0rdpKdcPSQVbg