Python
DeepLearning
StyleTransfer

style-transferを動かしたった

画像のスタイル(絵のタッチ)を変化させるstyle-transferの各種デモを動かすまで。

MaxOSX-10.13,Ubuntu-16.04で動作確認済み。

CPU, GPU両方で動作確認済み。


neural-transfer

Tensorflowでの実装らしい。

これがstyle-transferの源流。

こっちはCPUでもぎりぎりいける。(MacbookAitでちょっとファンが唸った)


Github

https://github.com/anishathalye/neural-style を使った。


Requirements

Python-3.6

Tensorflow (1.8で動作確認済み)

このコマンドでインストールできる。

pip install -r requirements.txt


準備

まずはVGG19のimagenetの事前学習モデルが必要らしい。

Githubの下にリンクがある。

このコマンドでもいける。

wget http://www.vlfeat.org/matconvnet/models/beta16/imagenet-vgg-verydeep-19.mat


デモを動かす

実際に動かすと、学習→テストの流れになる。

実際にexamplesの画像でこんな風にすると学習が始まる。

今回はiteration数を50にしてみる。

python neural_style.py \

--content examples/1-content.jpg \
--styles examples/1-style.jpg \
--output out.jpg \
--iterations 50

これでこんな画像ができる。それなりにいい画像ができる!


fast-style-transfer

Tensorflowでの実装。

neural-transferの改良版で速くなった。

しかし、これも学習が必要で学習に時間がかかる。

学習ではGPUを使っても数時間かかるレベル(CPUではためしてない)

最後のスタイル変換の部分だけならCPUでも余裕レベル。


Github

Github https://github.com/lengstrom/fast-style-transfer を使った。


Requirements

Python-3.6

Tensorflow (1.8で動作確認済み)

moviepyが必要なので、pipでいれておく。

pip install moviepy


準備

基本的にREADMEの通りの準備していく。

sh setup.sh

これでimagenetのデータと学習済みモデルをダウンロードしていくらしい。

しかし画像データが多すぎて容量をけっこう食うので、imagenetの事前学習モデルだけ入れる場合は、このコマンドだけでもいい。

wget http://www.vlfeat.org/matconvnet/models/beta16/imagenet-vgg-verydeep-19.mat

すると、imagenet-vgg-verydeep-19.matがダウンロードできるので、これをdataディレクトリに移す。

mkdir data

mv imagenet-vgg-verydeep-19.mat data


デモを動かす

実際にデモを動かす。

examplesの画像を使ってみる。

train-pathはデフォではtrain2014となるが、今回はexamples/styleの画像でやる。

ただし、画像数が少ないと学習回数が極端に少なくなってしまうので、注意!

python style.py --style examples/style/the_scream.jpg \

--checkpoint-dir checkpoint \
--train-path examples/style \
--test examples/content/chicago.jpg \
--test-dir examples/content \
--content-weight 1.5e1 \
--checkpoint-iterations 1000 \
--batch-size 20

学習が終わると、checkpointというディレクトリに以下の学習済みパラメータが保存される。

~/work/fast-style-transfer :$ ls checkpoint/

checkpoint fns.ckpt.index
fns.ckpt.data-00000-of-00001 fns.ckpt.meta

あとはこのモデルを使って実際にスタイルを変えるだけ。

その前にevaluate.pyの

from moviepy.video.io.VideoFileClip import VideoFileClip

import moviepy.video.io.ffmpeg_writer as ffmpeg_writer

をコメントアウトする。

#from moviepy.video.io.VideoFileClip import VideoFileClip

#import moviepy.video.io.ffmpeg_writer as ffmpeg_writer

そしてこのコマンドでテストする。

学習済みモデルも公式gitで配布されている。

python evaluate.py \

--checkpoint checkpoint
--in-path examples/content/stata.jpg
--out-path out.jpg

こんな感じでできる。


ウェブカメラでリアルタイムにする

webカメラを使って、取り込んだ画像をstyle transferして表示する。

つまり、現実世界のstyle transferをリアルタイムに行う。

ただし、webカメラから取り込んだ画像の真ん中だけを切り取るようにしている。

