昨今、動画の作成が手軽になっており、大量の動画を処理する機会も増えている。例えば、100個の動画があり、その全ての動画に会社のロゴを差し込みたい場合、どうしたら良いだろうか。そんな時こそPythonの出番だ。今回は指定フォルダに入っている動画ファイルにロゴを重ねるプログラムを作ってみよう。
動画ファイルもPythonで一括処理できる
昨今、動画は簡単に作成できるので、仕事やプライベートで動画を処理しないといけない場面は増えていることだろう。スマートフォンで手軽にクオリティの高い動画を撮影できるだけでなく、手軽に動画を作成するツールも多い。加えて、PowerPointなど動画とそれほど関係なさそうなツールにも、動画を編集したり、書き出したりする機能がついている。
とは言え、手元にある100個の動画ファイルを、一つずつ開いて編集処理しなければならないとしたら、とても大変だろう。そこでプログラミングの出番だ。
必要ライブラリのインストール - FFmpeg
今回利用するのは、FFmpegとimageioというPythonのライブラリだ。
まずは、FFmpegをインストールしよう。FFmpegはオープンソースの動画・音声のコマンドラインツールだ。いろいろなソフトウェアに組み込まれており信頼性も高い。
【WindowsでFFmpegをインストール】
FFmpegのWindows/Linux版はこちらからダウンロードできる。用途や環境ごとに異なるパッケージが配布されているが、例えば、こちらのリンクからからダウンロードできる。
ダウンロードして、ZIPアフィルを解凍してドキュメントフォルダなどにコピーすると、binフォルダがあり、その中にffmpeg.exeというファイルがある。これを利用可能にするために環境変数PATHにbinフォルダを通そう。
環境変数を編集するには、画面下部にあるWindowsロゴがあるスタートメニューをクリックし「環境変数の編集」を検索しよう。そして、「PATH」を選んで「新規」ボタンを押して、自身のbinフォルダのパスを入力しよう。
【macOSにFFmpegをインストール】
macOSでは、Homebrewを使ってインストールするのが簡単だろう。ターミナル.appを起動して、次のコマンドをコピーして実行していくことでインストールできるだろう。
# --- macOSの場合 ---
# Homebrewをインストール
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# HomebrewでFFmpegをインストール
brew install ffmpeg
Pythonパッケージ「imageio」のインストール
実は、FFmpegを使うだけでも、動画に画像ロゴを重ねることはできる。とは言え、Pythonと組み合わせることで自由度が大幅に向上する。ここでは、imageioとPillow、numpyライブラリを利用してみましょう。
# Windowsの場合
python -m pip install imageio imageio-ffmpeg pillow numpy
# macOSの場合
python3 -m pip install imageio imageio-ffmpeg pillow numpy
動画にロゴを重ねるプログラム
最初に今回のプログラムがどのように動作するかを箇条書きでまとめよう。
- (1) 入力ディレクトリにあるMP4ファイルを全部列挙
- (2) 動画ファイルにロゴを重ねて出力ディレクトリに保存
この処理を行うため、プログラムと動画の入った入力フォルダと、ロゴを重ねた出力フォルダを次のように配置しよう。
.
├── convert_mp4.py --- プログラム本体
├── logo.png --- 重ね合わせたいロゴ画像
├── <in_dir> --- 動画の入力フォルダ
│ ├── sample001.mp4 --- 入力元の動画一覧
│ ├── sample002.mp4
│ └── sample100.mp4
└── <out_dir> --- 動画の出力フォルダ
そもそも、動画というのは、画像データを連続に並べたものとなっている。つまり、画像データ一枚ずつにロゴを書き込めば良いのだ。そこで、ロゴを重ねる処理は次のように行う。
- (1) imageioを使ってMP4ファイルを読み込むreaderと書き込み用のwriterを準備
- (2) 動画の1フレームごとに以下を繰り返し処理する
- (3) ロゴファイルをフレームに書き込む
以下が実際のプログラムだ。「convert_mp4.py」という名前で保存しよう。こちらからもダウンロードできる。
import imageio, glob, os
from PIL import Image
import numpy as np
# ロゴファイルや入出力フォルダを指定 --- (*1)
LOGO_FILE = './logo.png' # ロゴ
INPUT_DIR = './in_dir' # 入力フォルダ
OUTPUT_DIR = './out_dir' # 出力フォルダ
# 背景透過したロゴを読み込む --- (*2)
logo = Image.open(LOGO_FILE)
logo = logo.convert("RGBA") # RGBAモードに変換
logo_width, logo_height = logo.size
# メインプログラム --- (*3)
def main():
# 入力フォルダにある動画一覧を得る
files = glob.glob(f'{INPUT_DIR}/*.mp4')
# 動画ファイルを一つずつ処理する
for idx, infile in enumerate(files):
print(f'{idx:003}:{infile}')
outfile = os.path.join(OUTPUT_DIR, os.path.basename(infile))
add_logo_to_video(infile, outfile)
print("ok")
# 動画にロゴを追加する関数 --- (*4)
def add_logo_to_video(infile, outfile):
# 動画を読み込む --- (*5)
reader = imageio.get_reader(infile)
fps = reader.get_meta_data()['fps']
# 出力動画の書き込みを開始 --- (*6)
writer = imageio.get_writer(outfile, fps=fps)
# 動画の各フレームにロゴを描画して書き込む --- (*7)
for i, frame in enumerate(reader):
# フレームをPillowのImageオブジェクトに変換
frame_image = Image.fromarray(frame)
if i == 0:
# ロゴをframe_imageの1/3のサイズにリサイズ --- (*8)
target_width = int(frame_image.width / 3)
aspect_ratio = logo.width / logo.height
target_height = int(target_width / aspect_ratio)
resized_logo = logo.resize((target_width, target_height))
# ロゴの位置を右上にする --- (*9)
position = (frame_image.width - resized_logo.width - 20, 50)
# フレームとロゴを合成 --- (*10)
frame_image.paste(resized_logo, position, resized_logo)
# Imageオブジェクトをnumpy配列に変換して書き込み --- (*11)
writer.append_data(np.array(frame_image))
writer.close()
if __name__ == '__main__':
main()
プログラムを確認してみよう。(*1)には、ロゴファイルや入出力フォルダを指定する。(*2)では、背景を透過したロゴを読み込む。