昨今、動画の作成が手軽になっており、大量の動画を処理する機会も増えている。例えば、100個の動画があり、その全ての動画に会社のロゴを差し込みたい場合、どうしたら良いだろうか。そんな時こそPythonの出番だ。今回は指定フォルダに入っている動画ファイルにロゴを重ねるプログラムを作ってみよう。

  • 100個の動画ファイルにロゴを重ねよう

    100個の動画ファイルにロゴを重ねよう

動画ファイルもPythonで一括処理できる

昨今、動画は簡単に作成できるので、仕事やプライベートで動画を処理しないといけない場面は増えていることだろう。スマートフォンで手軽にクオリティの高い動画を撮影できるだけでなく、手軽に動画を作成するツールも多い。加えて、PowerPointなど動画とそれほど関係なさそうなツールにも、動画を編集したり、書き出したりする機能がついている。

とは言え、手元にある100個の動画ファイルを、一つずつ開いて編集処理しなければならないとしたら、とても大変だろう。そこでプログラミングの出番だ。

必要ライブラリのインストール - FFmpeg

今回利用するのは、FFmpegとimageioというPythonのライブラリだ。

まずは、FFmpegをインストールしよう。FFmpegはオープンソースの動画・音声のコマンドラインツールだ。いろいろなソフトウェアに組み込まれており信頼性も高い。

【WindowsでFFmpegをインストール】

FFmpegのWindows/Linux版はこちらからダウンロードできる。用途や環境ごとに異なるパッケージが配布されているが、例えば、こちらのリンクからからダウンロードできる。

ダウンロードして、ZIPアフィルを解凍してドキュメントフォルダなどにコピーすると、binフォルダがあり、その中にffmpeg.exeというファイルがある。これを利用可能にするために環境変数PATHにbinフォルダを通そう。

環境変数を編集するには、画面下部にあるWindowsロゴがあるスタートメニューをクリックし「環境変数の編集」を検索しよう。そして、「PATH」を選んで「新規」ボタンを押して、自身のbinフォルダのパスを入力しよう。

  • 環境変数にFFmpegのbinフォルダを追加

    環境変数にFFmpegの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)では、背景を透過したロゴを読み込む。

(*3)では、入力フォルダにある動画ファイルの一覧を取得する。そして、一つずつ変換関数add_logo_to_videoを実行して動画を出力フォルダに保存する。

(*4)の関数add_logo_to_videoは、動画にロゴを描画する処理を行う。(*5)では動画を読み込むreaderを作成し、(*6)では書き込み用のwriterを作成する。

(*7)以降では動画の書くフレームを読み出して一枚ずつロゴ画像を重ね合わせる処理を行う。

なお、(*8)ではロゴを動画の1/3サイズにリサイズして利用する。(*9)ではロゴの位置が右上になるように座標を計算する。そして、(*10)では画像にロゴを重ね合わせる。そして、(*11)ではwriterを利用して画像を書き込む。

まとめ

今回は、複数の動画ファイルに対して、連続でロゴ画像を書き込むプログラムを作ってみた。動画ファイルを処理する機会は多いので参考になるだろう。

なお、今回のプログラムは画像のみを処理するプログラムであるため、音声データが失われてしまう。ただし、FFmpegを利用することで、動画から音声を取り出して別の動画ファイルに移し変えることができる。以下はターミナル上で実行するコマンドだ。これを参考にしてプログラムに組み込むと良いだろう。

# (1) in.mp4の音声をout.aacに保存する
ffmpeg -i in.mp4 -q:a 0 -map a audio.aac

# (2) audio.aacをout.mp4に差し込んでout2.mp4に保存する
ffmpeg -i out.mp4 -i audio.aac -c:v copy -c:a aac -strict experimental out2.mp4
自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。直近では、「実践力をアップする Pythonによるアルゴリズムの教科書(マイナビ出版)」「シゴトがはかどる Python自動処理の教科書(マイナビ出版)」「すぐに使える!業務で実践できる! PythonによるAI・機械学習・深層学習アプリのつくり方 TensorFlow2対応(ソシム)」「マンガでざっくり学ぶPython(マイナビ出版)」など。