面白そうな画像処理(画風変換)の論文を見つけたので、実装してみました。
当初は詳細なアルゴリズムまで説明しようと思っていましたが、途方も無く時間がかかる上、そもそもそこに興味がある人は論文を読むだろうという結論に至ったので、この記事では大雑把な流れを説明するにとどめ、画像処理の楽しそうな雰囲気を共有することに努めます。
ソースコードも下記に公開しているので、参考になればと思います。論文との差分は「README.md」を参照してください。
https://github.com/trbay/style_transfer_via_texture_synthesis
CONTENTS
画風変換とは
英語ではStyle Transferと呼ばれる画像処理の小領域です。特徴的な画風をもつ画像(Style Image; 以降はStyle画像)の画風を、他の画像(Content Image; 以降はContent画像)に転送することを指します。下記に例を示します。左がContent画像、中央がStyle画像、右が画風変換された画像(今回実装したプログラムで生成した画像)です。
この例のように、Content画像の性質を残しつつ、Style画像の特徴をいい感じに適用した画像を生成するのがStyle Transferの重要な点です。やみくもに画風を適用すればContent画像を認識できなくなり、逆にうまく適用されないと”画風(Style)”とは呼べない代物になります。このバランスを保ちながら、究極のいい感じを求めるのがStyle Transferの目標と言っても良いかもしれません。
※もちろん、この”感じ”も研究・論文の中で定性・定量評価されますが、この記事では詳細に触れません。つまるところ、画風変換された画像を見るのは人間なので、この記事を見て「おー!いい感じに画風が変わってる!」と直感的に思えるかどうかが”感じ”に直結します。
画風変換の近況
2015年あたりから画風変換においてもディープラーニング(CNN)が有効であることが明らかになり、「Neural Style Transfer」という名のもとCNNによる画風変換の研究が多くなっている印象です。得られる結果もとても良さげです。
そんな中、CNNで得られる結果と比較しても遜色ない画風変換を、CNNなしで実現したのが今回紹介・実装する論文です。
実装した論文
2017年の「Style Transfer Via Texture Synthesis」という論文です。
M. Elad and P. Milanfar, “Style Transfer Via Texture Synthesis,” in IEEE Transactions on Image Processing, vol. 26, no. 5, pp. 2338-2351, May 2017
この論文ではテクスチャ合成(Texture Synthesis)と呼ばれる技術が肝になります。特に強く引用されているのが2005年の論文「Texture optimization for example-based synthesis」です。こちらも実装しました。
V. Kwatra, I. Essa, A. Bobick and N. Kwatra, “Texture optimization for example-based synthesis”, ACM Trans. Graph., vol. 24, no. 3, pp. 795-802, 2005.
先にこちらの論文を紹介します。
Texture optimization for example-based synthesis
この論文では2つのテクスチャ合成手法が提案されていますが、ここではそのうちの一つ、「与えられたテクスチャ画像をもとに、さらに大きなテクスチャ画像を合成する」ための手法を取り上げます。(「Style Transfer Via Texture Synthesis」で必要なのはこちらのみ)
テクスチャが何たるかを言葉で説明するのは難しそうなので、先に例を示します。与えられた入力テクスチャをもとに、その二倍のサイズのテクスチャを生成した例です。(こちらも実装したプログラムで生成)
”テクスチャ”については何となく把握できたと思います。
驚くべきは、生成されたテクスチャの自然さです。入力テクスチャのつなぎ目がほとんどなく、とても自然に表現されていることがわかります。結果が得られたときには思わず声が出てしまいました。素晴らしいです。
私が普段使っている醤油皿もテクスチャっぽかったので、同じように生成してみました。
いい感じに合成されています。
手法の処理内容やハイパーパラメータについての解説は割愛します。
(ここが面白い点なのですが、めちゃ長くなるので… 🙁 )
画風変換にどう活きるか
上のテクスチャと同じ要領で、Style画像についてもどんどん合成していくことで、同じような画風で新たな描画(っぽいこと)を行うことができます。例えば、下記のように左の画像を適当に合成して右の画像を作り出せます。
これに、「Content画像に合わせて合成する」という制約を設けることで画風変換につなげていきます。
Style Transfer Via Texture Synthesis
下記の実行例を参考に、本手法を大雑把に説明していきます。
Content画像(左)、Style画像(中央)、画風変換後のContent画像(右)
1. 重みの計算
Content画像のどの部分をどれだけ保持するかを計算します。論文ではSegmentation(領域分割)によってこれを行っていますが、今回の実装ではSobelフィルタまたはLaplacianフィルタによるエッジ検出でこれを補います。
下記画像では、白くなっている部分ほどContent画像が保持されることを指します。逆に言えば、黒い部分ほどある程度自由に描画されることになります。
※下記例はカーネルサイズ3のSobelフィルタ
2. 色の転送(Color Transfer)
Content画像とStyle画像の色味を合わせていないと、うまいことStyleを適用できない(※)ので、ヒストグラムマッチングと呼ばれる手法により、Content画像のヒストグラムをStyle画像のヒストグラムに合わせます。
下記例では、左がContent画像、中央がStyle画像、右がStyle画像のヒストグラムにフィットさせたContent画像になります。
※論文では色(RGB)をピクセル強度として扱っていますが、彩度や明度など強度の選び方は自由なため、それに合わせて前処理を行います。
3. テクスチャ合成
1.の重みを考慮しながら、色転送したContent画像に近いStyle画像の部分を見つけ合成することで、画風変換が完了します。
一気に端折ってしまいましたが、ここの説明は長くなってしまいます 🙁
※加えて、これらを複数の解像度・複数のパッチ抽出を用いて行い、何度か繰り返して実行します。
成功例(といえるかも)
いろいろな画像の組み合わせをテストしすぎて、いい感じに合成できてるか正常に判断する能力が執筆現在欠如しているので注意です XD
失敗例
結構失敗します。Style画像の内容がContent画像にそのまま現れてしまうケースが一番の問題です。
※ハイパーパラメータ(後述)を調整することで解決できる可能性はあります。
※論文で紹介されている領域分割で対処できるケースはあります。(一番下の失敗例は解決できそうです。上2つの風景画像のように分割が難しいケースでは、Content画像が守られすぎてStyleをあまり適用できない可能性があります。)
画風の保持 vs. 滑らかさ
Style画像をContent画像に適用する際、StyleとContentのピクセルの距離(色がどれだけ離れてるか)を計算しますが、この距離が離れているほど強めの合成を施し、逆に距離が近いのであればあまり合成しない、というパラメータが存在します。
(だいぶ語弊のある言い方になっています。詳細は論文参照)
厳密には、このパラメータは最適化手法IRLSで行うLPノルム線形回帰のPの値を指します。
Pの値が2に近づけば近づくほど、ピクセル同士の距離を考慮しなくなります。そして合成結果も滑らかになりますが、Style画像の表現が失われる形になります。
一番最初に示したContent画像(左)とStyle画像(右)を対象にPの値の影響を見てみます。
Pの値を0.8・1.0・1.2・1.5・1.8・2.0にした画風変換の結果を示します。0.8・1.0・1.2が上段、1.5・1.8・2.0が下段です。
空の部分に着目すると違いがよくわかります。1.8や2.0の場合、Style画像の動きはほとんど失われています。Pの値が小さいほどStyle画像の動きを保持していますが、よく見ると不自然に繋がれて合成されている部分(P=0.8は特に)もあります。この例の場合、1.0がちょうど良いかもしれません。
今回この記事で紹介している大半の画像はP=1.2で決め打ちして画風変換されていますが、Content画像やStyle画像の性質に合わせて調整すると、もっといい感じになるかもしれません。
Content画像の保持
前述した重みを抑制したり増幅させたりすることで、Content画像の影響を操作することができます。下記のContent画像(左)とContent画像の重み(中央)、Style画像(右)を対象に見ていきます。
この重みに対して0.2・0.4・0.5・0.8・1.0を乗算して画風変換すると以下のような結果が得られます。
一番左の結果(0.2を乗算)はほとんどContent画像を認識できないのが分かるかと思います。こうして並べると1.0よりも0.8の方がそれっぽく見えたり、もしかすると0.5と0.8の間くらいが良いんじゃないかとか、このパラメータの調整も難しいです。
むすび
少しでも「へ~」と思ってもらえたなら嬉しい限りです。知見は共有するにつきます 🙂
この領域をもっと知りたい!と思った方はNPR(非写実的レンダリング)で検索すると良いかもしれません。
久々にしっかりと論文を読みましたが、論文の引用元をたどってもまた同じくらいの引用リストがあったり、90年代の論文に行き着いたりと、時代の重みを感じてとても温かい気持ちになりました。