概要
「同じ場所から毎日撮っている写真」などをつなぎ合わせて、スライドショーっぽい動画にする方法を紹介。PythonのライブラリMoviePyを使用する。
動作確認環境
- Python3.6(Python2系での動作は未確認)
- OS : Ubuntu 18.04
- Pythonがインストール可能であれば、他のOSでも問題なく動くはず
事前準備
- Pythonのインストール(説明は割愛)
- 下記コマンドでMoviePyをインストール
$ pip install moviepy
-
[参考]MoviePyのインストール方法が書かれたサイト
- https://zulko.github.io/moviepy/install.html
- 今回やりたいことを実現するだけであれば、
pip install moviepy
のコマンドのみで問題ないはず
-
スライドショーにする静止画像を用意
-
input
ディレクトリ配下に、スライドショーでつなげたい順番にインデックスをつけて静止画像(拡張子は.png
,.jpg
など)を配置 - 以下はその一例だが、Pythonのソース内でファイル名で昇順ソートした際にスライドショーでつなげたい順番に並ぶのであれば、以下の名前規則に従わなくてもOK。
-
input
├── IMG_0000.jpg
├── IMG_0001.jpg
├── IMG_0002.jpg
├── ...
ソース全体
- 以下のソースを
python create_slideshow.py
で実行すると、静止画を0.5秒間隔でつなげた動画像output.mp4
が出来上がる。
create_slideshow.py
#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
import glob
from moviepy.editor import *
if __name__ == '__main__':
# inputディレクトリ以下の拡張子が.jpgのファイル名リストを一括取得
file_list = glob.glob(r'input/*.jpg')
# ファイル名リストを昇順にソート
file_list.sort()
# スライドショーを作る元となる静止画情報を格納する処理
clips = []
for m in file_list:
clip = ImageClip(m).set_duration('00:00:00.50')
clip = clip.resize(newsize=(640,480))
clips.append(clip)
# スライドショーの動画像を作成する処理
concat_clip = concatenate_videoclips(clips, method="compose")
concat_clip.write_videofile(r"output.mp4",
fps=24,
write_logfile=True,
)
解説
スライドショーを作る元となる静止画情報を格納する処理
clips = []
for m in file_list:
clip = ImageClip(m).set_duration('00:00:00.50')
clip = clip.resize(newsize=(640,480))
clips.append(clip)
-
ImageClip(m).set_duration('00:00:00.50')
- 各画像の表示時間を設定。数値入力も可能で、その場合の単位は「秒」になる模様
-
clip.resize(newsize=(640,480))
- 動画像(clip)のサイズを変更。一般的に静止画の画像サイズは動画像よりも大きく、そのまま処理するとドデカい動画像が出来てしまうので、予めここでサイズ変更していた方がよさそう。
- ちなみに筆者が試した画像のサイズは4032×3024で、リサイズせずに変換をかけたらマシンのリソース不足で処理がハングアップした…
スライドショーの動画像を作成する処理
concat_clip = concatenate_videoclips(clips, method="compose")
concat_clip.write_videofile(r"output.mp4",
fps=24,
write_logfile=True,
)
- concatenate_videoclips(clips, method="compose")
- 動画像リスト(clips)をつなぎ合わせて一つの動画像にする処理。
- 引数
method
はchain
またはcompose
を選択可能。ドキュメントを見ると、つなぐ前の動画像のサイズが異なる場合はcompose
を使う方がよさそう。今回の場合は、予め動画像のサイズを640x480にしていて同じサイズになっているので、method="chain"
にしても動くことを確認済。
- concat_clip.write_videofile(r"output.mp4",…
- 動画像をファイル出力
-
write_logfile=True
にすると、出力ファイルを作成するログがoutput.mp4.log
という名前で下記のように出力され、裏でffmpegが動いていることを確認できる。
output.mp4.log
ffmpeg version 4.2.2-static https://johnvansickle.com/ffmpeg/ Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 8 (Debian 8.3.0-6)
configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gmp --enable-libgme --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libdav1d --enable-libxvid --enable-libzvbi --enable-libzimg
libavutil 56. 31.100 / 56. 31.100
libavcodec 58. 54.100 / 58. 54.100
libavformat 58. 29.100 / 58. 29.100
libavdevice 58. 8.100 / 58. 8.100
libavfilter 7. 57.100 / 7. 57.100
libswscale 5. 5.100 / 5. 5.100
libswresample 3. 5.100 / 3. 5.100
libpostproc 55. 5.100 / 55. 5.100
Input #0, rawvideo, from 'pipe:':
Duration: N/A, start: 0.000000, bitrate: 176947 kb/s
Stream #0:0: Video: rawvideo (RGB[24] / 0x18424752), rgb24, 640x480, 176947 kb/s, 24 tbr, 24 tbn, 24 tbc
Stream mapping:
Stream #0:0 -> #0:0 (rawvideo (native) -> h264 (libx264))
[libx264 @ 0x6856ac0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 0x6856ac0] profile High, level 3.0, 4:2:0, 8-bit
[libx264 @ 0x6856ac0] 264 - core 159 r2991 1771b55 - H.264/MPEG-4 AVC codec - Copyleft 2003-2019 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=24 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'output.mp4':
Metadata:
encoder : Lavf58.29.100
Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p, 640x480, q=-1--1, 24 fps, 12288 tbn, 24 tbc
Metadata:
encoder : Lavc58.54.100 libx264
Side data:
cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
frame= 85 fps=0.0 q=28.0 size= 0kB time=00:00:01.33 bitrate= 0.3kbits/s speed=2.58x
frame= 148 fps=145 q=28.0 size= 512kB time=00:00:03.95 bitrate=1059.7kbits/s speed=3.89x
frame= 205 fps=130 q=28.0 size= 768kB time=00:00:06.33 bitrate= 993.4kbits/s speed= 4x
...