サーバルちゃんによる海の想像図のスタイル転送をやってみる

流行に乗っかって、画像のスタイル転送[deep-photo-styletransfer](https://github.com/luanfujun/deep-photo-styletransfer)を自分でも試してみました。スタイル画像として用いるのは、タイトル通り以下の画像です。

![serval's sea](https://knok.github.io/images/sea-small.png)
(c) 2017 けものフレンズプロジェクトA

# 対象画像

どういう画像に適用するかを考えるのは面倒だったので、deep-photo-styleransfer付属のサンプルの1番目の画像を使いました。

![dps blob1](https://github.com/luanfujun/deep-photo-styletransfer/blob/master/examples/input/in1.png?raw=true)

# スタイル画像の取得

まずは元となる画像を用意します。けものフレンズ9話の本編20:38あたりが当該映像です。この作品は複数の動画配信サイトで見ることができるので、PC上で再生してスクリーンショットをとることで用意できると思います。

* [バンダイチャンネル](http://www.b-ch.com/ttl/index.php?ttl_c=5488)
* [dアニメストア](https://anime.dmkt-sp.jp/animestore/tp_pc)
* [ニコニコ動画](http://www.nicovideo.jp/watch/1488872180)

ニコニコ動画は解像度が低いのが難点ですが、ピンポイントで9話だけ見ることができます。

取得した画像は、アスペクト比を無視してスタイル適用画像のサイズ700x437に無理やり合わせます。縮小したサンプルを以下に示します(オリジナルそのまま掲載するのは問題があると思われるので)。

![serval's sea](https://knok.github.io/images/sea-small.png)
(c) 2017 けものフレンズプロジェクトA

スタイル画像ファイル名はsea.pngとしました。

# スタイルのセグメンテーション画像作成

どの部分をスタイルとして適用するかを識別させるためのセグメンテーション画像を作ります。レイヤーの扱える画像処理ソフトウェアを使って、スタイルとして利用する領域を特定の色で塗りつぶして作ります。今回、自分はこの作業だけをWindows上の[Paint.NET](http://www.getpaint.net/index.html)を使って作りました。もちろんLinux上でGIMP等を使っても良いでしょう。

![style segmentation](https://knok.github.io/images/kf-style-sg.png)

* 赤: 太陽部分
* 青: 空
* 緑: 木
* 黄: 地面
* 白: 水面
* 黒: その他(桶含む)

とりあえず、この6種類に分けました。どれをどう適用するかはいろいろ試して決定することにします。ファイル名はkf-style-sg.pngとしました。

# コンテンツセグメンテーション画像

対象画像を付属サンプルに決定したので、セグメンテーション画像は基本同じもので良いはずです。元データであるexamples/segmentation/in1.pngを元に、適用するスタイルの箇所と同じ色へ塗り替えて利用します。

![contents segmentation](https://knok.github.io/images/kf-cont-seg2.png)

* 空部分: 青(スタイル画像の空に対応)
* 建物部分: 黒(スタイル画像のその他部分に対応)
* 海面部分: 白(スタイル画像の海に対応)

ファイル名はkf-cont-seg.pngとしました。

# matting処理用データの生成

入力画像に対するMatting Laplacianの計算処理は、MATLABを持っていないのでOctaveで行いました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">フェネックやめるのだ！MATLABで実装すると金持ちの大学と研究室しか使えなくなるのだ！</p>&mdash; Hideaki_HS20 (@hgot07) <a href="https://twitter.com/hgot07/status/849115290755489792">2017年4月4日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

これについては次の記事が大変参考になりました。

* [Deep Photo Style Transferを低予算な環境で無理やり動かす](http://qiita.com/colspan/items/ee7c53ff0f7ced9afdbb)

mattingは画像の背景と前景とを切り分けるための処理のことで、deep photo styletransferではLevinらによる"A Closed Form Solution to Natural Image Matting" 2008[(論文PDF)](http://www.wisdom.weizmann.ac.il/~levina/papers/Matting-Levin-Lischinski-Weiss-CVPR06.pdf)の手法を利用しているようです。
これにより、適当に同一色で塗りつぶしたセグメンテーション画像から、必要となる箇所をうまいこと切り取ってくれるようです。

gen_laplacian.mを実行するとサンプル入力画像60枚分全部のデータを生成しようとしますが、必要なのは1枚目の分(Input_Laplacian_3x3_1e-7_CSR1.mat)だけです。

# スタイルの適用

これまでに説明した画像を用意した状態で、以下を実行します。

```shell-session
th neuralstyle_seg.lua -content_image examples/input/in1.png \
 -style_image sea.png -content_seg kf-cont-seg2.png \
 -style_seg kf-style-sg.png -serial serial
```

1000回イテレーションが走り、serialディレクトリ以下にout1_t_100.png〜out1_t_1000.pngが生成されます。GPUでこの処理を行うと、だいたい8GB程度のメモリを使うようです。私はGoogle Computing EngineのGPUインスタンス(Tesla-K80 12GB)を使いました。

![out1_t_1000](https://knok.github.io/images/out1_t_1000.png)

これだけでも割とそれっぽいですが、この段階ではmattingがなされていないので、次の処理を行います。

# mattingの適用

以下を実行します。

```shell-session
th deepmatting_seg.lua -content_image examples/input/in1.png \
 -style_image sea.png -content_seg kf-cont-seg.png \
 -style_seg kf-style-sg.png \
 -init_image serial/out1_t_1000.png \
 -serial output -f_radius 15 -f_edge 0.01
```

また1000回イテレーションが回ります。この処理ではそれほどGPUメモリを必要としないようです(1GB未満)。outputディレクトリ以下にbest1_t_100〜1000.pngが生成されます。

![best1_t_1000](https://knok.github.io/images/best1_t_1000.png)

思った以上にそれっぽい画像が生成できました。

# 結果について

## 論文の趣旨

オリジナルの論文[(1703.07511) Deep Photo Style Transfer](https://arxiv.org/abs/1703.07511)をざっと読んだところ、以下の2つがポイントのようです。

* 局所的な色空間のアフィン変換を行うことで元画像の写真らしさを失わない
* セマンティックセグメンテーションにそってスタイル転送を行うことで、さらなる質向上を目指す(ここでImage mattingが行われる模様)

理解が間違っている点などあればコメント、編集リクエストをください。

## 出力に関して

元のスタイル画像の空には雲があるのですが、対象画像の空には雲がまったくない状態です。この手法では、勝手に雲を生成するようなことが発生しないようです。雲を含んだ空画像を対象としたときに、ちゃんと雲の特徴が反映されるかどうかは確認してみたいところです。

海に関してははかなりいい感じではないでしょうか。若干黄色っぽいものが混じっているのはセグメンテーション領域が不適切だった部分があったせいだと思われます(mattingはコンテンツ画像のみ実施している)。

建物については中央部分がちょっと白くなりすぎかなあとも思いますが、元画像の明るさに比例しているようなのでこんなものかな、という感じです。
最初は建物部分に木のスタイルを適用してみたのですが、ほとんど変化を感じられませんでした。

![tree best](https://raw.githubusercontent.com/knok/knok.github.io/master/images/tree-best1_t_1000.png)

# 最後に

* deep photo style transferありがとう
 * Fujun Luanさん他ありがとう
 * サンプル実装まで公開しれくれてありがとう
 * ライセンスがアカデミック、非商用限定なので気をつけてね!
* VGG-19 pretrain modelありがとう
 * 特徴、スタイル抽出に用いているそうです
* [colspan](http://qiita.com/colspan)さんありがとう
 * Octaveありがとう
* たつき監督ありがとう(お約束)
 * けものフレンズプロジェクトありがとう
 * よしざきおにいさんありがとう
 * (元々のこの絵をかいたフレンズは誰だろう…)

本当はもうちょっと論文や実装に踏み込みたかったのですが力尽きました。