目的
AviUtlにて,連番BMP出力(または連番PNG出力)した画像から特定のfps(秒間フレーム数)のパラパラ漫画風のmp4動画ファイルを作成する.
Python3は既にインストールされている前提で,PythonとOpenCVライブラリーを使用した方法を紹介する.
名称 | 規格 | 製造会社 | 備考 |
---|---|---|---|
オペレーティングシステム | Windows 10 Pro 64ビット,22H2 | マイクロソフト | |
Python3 | 3.12.2 | Python Software Foundation | python3 --version にて確認 |
package installer for Python(pip) | 24.0 | Python Software Foundation | python3 -m pip list にて確認 |
opencv-python | 4.9.0.80 | OpenCV Team | |
Python Image Library(Pillow,PIL) | 10.2.0 | ? | gif出力は採用せず(後述) |
結論
インストール~mp4動画生成までを順番に記載する
インストール
D:\>python3 -m pip list Package Version ------- ------- pillow 10.2.0 pip 24.0 D:\>python3 -m pip install opencv-python Defaulting to user installation because normal site-packages is not writeable Collecting opencv-python Using cached opencv_python-4.9.0.80-cp37-abi3-win_amd64.whl.metadata (20 kB) Collecting numpy>=1.21.2 (from opencv-python) Downloading numpy-1.26.4-cp312-cp312-win_amd64.whl.metadata (61 kB) ---------------------------------------- 61.0/61.0 kB 819.4 kB/s eta 0:00:00 Using cached opencv_python-4.9.0.80-cp37-abi3-win_amd64.whl (38.6 MB) Downloading numpy-1.26.4-cp312-cp312-win_amd64.whl (15.5 MB) ---------------------------------------- 15.5/15.5 MB 46.7 MB/s eta 0:00:00 Installing collected packages: numpy, opencv-python WARNING: The script f2py.exe is installed in 'C:\Users\so2akt\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\Scripts' which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. Successfully installed numpy-1.26.4 opencv-python-4.9.0.80 D:\>python3 -m pip list Package Version ------------- -------- numpy 1.26.4 opencv-python 4.9.0.80 pillow 10.2.0 pip 24.0
f2py.exeが既にインストールされているがPATHに登録されていないという警告が出ているが,今回の手順では問題なかったため,無視して進めている.
連番画像からmp4動画作成
以下のPythonコードを,連番画像と同一のディレクトリーで実行する.以下の例では,連番画像が5_00000.png
,5_00001.png
,5_00002.png
,……,5_01113.png
の合計1114枚あり,それら画像を約0.618(≒2200 / 3555)fps*1の5.mp4
として動画にするように処理している.
import numpy as np import cv2 filnam = '5' delim = '_' ext_in = '.png' ext_out = '.mp4' zfill_num = 5 # 連番部分が00001という形式のように5ケタなので5 fps = 2200 / 3555 # 計算値の小数点以下の精度は不明…… frm_num = 1113 # フレーム数(≒結合する画像の連番番号最大値) # 1枚目の画像を読み込んで,幅と高さを確定させる img = cv2.imread(filnam + delim + str(0).zfill(zfill_num) + ext_in) w = img.shape[1] h = img.shape[0] codec = cv2.VideoWriter_fourcc(*'mp4v') video = cv2.VideoWriter(filnam + ext_out, codec, fps, (w, h)) for i in range(frm_num): img = cv2.imread(filnam + delim + str(i).zfill(zfill_num) + ext_in) video.write(img) video.release()
画像ファイル名が連番ではない場合
連番画像ではあるが,5_00000.png
,5_00029.png
,5_00059.png
,……というように数字で言う30ごとに飛び飛びのファイル名の場合,上記のPythonコードを一部変更する必要がある:
import numpy as np import cv2 filnam = '5' delim = '_' ext_in = '.png' ext_out = '.mp4' zfill_num = 5 # 連番部分が00001という形式のように5ケタなので5 fps = 2200 / 3555 # 計算値の小数点以下の精度は不明…… frm_sta = 0 # 結合する画像の連番番号開始値 frm_end = 1113 # 結合する画像の連番番号最大値 frm_delta = 30 # 結合する画像の連番番号増分 # 1枚目の画像を読み込んで,幅と高さを確定させる img = cv2.imread(filnam + delim + str(0).zfill(zfill_num) + ext_in) w = img.shape[1] h = img.shape[0] codec = cv2.VideoWriter_fourcc(*'mp4v') video = cv2.VideoWriter(filnam + ext_out, codec, fps, (w, h)) # 00000番から始める場合は,0→29→59→……としたいが,増分30では,0→30→60→……となってしまうため,-1から繰り返す # それ以外の,たとえば,29→59→89のように00029番から始める場合は29から繰り返せばOK if frm_sta == 0: frm_sta = -1 for i in range(frm_sta, frm_end, frm_delta): # iが-1のときは00000番を意味するのでif文で分岐している img = cv2.imread(filnam + delim + str(0 if i < 0 else i).zfill(zfill_num) + ext_in) video.write(img) video.release()
その他
感想
当初はmp4ではなく,Pillowライブラリーを使ったgifファイルとして生成し,AviUtlでイロイロ結合してmp4出力させようとしていた.しかしながら,gifをAviUtlで複数回読み込ませるとAviUtlで例外が発生してAviUtlが強制終了してしまっていたため,OpenCVを使用してmp4ファイル生成に至った.
OpenCVのインストールに手間・時間がかかると思い込んでいたが,Pythonライブラリーとしてのインストールは数秒であり,使い方例も豊富に存在したので手軽に実行できた.
なお,Pillowライブラリーを使ったgifファイル生成のソースコードは以下のとおりだが*2:
from PIL import Image filnam = '5' delim = '_' ext_in = '.png' ext_out = '.gif' zfill_num = 5 # ファイル_00001.pngなので5ケタ dur = 3555 / 2200 # フレーム間隔ms frm_num = 1113 # フレーム数 pictures = [] for i in range(frm_num): pic_name = filnam + delim + str(i).zfill(zfill_num) + ext_in img = Image.open(pic_name) pictures.append(img) pictures[0].save(filnam + ext_out, save_all = True, append_images = pictures[1:], optimize = True, duration = dur, loop = 0)
今までは……
以下の画像のように,1枚ごとにAviUtlに読み込ませる→長さを変更,を画像の枚数ごとに繰り返していた.さすがにもっとよい方法があるだろうと思い,今回の対策大作にたどり着いた.
改訂履歴
# | 日付 | 内容 |
---|---|---|
1 | 2024/02/11 | Pillowライブラリーを使用したgifファイル出力について追記 |
2 | 2024/02/17 | 画像ファイル名が連番ではない場合のPythonコードを追記 |
参考サイト
- OpenCVで動画作成 VideoWriter - Python徹底解説 · Daizyu.com(2024/02/10現在)
- Python(Google Colab)で.pngを.mp4にする(2024/02/10現在)
- 【python】複数画像からパラパラ漫画(gifアニメ)を作成する方法! - ヒガサラblog(2024/02/11現在)
- [解決!Python]条件式(三項演算子)を使ってif文を1行で書くには:解決!Python - @IT(2024/02/17現在)