from __future__ import print_function

import sys
sys.path.insert(0, 'src')
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

import transform, numpy as np, vgg, pdb, os
import scipy.misc
import tensorflow as tf
from utils import save_img, get_img, exists, list_files
from argparse import ArgumentParser
from collections import defaultdict
import time
import json
import subprocess
import numpy

import matplotlib.pyplot as plt

BATCH_SIZE = 1
DEVICE = '/gpu:0'

GPU_id=0

#- Camera setting
import cv2
cap = cv2.VideoCapture(0)
camera_scale = 1.5
#-

# get img_shape
def ffwd(checkpoint_dir, device_t='/gpu:0', batch_size=1):

ret, image = cap.read()
new_h = int(image.shape[0] * camera_scale)
new_w = int(image.shape[1] * camera_scale)
image = cv2.resize(image, (new_w, new_h))
orig_h, orig_w = image.shape[:2]

## clip center
cx = orig_w // 2
image = image[:, cx-orig_h//2: cx+orig_h//2]
orig_h, orig_w = image.shape[:2]

#rh, rw = 360, 640
rh, rw = 180, 320
img_shape = (rh, rw, 3)
line = 30
out_frame = np.zeros((orig_h, orig_w * 2 + line, 3), dtype=np.uint8)
out_frame.fill(255)

g = tf.Graph()
batch_size = 1
curr_num = 0
soft_config = tf.ConfigProto(allow_soft_placement=True)
soft_config.gpu_options.allow_growth = True
soft_config.gpu_options.visible_device_list=str(GPU_id)
with g.as_default(), g.device(device_t), \
tf.Session(config=soft_config) as sess:
batch_shape = (batch_size,) + img_shape
img_placeholder = tf.placeholder(tf.float32, shape=batch_shape,
name='img_placeholder')

preds = transform.net(img_placeholder)
saver = tf.train.Saver()
if os.path.isdir(checkpoint_dir):
print(checkpoint_dir)
ckpt = tf.train.get_checkpoint_state(checkpoint_dir)
if ckpt and ckpt.model_checkpoint_path:
saver.restore(sess, ckpt.model_checkpoint_path)
else:
raise Exception("No checkpoint found...")
else:
saver.restore(sess, checkpoint_dir)

while True:
ret, image = cap.read()
image = cv2.resize(image, (new_w, new_h))
## clip center
image = image[:, cx-orig_h//2: cx+orig_h//2]
out_frame[:orig_h, :orig_w] = image

if cv2.waitKey(10) == 27:
break
image = cv2.resize(image, (rw, rh))
image = image[..., ::-1].astype(np.float32)
image = (image - 127.5) / 127.5
X = np.zeros((1,) + img_shape, dtype=np.float32)
X[0] = image
_preds = sess.run(preds, feed_dict={img_placeholder:X})
out = _preds[0]
out = out[..., ::-1]
out = cv2.resize(out, (orig_w, orig_h))
out -= out.min()
out /= out.max()
out *= 255
out = out.astype(np.uint8)
out_frame[:orig_h, orig_w+line:] = out
cv2.imshow("fast-style-transfer", out_frame)

def build_parser():
parser = ArgumentParser()
parser.add_argument('--checkpoint', type=str,
dest='checkpoint_dir',
help='dir or .ckpt file to load checkpoint from',
metavar='CHECKPOINT', required=True)

help_out = 'destination (dir or file) of transformed file or files'

parser.add_argument('--device', type=str,
dest='device',help='device to perform compute on',
metavar='DEVICE', default=DEVICE)

parser.add_argument('--batch-size', type=int,
dest='batch_size',help='batch size for feedforwarding',
metavar='BATCH_SIZE', default=BATCH_SIZE)

parser.add_argument('--allow-different-dimensions', action='store_true',
dest='allow_different_dimensions',
help='allow different image dimensions')

return parser

def main():
parser = build_parser()
opts = parser.parse_args()

ffwd(opts.checkpoint_dir, device_t=opts.device,
batch_size=opts.batch_size)

if __name__ == '__main__':
main()