アニメーションGIFから連続したコマの静止画(↓こういうやつ)を生成したかったので方法を調べました。
実現方法
ご指摘いただきましたが、
ffmpeg
のコマンドで出来るそうです。
コメント欄参照。
OpenCVを使えばgifのフレー ム単位読み出しとかができるとのことなのでこれを使います。
def read_gif(filename):
gif = cv2.VideoCapture('sample.gif')
_, img = gif.read()
return img
準備
とりあえず今回は、Python3とOpenCVで実装します。
必要なライブラリをインストールしておきます。
pip3 install opencv-python
pip3 install numpy
一枚の画像作成
あまりスマートじゃないですが、コードは以下のようになりました。
単純にgifのフレームを読み出していって、右の折り返し列が来たら次の行に進めて画像を出力していく感じです。
最終的にマトリクス状の一枚の静止画になります。フレームが足りない部分は黒塗りの画像で埋めます。
combine.py
import cv2
import os
import numpy as np
def make_blank(h, w):
return np.tile(np.uint8([0,0,0]), (h,w,1))
def combine_gif(filename):
# gif読み込み
gif_stream = cv2.VideoCapture(filename)
# 折り返し列
split = 10
# フレーム読み込み処理
vlist, hlist = [], []
pre_w, i = 0, 1
success = True
while success:
success, frame = gif_stream.read()
# n行目を作成するリストに追加
if frame is not None:
hlist.append(frame)
# 折り返し地点(or 読み込みがない)場合、
if (i % split == 0 or not success) and len(hlist) > 0:
# widthの差分を計算して黒埋め画像作成
h, w = cv2.hconcat(hlist).shape[:2]
diff = pre_w - w
if diff > 0:
hlist.append(make_blank(h, diff))
# 横一列を結合して、行リストに追加
vlist.append(cv2.hconcat(hlist))
hlist = []
pre_w = w
i += 1
# 行リストを結合して、画像出力
vimg = cv2.vconcat(vlist)
cv2.imwrite('output.png', vimg)
if __name__ == '__main__':
combine_gif("sample.gif")
連番画像作成
一枚の画像じゃなくて複数の連番画像を作成する場合は以下のような感じです。
split.py
import cv2
import os
def split_gif(filename):
# 保存先ディレクトリ作成
output_dir = "output"
if not os.path.exists(output_dir):
os.mkdir(output_dir)
# GIF読み込み
gif_stream = cv2.VideoCapture(filename)
# 連番画像出力
i = 0
while True:
success, frame = gif_stream.read()
if not success:
break
path = os.path.join(output_dir, str(i) + ".png")
cv2.imwrite(path, frame)
i += 1
if __name__ == '__main__':
split_gif("sample.gif")