10/15(火)-10/19(土) 岐阜県(南濃温泉「水晶の湯」)で自動運転車の実証実験を行います☆彡

4-5. Auto-encoderでお寿司をモーフィングする(ソースコードあり)

やること

オートエンコーダでお寿司のモーフィング(画像がだんだん変化するアレ)を行います。

使うもの

Google Colaboratoryが利用可能です。

Google Colab

WinPython3.6をおすすめしています。

WinPython - Browse /WinPython_3.6/3.6.7.0 at SourceForge.net
Portable Scientific Python 2/3 32/64bit Distribution for Windows

こちらの勉強会を参考にしています。

AIワークショップ|初心者だけどCNNで次元圧縮できちゃった (2019/02/25 19:00〜)
# 「そうだ、次元を圧縮しよう」 中高生のなりたい職業ランキング1位「次元圧縮師」(大きな声で嘘をつく) ## オンラインコミュニティ 情報交換・質問・クレームなどはAI FASHIONのSlack(自由参加)でお願いします。 ## コンセプト CNNで画像の次元圧縮をしてみる。期待しすぎてはいけない。初心者...
AI勉強会|GANやVAEが書けるようになりたい (2019/10/11 19:30〜)
## 久しぶりに本郷で開催します こちらがライブ配信のアーカイブ動画です。 ## 参加方法 抽選や承認はありませんので、好き勝手にお越しください。 ## オンラインコミュニティ 情報交換・質問・クレームなどはAI FASHIONのSlack(自由参加)でお願いします。 ビネクラの公式Twitterもよろし...

ソースコード

学習で保存されたエンコーダとデコーダの重みを指定してください(encoder_500.h5、decoder_500.h5)。実行すると、「AE_morph」フォルダに画像が保存されていき、さらにmorph.gifも保存される親切設計です。

import os
import numpy as np
import numpy.random as nr
from PIL import Image
import matplotlib.pyplot as plt
from keras.models import load_model
np.set_printoptions(threshold=np.inf)

#書き換える場所
#======================================
#使用する重み
para_encoder = 'AE_para/encoder_500.h5'
para_decoder = 'AE_para/decoder_500.h5'

#乱数列の次元
z_dim = 100
#補完数(58だと60枚出ます)
img_num = 58

#モーフィングを保存するフォルダ
img_f = 'AE_morph/'
#======================================



#教師データからランダムに2つ、エンコーダにいれる
#======================================
i, j = nr.choice(range(len(files)), 2, replace=False)
files = os.listdir(f)

imgs = []
img_a = Image.open(f + files[i]).convert("RGB"); img.close
imgs.append(np.array(img_a))
img_b = Image.open(f + files[j]).convert("RGB"); img.close
imgs.append(np.array(img_b))

imgs_array = np.array(imgs)

#-1~+1に規格化
imgs_array = (imgs_array - 127.5) / 127.5

#エンコーダにいれる
encoder = load_model(para_encoder)
ab = encoder.predict(imgs_array)

a = ab[0]
b = ab[1]
#======================================


#間の補完
#======================================
zs = np.zeros((img_num+2, z_dim))
for i in range(img_num+2):
    zs[i] = a * ((img_num+1-i)/(img_num+1)) + b * (i/(img_num+1))
#======================================


#generatorで画像を生成
#======================================
decoder = load_model(para_decoder)
imgs_array = decoder.predict(zs)
imgs = []
for i in range(len(imgs_array)):
    img = Image.fromarray(np.uint8(imgs_array[i] * 127.5 + 127.5))
    imgs.append(img)
#======================================

#保存用フォルダ作成
if not os.path.isdir(img_f): 
    os.makedirs(img_f)

#保存
#======================================
for i in range(len(imgs)):
    print(i)
    #画像の表示と保存
    imgs[i].save(img_f + str(i) + '.png')
    plt.imshow(imgs[i], vmin = 0, vmax = 255)
    plt.show()
#gif保存
imgs[0].save('morph.gif', save_all=True, append_images=imgs[1:], optimize=False, duration=1, loop=0)
#======================================

結果

教師画像からランダムに選ばれた2枚の画像と、その中間の画像(枚数指定可)が保存されます。

生エビからサーモンです。

生エビからサバです。

余談

モーフィングでは2つの画像がなめらかに変化することが理想ですが、上では一旦「白い闇」を経由しています。これは潜在空間の分布が整っていないことが原因と考えられますので、次回はこれを克服したVAE(Variational Auto-encoder)に挑戦してみたいと思います。

関連記事もご参照ください

タイトルとURLをコピーしました