今回は、BigGANデモを使って、ランダムに選んだ画像でモーフィングする動画を自動で作ってみます。
こんにちは cedro です。
先回、BigGANデモで、サクッと遊んでみました のブログの最後に「これ映像関係の人とか、かなりイマジネーションがわくツールになるんじゃないかな」とコメントしたように、特にモーフィングのGIF動画は何度見ても面白いです。
そうした中で、次から次へとランダムに画像を選んでモーフィングする動画を作ったら、かなり刺激的で面白いと思ったわけです。
しかし、先回ご紹介した方法だと、作るのにやたら手間が掛かるので、なんとかこれを自動化したいと考えました。
ということで、今回は、BigGANデモを使って、ランダムに選んだ画像でモーフィングする動画を自動で作ってみます。
早速、動かしてみる
コードの説明は後にして、早速動かしてみましょう。
BigGAN TF Hub Demo に行き、Google account でログインします。
まずは、先回同様、[ 1 ] から [ 5 ] までのボタンを順にクリックして、コードを実行して下さい。
すると、コードを入力するセルが表示されます。ここに、下記のコードをコピペします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#@title Interpolation { display-mode: "form", run: "auto" } import cv2 import random num_samples = 1 num_interps = 40 length = 45 #@param {type:"slider", min:15, max:120, step:1} truncation = 0.2 #@param {type:"slider", min:0.02, max:1, step:0.02} def interpolate_and_shape(A, B, num_interps): interps = interpolate(A, B, num_interps) return (interps.transpose(1, 0, *range(2, len(interps.shape))) .reshape(num_samples * num_interps, *interps.shape[2:])) fourcc = cv2.VideoWriter_fourcc('m','p','4','v') video = cv2.VideoWriter('BigGAN_video.mp4', fourcc, 10.0, (256, 256)) kn = random.randint(0,100) kc = random.randint(0,999) for i in range(length): noise_seed_A = kn category_A = kc noise_seed_B = random.randint(0,100) category_B = random.randint(0,999) kn = noise_seed_B kc = category_B z_A, z_B = [truncated_z_sample(num_samples, truncation, noise_seed) for noise_seed in [noise_seed_A, noise_seed_B]] y_A, y_B = [one_hot(category * num_samples) for category in [category_A, category_B]] z_interp = interpolate_and_shape(z_A, z_B, num_interps) y_interp = interpolate_and_shape(y_A, y_B, num_interps) ims = sample(sess, z_interp, y_interp, truncation=truncation) for i in range(len(ims)): img = ims[i] img = img[:, :, [2,1,0]] video.write(img) video.release() |
このコードをコピーして、先程のセルに張り付けます。
後は、ボタンを押せばOK。デフォルトは、ランダムに選んだ画像から画像への4秒間のモーフィングを45回やって、3分間のmp4ビデオを作成します。作成には3分半くらい時間が掛かり、ボタンのクルクルが止まったら、処理完了です。
ビデオの長さは length で調整出来、length=15が1分に相当します。生成画像の多様性を変化させたい場合は、truncation を調整します。値が低いと多様性は下がり(画質は向上)、値が高いと多様性は上がり(画質は低下)ます。
ボタンのクルクルが止まったら、左側の目次があるところで、ファイルのタブを選択し、赤丸の更新ボタンを押します。
すると、BigGAN_video.mp4 というファイルが現れますので、右クリックでダウンロードを選択すればダウンロードを開始します。ビデオの内容が気に入らなければ、再度ボタンを押せば、別のビデオが作成されます。エンジョイ!
どんなビデオが出来るのか
これは、length = 45, truncation = 0.2 で動画生成したもの(17.3MB)をそのままYoutubeにアップロードした例です。
これは、上記ビデオに音楽を付けてYoutubeにアップロードした例です。音楽を付けると雰囲気が出ますよね。なお、これを再生すると音が出るのでご注意下さい。
コードを説明します
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#@title Auto Interpolation { display-mode: "form", run: "auto" } import cv2 # ビデオライブラリーインポート import random # 乱数発生ライブラリーインポート num_samples = 1 num_interps = 40 # 画像間補完に使う画像数 # 画像間補完を行う回数 length = 45 #@param {type:"slider", min:15, max:120, step:1} truncation = 0.2 #@param {type:"slider", min:0.02, max:1, step:0.02} def interpolate_and_shape(A, B, num_interps): interps = interpolate(A, B, num_interps) return (interps.transpose(1, 0, *range(2, len(interps.shape))) .reshape(num_samples * num_interps, *interps.shape[2:])) |
7行目 num_interps = 40 は1回の画像間補完に使う画像数で、ビデオは10フレーム / 秒設定なので、1回の画像間補完は4秒掛かります。
9行目 length = 45 は画像間補完を行う回数で、時間に換算すると4秒/回 ×45回=180秒で 3分となります。つまり、length = 15 が1分に相当します。
1 2 3 4 5 6 |
# 動画コーデックは mp4 を指定 fourcc = cv2.VideoWriter_fourcc('m','p','4','v') # 動画の保存名, 10フレーム/秒, 256×256ピクセルサイズ を指定 video = cv2.VideoWriter('BigGAN_video.mp4', fourcc, 10.0, (256, 256)) |
動画作成に関する設定の部分です。3行目は動画コーデックで mp4 を指定しています。5行目はコンテンツ仕様で、保存名、毎秒のフレーム数、画像サイズを指定しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
kn = random.randint(0,100) # 0〜100 の整数の乱数を生成 kc = random.randint(0,999) # 0〜999 の整数の乱数を生成 for i in range(length): noise_seed_A = kn category_A = kc noise_seed_B = random.randint(0,100) category_B = random.randint(0,999) kn = noise_seed_B kc = category_B z_A, z_B = [truncated_z_sample(num_samples, truncation, noise_seed) for noise_seed in [noise_seed_A, noise_seed_B]] y_A, y_B = [one_hot(category * num_samples) for category in [category_A, category_B]] z_interp = interpolate_and_shape(z_A, z_B, num_interps) y_interp = interpolate_and_shape(y_A, y_B, num_interps) ims = sample(sess, z_interp, y_interp, truncation=truncation) |
画像間補完を行う部分です。基本的に、元のコードをlength 回繰り返す仕様です。1回目のnoise_seed_Aとcategory_Aはランダムに決めますが、2回目以降 noise_seed_Aとcategory_A は、その前のnoise_seed_Bとcategory_Bのものを使い、連続した画像間補完になるようにしています。
1 2 3 4 5 6 7 8 9 |
for i in range(len(ims)): # 1フレーム取得 img = ims[i] # BRGをRBGに変換 img = img[:, :, [2,1,0]] # ビデオに書き込む video.write(img) |
ビデオ作成をする部分で、「 ims = 生成した40枚の numpy.nadaray 」 を1フレームづつ直接ビデオに書き込んでいます。
4行目で1フレーム取得し、6行目で OpenCV への入力画像はBGRの順番ににする必要があるので RBGからBGRの順番に直し、8行目でビデオに書き込みます。
いかがでしたか。お気に入りのビデオに出会えましたかでしょうか。
今回、OpenCVの動画作成機能を使ってみたのですが、これは便利ですねー。今まで、静止画を作ってからGIF動画を作っていたのですが、直接動画が作れるとすごく生産性が上がります。やっぱり、便利なものは、ドンドン使うべきですね、
では、また。