RE: Imager::AnimeFaceを使ってみた簡素な感想。

# うまく認識してくれない画像を眺めてたところ、どうも眼の位置に微妙に肌の色と違う部分があると(例えば頬が赤く染まってたりすると)そこを眼として認識してしまう気がする。

* 横顔も認識する?と思ったら、鼻の上の空間を眼として認識してたりとか。
* 両目の色が同じとして探す→候補がない場合は両目の色が違う、みたいな感じにしたほうが認識精度は上がりそう。そのかわりオッドアイなキャラの認識が悪くなるのかもしれないけど……。

# 眼の位置はともかく、鼻と顎の位置を見つける精度はあまり高くないみたいなので、その位置パターンを利用するのはちょっと難しいかもしれない。

* 顔の向きのチェックができるかなとか思ってたんだけど。眼の形から判断したほうがいいのかもね。

http://asakura.g.hatena.ne.jp/asakura-t/20090522

コメント欄に書こうかと思ったけれど、僕の説明不足な部分が多くあるのでこっちに書きます。主に言い訳で一部矛盾してたりあまりいい回答にはなっていないと思いますが、いい機会なので、関連した話でいろいろ言いたいことを書こうと思います。
RE:としていますが、個人宛ではなく全国民に対する周知として書きます。

横顔の検出について

まず前提として。今のところ顔の検出処理は部品位置と大きさの推定には全く依存していません。顔の検出を行って、そのあとに部品位置と大きさを計算しています。

今の実装としては、横顔を検出するかは未定義になってしまっています。検出処理の教師データに正解にも不正解に横顔は入れていないので、斜めの顔に近い横顔なら検出する場合もあるし、検出されない場合もあります。
こうなっている理由としては、横顔を検出できるのか、つまり『横顔』と『顔以外』を分類できるかという問題があって実験できてなくて、よくある人間を対象にした結果だと今のような方法だとあまりうまくいかないし、アニメ横顔はさらに多様で複雑な問題になるので、正解にいれて顔以外の誤検出が増えるように影響しても不正解にいれて検出ができない顔が増えるように影響しても嫌なので、どっちにも入れないという形で逃げています。なぜ試していないのかというと、試すのに大量の横顔画像が必要で、横顔はレアなのでデータをどうやって用意するかという段階で止まっています。
よくないことに部品位置の推定は正面しか想定していないので、横顔を検出している場合は、間違いなく変な結果になると思います。
今の状態で横顔をどう扱うべきか、正直なところよい対応は思いつかないです。いくつかについては横顔かどうかの判定がうまくいく、という方法はいくつかあると思います。ただ個人的には、不安定な結果は使う目的に最適化されるべきと思っているので、ライブラリに入れるようなことは今のところしていません。まず検出できない横顔もある、という問題があります。

部品位置と大きさの推定について

まず前提として。顔の部品位置と大きさは予想の類であって、画像を中を見ていないということ。画像の中を見ていない、というとちょっと意味が分からなくなりそうですが、ピクセルをひとつずつ追うようなことはしていないし、特に鼻に関しては解像の問題でほとんどの場合は消えてしまっています。
どうやっているのかというと、顔の正方形領域を32x32セルで考えて2セルおきに12x12個の点を打って、各点を中心とする8x8の矩形領域内で特定の光の勾配方向にのみ強く反応する受容体のようなものを8種類重ねて12x12x8=1152個の数値出力を得て、それを入力とし、(左目の中心座標X,左目の中心座標Y,左目の縦幅,左目の横幅,右目の中心座標X,右目の中心座標Y,右目の縦幅,右目の横幅,鼻の座標X,鼻の座標Y,口の中心座標X,口の中心座標Y,口の縦幅,口の横幅,あご先の座標X,あご先の座標Y)を出力するニューラルネットワークで予測を行っています。
これはかなりチャレンジングな方法だと思っていますが、まずいことにあまり力を入れていません。具体的には教師データが圧倒的に足りていないけれど、作るのが苦行すぎて、逃げてしまっています。

最初の文含め全体的に顔部品の話だと思っています。
上で述べたように部品位置と大きさはただの予測で、あまり信用のできる結果は出せていません。そして実装としてはそれ以上のことは行っていません。
今の状態でもっとよい部品位置と大きさの結果を得るには、僕は次の手順が必要だろうと考えています。

  1. 顔を正しく検出し、検出位置を大体そろえる
  2. 部品の位置と大きさを予想する
  3. 部品の位置と大きさの予想を元に実際の画像を見ながら最適化する

