概要
複数の画像ファイルからスライドショーの動画を作成するのは ffmpeg
等で簡単に可能ですが、単に画像を結合した場合では以下のようにやや味気ないスライドショーになってしまいます。
そこで、以下のようなフェードエフェクトを導入することで、ややリッチな動画になります。
ffmpeg
でもフェードの導入は可能ですが、入力ファイルの数が多いとコマンドが煩雑になるため、ここでは Python で実装する方法を紹介します。
入力画像
入力する画像は何でも良いですが、ここでは例として CC0 ライセンスで利用可能な Pixabay の画像を利用します。
以下の5枚をダウンロードし、./img/
に保存します。
- https://pixabay.com/photos/dandelion-flower-close-up-macro-8318529/
- https://pixabay.com/photos/duck-mallard-lake-pond-waterbird-8297668/
- https://pixabay.com/photos/european-shorthair-cat-kitten-8267220/
- https://pixabay.com/photos/fox-animal-mammal-canine-wildlife-8308116/
- https://pixabay.com/photos/gosling-chick-bird-baby-goose-7938451/
Pythonによる実装
Pythonを使ってフェードエフェクトを導入した動画を作成します。Pillow の Image.blend
で連続する2枚の画像をブレンドしたフレームを生成し、 OpenCV の cv2.VideoWriter
を用いて動画を出力するという内容になっています。
import pathlib
import cv2
import numpy as np
from PIL import Image
def main():
fps = 10 # 出力する動画のフレームレート
fade_frames = 20 # 入力画像1枚に対するフェード適用後のフレーム数
img_dir = pathlib.Path("./img/")
imgs = [Image.open(img_file) for img_file in img_dir.glob("*.jpg")]
deltas = np.linspace(0.0, 1.0, fade_frames, endpoint=False) # フェード適用時のフレーム割り
fourcc = cv2.VideoWriter_fourcc(*"H264")
video = cv2.VideoWriter("video.mp4", fourcc, fps, imgs[0].size)
for i in range(len(imgs) - 1):
for delta in deltas:
alpha = (1 - np.cos(delta * np.pi)) / 2 # 三角関数で滑らかに補間する
img_blended = Image.blend(imgs[i], imgs[i + 1], alpha) # delta=0(alpha=0)では元画像が使われる
video.write(cv2.cvtColor(np.asarray(img_blended), cv2.COLOR_RGB2BGR))
video.write(cv2.cvtColor(np.asarray(imgs[-1]), cv2.COLOR_RGB2BGR)) # 最後の元画像のフレームも追加
video.release()
if __name__ == "__main__":
main()
実行すると、 video.mp4
に以下の動画が出力されます。(記事上では別途出力したgif動画を貼り付けています。)
Image.blend
の引数 alpha
の算出方法の違いによる差異
上記実装の22行目では alpha = (1 - np.cos(delta * np.pi)) / 2
として、三角関数を使った補間をしていますが、Image.blend
の引数 alpha
は0~1の数値であれば良いので、 alpha = delta
としても問題はありません。以下は alpha = delta
とした場合と alpha = (1 - np.cos(delta * np.pi)) / 2
とした場合の比較です。
左: alpha = delta
右: alpha = (1 - np.cos(delta * np.pi)) / 2
好みのレベルですが、三角関数で補間した右の方がややメリハリが効いた遷移に見えます。