CNNを利用したアニメキャラクターのフェイストラッキング
はじめに
CNN(Convolutional Neural Network)を利用して、ラブライブ!のμ's9人の顔を学習し、未知のラブライブ!イラストに写っているキャラクターの分類を行った。
処理の流れ
- インターネットからラブライブ!関係の画像を収集する。
- OpenCVを利用して、収集した画像からキャラクターの顔を抽出する。
- 抽出した顔画像を手作業で10クラス(キャラクター9人+背景)に分類する。
- CNN(AlexNet)で学習する。
- 学習したモデルを利用し、動画(ダンスシーン)の各フレームに対し、顔抽出と分類を行う。
開発環境
OS : macOS High Sierra
言語 : Python 3.6.3
ライブラリ : TensorFlow, Keras, Numpy等データ処理ライブラリ
API :
LoveLive! SchoolIdol API
Twitter Developer Platform — Twitter Developers
GitHub:
FaceDetector
画像収集
学習用画像として、ラブライブ!関係の画像を収集する。
まず、「LoveLive! SchoolIdolAPI」を利用して、各キャラクターの全カード画像・楽曲ジャケット画像を取得した。カード画像に関しては、背景が学習の妨げになると考え、キャラクター以外の領域が透過されているものを利用した。計1579枚。
次に、Twitter上でラブライブ!のアニメやライブシーンのgif画像をツイートしているアカウント(ラブライブ!gif画像 (@llimgfunbot) | Twitter)を利用し、gif画像を1700枚取得した。取得したgif画像をバラして学習に利用するが、全フレームを対象とすると、
- 学習用画像数の増加に伴い、学習時間が膨れ上がる。
- 隣接したフレームでは画像の変化が少ない。
といった理由から、gif画像の10フレームにつき1フレームを抽出した。計17861枚。
顔抽出
前節で収集した19440枚の画像から、OpenCVを利用して顔抽出を行う。
ここで得られた計12011枚の顔の画像を学習用顔画像とする。
顔抽出においては下記の記事を参考にした。
上記の記事で紹介されている方法で顔抽出を行う場合、アニメキャラ用の顔抽出用カスケード分類器「lbpcascade_animeface.xml」が必要になるので注意。下記のサイトでダウンロードできる。
画像分類
前節で得た学習用顔画像12011枚をキャラクターごとに分類する。今回はμ'sのキャラクターを分類するため9クラスとなる。また、OpenCVの顔検出が上手くいかず、キャラクターの顔でない部分が抽出されることがあるため、誤検出を検出するためのクラスを1つ用意した。このクラスには主に背景が分類される。よって、今回の分類対象は、キャラクター+背景の10クラスとなる。
この手順ばかりは手作業でやるしかないので、覚悟すること。とてもしんどかった。
画像の水増し
前記事で分類精度を上げるためには画像数が重要であり、画像数を手軽に増やす方法として、学習用画像を回転・反転・ノイズ付加する方法があると述べた。今回も画像数の水増しを行う。具体的には、学習用顔画像を時計回り、反時計回りに15°回転させる。これにより、学習用顔画像は3倍の36033枚になった。
モデル
当初、CNNのモデルを自分で構築する気でいたが、モデルを少し考えたところで、自分で苦労して考えたモデルよりも、既に実績があり一定の評価を受けているモデルを利用したほうが賢いことに気がついた。
そこで今回は、画像処理コンテストIISVRC(2012)で優勝した実績のあるAlexNetを利用することにした。詳細は下記参照。
[ディープラーニング] AlexNet – Tech Memo
実装したモデルは下図のようになった。そこそこ複雑なネットワークに見えるが、要は単純な層を繋げているだけなので、実装はそこまで難しくなかった。(内容を理解しているとは言っていない)
なお、入力はH244 W244 RGB 3チャネルなので、学習用顔画像をこのサイズにリサイズする必要がある。
学習
構築したモデルに学習用顔学習を学習させる。
- 学習用画像 : 21619枚, 評価用画像 : 14113枚(CV 0.6)
- エポック数 : 40
- バッチサイズ : 32
筆者の環境では学習に丸一日かかった💢。GPUが乗っている環境であれば、TensorFlowのGPU対応版を使うことでもっと早く学習できると思う。
筆者の怠慢で学習の過程の精度等をメモするのを忘れてしまった。体感では(記憶の中では)エポック0-エポック15間にAcc0.8まで上がり、そこからエポック40まで少しずつ上昇し、最終的にはAcc0.9ほどになった。何の役にも立たない体感だァ…次はちゃんとlog取ります…。
分類
学習したモデルに、未知の顔画像を突っ込むと9+1クラスのいずれかに分類してくれる。今回は2種類の動画の各フレームに対し、顔認識・分類を行った。
- 【フェイストラッキング】コールアンドレスポンス
- 動画の各フレームに同時に映るキャラクターが1人ずつ
- キャラクターの動作が少ない
- キャラクターが正面を向いている
以上の理由から、正常にキャラクターを分類できているかの確認が容易。 - 【フェイストラッキング】ユメノトビラ
コールアンドレスポンスと比較して、
- 各フレームに複数のキャラクターが映っている
- キャラクターの動作が大きい
- カメラワークが激しく、正面だけでなく横顔や上を向いているシーンが多い
以上の理由から、本分類器が実用に足るかの確認ができる。
結果
四角の枠の左上の文字が、分類したキャラクターの名前。その隣の数字が分類の尤度。Eli[0.99834]の場合、99.8%の確率で絵里であると判別したという意味。
概ね上手くいっているが、顔をアップで映しており、髪型が画面外に移動したフレームや、キャラクターが動くことによって前髪が大きく動いている(崩れている)ときに誤判別が発生している。これより、キャラクターの判別方法の一つに、前髪を含む髪型があることが予想できる。
かなりカメラワークやライティングの変化が激しく、キャラクターの輪郭などのブレが大きいため、顔の検出が上手くいっていないフレームが目立つ。しかし、検出ができているフレームに関しては、概ねキャラクターの判別が上手くいっているため、本プログラムではなく、OpenCVの顔検出機能の精度に問題があることがわかる。
解決策としては、
・横顔や輪郭のブレに強いOpenCVの顔抽出用カスケード分類器を自作する。(OpenCVで解決する場合)
・顔周辺の画像特徴量を調べ、それらを抽出できるプログラムを自作する。(OpenCVを使わない場合)
訓練画像の数や質を向上する等の力技では解決できず、本格的な画像処理や数学処理を使わざるを得ないため、割りと茨の道である。改善する場合は本腰入れて学習が必要。
まとめ
・訓練画像データの選別が一番の鬼門
・CPUでディープラーニングをするのは非効率。可能であればGPU版TensorFlowを使い、学習の時間を短縮すべき。
・フェイストラッキングに関しては、OpenCVの顔抽出機能の性能がネックになる。