こう考えながらも3については、実装していません。これを行っていると思われたり、画像を見ていると思われていると、いろいろと思うことがあると思われます。
では、なぜかやっていないのかというと、問題が複雑すぎるのでプログラミングしても不安定な結果しか出せないだろうということ。簡単な例だとよい結果を出すことはできるけれど、いくつかの例では最悪の結果を出しかねない。これは、2と3の結果が大きく違っていた場合に、どちらが信用できるかといった話で、3のほうが信用できるとは一概には言えないと思っているからです。むしろ僕としては究極的には3は不要になると考えています。
ただライブラリ作者としては、何パターンか修正関数を用意して、使いたい人は使ってください、としたいのですが、余裕的な問題でできていません。特に目に関してはほとんどの場合、位置修正はうまくいくと思っています。

顔の向きの予測について

  • 鼻がどちらの目に近いか
  • 左右の目のバランス
  • 顎先→鼻→左右の目の中心(3Dを少し考慮した上での中心)を結ぶ線の傾き

などである程度はできると思っています。
ただ部品位置が不安定なのでどうしても不安定になると思います。また顔の向きは本来3Dで考える必要があって、それを2Dのイラストとしてデフォルメして描かれているので、正解があるのかもよく分からないし、人間の感覚に近い結果は単純なプログラミングでは出せないとも思っています。本格的にやるとしたら、傾きごとにいくつかのクラスを定義して、検出された顔がどのクラスに属するか推定する形になると思っています。

まとめ

ほとんどの人間はImager::AnimeFaceよりいい予測を行えるので、間違った例を見ていろいろ思うことはあると思います。ただ人間は自分の経験を後付で説明するよりも恐ろしく複雑な処理を行っているので、それ完全に満足させる結果を求めるのはちょっと無理があります。もちろん、目標にはしています。Imager::AnimeFaceは多くの場合にはそこそこの結果は出せていると思っています。そこそこ以上の結果を出すのは、アニメ顔認識というネタみたいなテーマを超えて人類にとっての大きな課題にまで到達する話だと思っているので、いまのところ応用としては、少々間違っていても問題にならないような方法で使うか、ある程度間違うという許可を得れる環境で使うか、間違いを補助できる仕組みの上で使うか、だと思っています。
今の実装で得られる結果をいくつかの例を勝手に紹介するので、よさそうな改善があって教えていただければ、次のバージョンの参考にしようと思います。

1

f:id:ultraist:20090524123604p:image
よくある正面顔。ひとりはメガネ。
f:id:ultraist:20090524123605p:image
大体あってる。『大体』というのが基本。こういう簡単な例だと画像を見て位置を最適化することで、もう少し精度を上げれると思う。

2

f:id:ultraist:20090524123606p:image
手で顔の一部が隠されている
f:id:ultraist:20090524123607p:image
画像を見る方法ではできない例。隠れているアゴや口の位置を想像で補う。

3

f:id:ultraist:20090524123608p:image
マイクと指が顔にかぶっている。ウィンク。暗い色の前髪が目とかぶっている。
f:id:ultraist:20090524123609p:image
うまくいかない例。指と前髪がノイズにしては大きすぎる。瞑っている目より目立っている。

4

f:id:ultraist:20090524123610p:image
こなた。アゴがとがっていない。目が線、鼻がない、口がω。
f:id:ultraist:20090524123611p:image
鼻は画像上では存在していないので完全に予測された位置になる。前髪に影響されて目の位置がずれているように思う。

5

f:id:ultraist:20090524123612p:image
ハルヒちゃん。ちびきゃら。口とアゴが融合している。
f:id:ultraist:20090524123613p:image
鼻・口・アゴが下にずれてしまっている。この口無理だろ…。

6

f:id:ultraist:20090524123615p:image
コミック。顔が輪郭線しかない。
f:id:ultraist:20090524123616p:image
大体あってる。

7

f:id:ultraist:20090524123617p:image
線画+ウィンク。顔も目も輪郭線しかない。
f:id:ultraist:20090524131120p:image
少しずれる。目付近の濃い部分に反応する。そもそも検出位置がよくない。