FFmpegとPillowで動画をGIFに変換

FFmpegで動画をGIFに変換

ffmpeg -i input.mp4 -vf scale=300:-1 -r 10 output.gif
  • -r オプションでフレームレートを指定する。

  • scale=300:-1scale=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)

Tags:

Updated: