にせねこメモ

はてなダイアリーがUTF-8じゃないので移ってきました。

Chainerでアニメキャラの目からハイライトを消す

pix2pix

pix2pixというモデルがある。入力画像と、それと一対一対応する変換ターゲットの画像を用意すると、その間の変換を自動で学習してくれるというものである。
元論文はこれ:

この論文内では、モノクロ写真に着色するだとか、線画に色を付ける、航空写真から地図を生成する、ラベリング画像から写真を復元する、などが行われている。要するに、何らかの画像のペアを用意すれば、ペア間の画像変換が学習できるっぽい。


それで、入力画像としてアニメキャラの顔の画像を用意し、出力画像として入力画像から目のハイライトを消したものを用意すれば、アニメキャラの目からハイライトを消すモデルが学習できないだろうか。

幸い、pix2pixのChainer実装が公開されている:

ので、これを改変することによって作成していく。

環境

  • Windows 10 64-bit
  • Python 3.5.3 (Anaconda 64-bit)
  • Chainer 2.0.1
  • CuPy 1.0.1
  • OpenCV 3 (demo.pyの結果表示で使っている)

データセットの用意

まず、データセットがなければ話にならないので用意する。

2017年1~3月に放送されていた*1アニメのキャプチャから、OpenCVのカスケード分類器とlbpcascade_animeface.xmlを利用してアニメ顔を抜き出した。元動画が1280×720 pxとした時に256×256 px以上の解像度をもっているものだけ抽出した。

(20210223追記: データセットを公開しました。次のブログ記事をご参照ください: アニメキャラの目のハイライト消しデータセット - にせねこメモ)

それから、切り出された画像を目で見て、誤検出やブラーがひどいものなどを取り除いた*2

さらに、そこからランダムに500枚抜き出し、それらのコピーに対してSAIを使って手でハイライトを塗りつぶした画像を用意した*3。中には塗りつぶす必要のない画像もあったが、だいたい一枚あたり1~10分程度かかった。特に、目にグラデーションがかかっていたり、タッチ線が入っていたり、ハイライトに大きなグローがかけられていたりするなどの複雑な目の処理をしている場合は難しく、時間がかかった。
用意したデータセットに含まれる画像の例は、下にある結果セクションの入力とground truth(正解画像)を参照。

コードの変更

先ほど挙げたpix2pixの実装においては、Facade datasetから、入力用のラベリング画像を12 chとして、変換ターゲットの画像を3 chのnumpy.arrayとして読み込み、これらによってトレーニングを行っている。これを変更し、入力・出力ともに3chのカラー画像を扱えるものにする。

画像をデータセットとして読み込むプログラムをimg_dataset.py、このデータセットの上で訓練するコードをtrain_dehighlight.pyとして用意した。

ここで、先ほどデータセットとして用意した画像500組のうち、9割(450枚)を訓練用として、残り1割(50枚)を評価用として分割している。

コード

GitHubに上げた。
github.com

デモ

python demo.py -g <GPU番号> -i <画像ファイルのパス>

レーニン

python train_dehighlight.py --epoch 400 --gpu <GPU番号> 

などとして実行する。GTX 1060使って18時間とかだった気がする。GPU使用しないと凄く時間がかかる。実際トレーニングをしてみて感じたことであるが、50,000 iter以上繰り返してもほとんど結果が改善しているようには見えなかった。

結果

176,000 iter目のトレーニング結果を次に挙げる。

入力

f:id:nixeneko:20170801195435p:plain

出力 (変換結果)

f:id:nixeneko:20170801195606p:plain

Ground truth (正解画像)

f:id:nixeneko:20170801195542p:plain
上手くいっているところを選んだとはいえ、割といい感じにハイライトが消えてる気がする(たのしい)。

その他変換結果

訓練セットにも評価セットにも含まれない画像についての変換結果を載せる。トレーニング176,000 iter目のモデルを用いた。左が入力、右が出力である。絵は自作なので絵柄にバリエーションがないのはご愛敬。
f:id:nixeneko:20170801205608p:plain
f:id:nixeneko:20170801210236p:plain
f:id:nixeneko:20170801205943p:plain
何となく塗りつぶした跡が見えるが、そこそこうまく動いてる様に思う。

改善点など

現状、入力画像のうち顔の領域の大きさが256×256 px程度である場合にはうまくいくが、大きさが大きかったり小さかったりするとあまりうまくいかない。つまり、スケール不変性がない。
これは、カスケード分類器で切り出した顔画像を256×256に変形してそれを用いてトレーニングしているためであると考えられ、data augmentationなどで訓練画像として様々なスケールの入力が与えられるようにすることである程度は対応できるのではないかと思う。

また、元画像で目のハイライトが小さい場合にはあまり効果が感じられない。これについてもdata augmentationで様々にスケールを変更したものを入力とすることで多少改善するとは思うが、どうなんだろう。

更に、訓練画像を抽出したカスケード分類器の特徴からか斜めや横向きの顔の画像が少なく、正面向きではうまく働くが、横向くとハイライトが消えなかったりする様である。

後、訓練されたモデルはほとんど顔しか知らないので、画面に文字などが被さってる場合も文字のあたりを目のハイライトとして勘違いするらしく、暗くなったりした。

他にも、訓練に使った画像の作品以外の画像だとハイライトが消えづらいということがあった。目の描き方は作品によって千差万別で、様々な絵柄に対応するためには訓練画像のバリエーションを増やすしかないように思う。何にせよ訓練データセットの作り方次第で改善の余地は大きそうな気がする。

*1:一部再放送を含む。

*2:つらい

*3:とてもつらい