FFmpegとPillowで動画をGIFに変換
FFmpegで動画をGIFに変換
ffmpeg -i input.mp4 -vf scale=300:-1 -r 10 output.gif
-
-r オプションでフレームレートを指定する。
-
scale=300:-1
はscale=w=300:h=-1
と同じ、横幅を300ピクセルに設定し、縦幅はアスペクト比を維持して自動調整する。
もっと高画質のGIFを出力したい場合
ffmpeg -i input.mp4 -vf "fps=10,scale=300:-1:flags=lanczos,split[o0][o1];[o0]palettegen=stats_mode=full[p];[o1][p]paletteuse" output.gif
- split フィルタで入力の動画から出力
[o0]
と出力[o1]
を作成する。 - palettegen
フィルタを使用してパレット
[p]
を生成する。 - paletteuse フィルタは動画に生成されたパレット
[p]
を適用してGIFを作成する。
PillowでGIFを切り取り
GIFのフレームを取得し、numpy 配列として読み込む。 渡された座標によって画像を切り取って、Pillow image を取得する。 そして、最初のフレームに残りのフレームを追加してGIFを作成する。
import numpy as np
from PIL import Image, ImageSequence
def crop_gif(path, box):
gif = Image.open(path)
frames = ImageSequence.Iterator(gif)
left, upper, right, lower = box
def get_cropped_imgs(frames):
for frame in frames:
img = frame.copy().convert("RGB")
# convert image to numpy array
img_array = np.array(img)
# crop image
img_array = img_array[upper:lower, left:right]
# convert numpy array to image
img = Image.fromarray(np.uint8(img_array))
yield img
imgs = get_cropped_imgs(frames)
# get first image
output = next(imgs)
output.save(fp='output.gif',
save_all=True,
append_images=list(imgs),
duration=10,
loop=0)
if __name__ == '__main__':
path = 'input.gif'
box = (0, 0, 100, 100)
crop_gif(path, box)