首頁 > 軟體

Python視訊處理模組之moviepy的用法教學

2022-07-21 18:00:32

楔子

隨著自媒體時代,現在對視訊的處理變得越來越常見。我們可以使用 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-packagesmoviepyconfig_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-Q16magick.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)

以上就是Python視訊處理模組之moviepy的用法教學的詳細內容,更多關於Python視訊處理模組moviepy的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com