TL;DR
CartoonGANのコードをgifに対応させて試した
はじめに
最近、GAN(Generative Adversarial Network)の実装で、面白いものが増えて来ているような気がしています。
今まで自分でGANを実装したことは無いんですが、CartoonGANの実装が公開されていたので、触って遊んで見ました。
画像をアニメ風に変換するのは、パッケージをいくつかインストールするだけで、すぐに出来ました。
サンプルでgifの結果もあったので、試してみようと思ったのですが、
valid_ext = ['.jpg', '.png']
このようになっていたのでjpgとpngしか変換できませんでした。
またそれ以降の処理を見ても、画像にしか対応しておらず、gifには対応していないようでした。
少々手間だとは思いつつも、せっかくなのでgifでもCartoonGANでアニメ風に変換できるようにしようと思い
ちまちまといじって見ました。
具体的には、gifをフレームごとに分解してCartoonGANで変換し、その画像を一つのgifにまとめただけです。
変更点
gifを一枚ずつ分解する
まずはgifを読み込みます。
input_gif = Image.open(os.path.join(opt.input_dir, filename))
読み込んだgifは
.seek(number)
とすることで、フレーム毎に分割することができるようなので、一枚ずつ分割して、CartoonGANに入力できるようにしておきます。
convert_image
という関数に画像を入力することで、変換された画像が手に入るように書き換えています。
for nframe in range(input_gif.n_frames):
input_gif.seek(nframe)
output_image = convert_image(
model, input_gif.split()[0].convert("RGB"))
CartoonGANで変換された画像を、順番にファイル名をつけながらtmp/以下に保存します。
完成形はこちらです。
input_gif = Image.open(os.path.join(opt.input_dir, filename))
for nframe in range(input_gif.n_frames):
print(" {} / {}".format(nframe, input_gif.n_frames), end="\r")
input_gif.seek(nframe)
output_image = convert_image(
model, input_gif.split()[0].convert("RGB"))
save(image=output_image,
name="tmp/{name}_{nframe:04d}.jpg".format(**{
"dir": opt.output_dir,
"name": "{}_{}".format(filename[:-4], opt.style),
"nframe": nframe
}))
次で、ファイルを一括で読み込み、gifに整形するのですが、
その時に読み込む順番が変わってしまわないようにするために
{nframe:04d}
としています。
フレームが4桁を超える場合は、ここの数字をいじる必要があります。
複数のjpgをgifにまとめる
次に、先ほど保存したjpgをgifにまとめていきます。
先ほど、ファイル名に数字を割り振り順番が分かるようにしたので
sortしてからjpgファイルを順に読み込み、listにします。
sorted(os.listdir("tmp")):
元のgifファイルの速度と揃えるために、パラメータを与えて保存します。
完成形はこちらです。
def jpg_to_gif(input_image, input_filename):
images = []
for filename in sorted(os.listdir("tmp")):
ext = os.path.splitext(filename)[1]
if ext not in valid_ext:
continue
image = Image.open("tmp/{}".format(filename)).convert("RGB")
images.append(image)
images[0].save("{dir}/{name}.gif".format(**{
"dir": opt.output_dir,
"name": "{}_{}".format(input_filename[:-4], opt.style)
}),
save_all=True,
append_images=images[1:],
optimize=False,
duration=input_image.info["duration"],
loop=0)
gifファイルの扱いは、知らなければ掴みにくいのですが
分かれば、手間なだけで、特段引っかかることはなさそうです。
Colaboratoryの使い方
ローカルで実行しても良いのですが、pcがすごい熱を発するのでやめておいた方が良いでしょう。
また、cpuでdeep learningを実行するのは、処理時間的に考えてもあまり良い手段では無いと思います。
ということで、いつも通りgoogleにColaboratoryを使わせてもらいます。
gpuで実行したいので、ランタイムがgpuになっていることを確認してから、次のコマンドを実行します。
!git clone https://github.com/t-Asai/CartoonGAN-Test-Pytorch-Torch.git
%cd "CartoonGAN-Test-Pytorch-Torch"
!pip install -r requirement.txt
!sh pretrained_model/download_pth.sh
これで最低限必要な準備は整っているはずです。
オプションをいくつか付けることも可能ですが、一旦何もつけずに実行します。
この実行の仕方だと、jupyter notebookである必要性がカケラもないのは目を瞑る
!python test.py
これで、test_output以下に、結果が保存されていることが分かるかと思います。
ここまでで動作確認は終わりです。
次は、自分のgifファイルを良しなに変更するために
colaboratory上にファイルをアップロードしたり、変換後のファイルをダウンロードする方法について説明します。
やり方を見つけるまでは苦労するかもしれませんが、
見つけてしまえば単純です。
google.colab
を使ってアップロードとダウンロードが可能です。
「zipにしてからダウンロードしたい」などの要望がある場合は、shellをcolaboratory上で実行すれば可能です。
from google.colab import files
import os
files = files.upload()
for filename in sorted(os.listdir("test_output")):
files.download("test_output/{}".format(filename))
google driveとcolaboratoryを同期させる方法もありますが、
個人的に、あまり好きな方法ではないので使いません。
結果
gifファイルでも、問題なくアニメ風に変換することができるようになりました。