読者です 読者をやめる 読者になる 読者になる

ニートがプログラミングするブログ(はてな出張所)

ニートがプログラミングするブログです。今は主にコンピュータビジョンに関することをやっています。

ディープラーニングを使わない顔認識

最近は様々なところでディープラーニングが使われています。
ここで書く顔認識の分野でも主流となっています。
しかし、この記事ではあえてそれを使わない方法を説明します。
というか単にディープラーニングがうまく扱えなくて、自己流で顔認識技術を改良して言っただけですが……。
ちなみにここでは、画像中から人の顔を見つけるのが顔”検出”、その顔が誰であるかを特定するのが顔”認識”ということにしておきます。

一昔前の顔認識ではeigen face、fisher faceやLBPなどが使われていました。
これらはOpenCVに実装されているので、簡単に利用することが出来ます。
しかし実際に試してみたところ、これらは精度があまり高くない気がしました。
他に良い方法がないか探していたら、ぱろすけさんがAV女優の顔認識に関する論文を書いていたのでそれを参考にしました。
ちなみに、この論文は既に削除されてるようです。
論文中ではHistogram of Oriented Gradients(HOG)特徴量を使っていました。
HOGはその性質上、人の”検出”にはよく利用されますが、顔の”認識”にはあまり利用されないという印象があります。
とはいえ試してみたらそこそこの精度が出たのでHOGを使っています。
そんなわけでHOGを使った顔認識について具体的に書いていこうと思います。

1.データの水増し data augmentation
識別器の精度を上げるためにデータ数を増やします。
僕の実装では左右反転と色調補正を行いました。
色調補正ではガンマ補正を使いました。

2.顔検出 face detection
次に画像中から顔の部分を切り取ります。
この切り取った小さな画像のことをパッチといいます。
顔検出ではOpenCVが良く利用されていますが、ここではより精度の高いdlibの顔検出を利用しています。
検出される領域は少し小さいので、僕の実装では各辺を1.3倍くらいにしています。

3.顔の特徴点検出 landmark detection
次に顔の特徴点を検出します。
特徴点とは目尻や目頭、口の端などの部分です。
OpenCVには特徴点検出機能がないので、dlibのものを使うか、detectFace();を使うのが楽だと思います。
僕は自分で実装しましたが、面倒なので上のものを使うのが良いかと。

4.顔の位置合わせ face alignment
どれでもいいのですが1枚基準となる顔画像を選んでおきます。
そして他の画像をこの画像に合うようにアフィン変換を適用します。
アフィン変換とは拡大縮小、回転、平行移動を行う変換のことをいいます。
変換で使うパラメータは、3番で求めた特徴点を用いて、procrustes analysisや参考文献[1]のAppendix Dの方法で求めます。
僕の実装では位置合わせが済んだら全画像のサイズを一辺が約200pxの正方形にしています。

5.特徴量の計算 HOG feature
それぞれの人がどんな顔をしているのかを数値的に表したものを特徴量といいます。
一般的にはLBPが用いられますが、経験的にHOGのほうが良かったのでそっちを使います。
HOGは比較的簡単に実装できますが、dlibのFHOG(HOGの改善版)を使うのが簡単だと思います。
僕の実装では、特徴点を中心とする一辺が60pxの正方形のパッチのHOGを求めています。
ただし、すべての特徴点で取ると制度が悪くなるので、5個置きに取っています。
僕の場合特徴点は合計で81個あるので、81/6=13箇所でHOGを取っています。
さらに画像を2倍に拡大して同様のことを行うので、合計26箇所でHOGを取っています。
ちなみにHOGのセルサイズは20px、ブロックサイズは2セルx2セル、ヒストグラムのサイズは12です。

6.次元圧縮 dimensionality reduction
5番で求めたHOGを全て連結(concatenate)して特徴量として使うのもありですが、次元圧縮をしたほうが精度が上がります。
僕の実装ではPCAを使い次元圧縮をしています。

7.識別器の作成 neural network
6番で求めた特徴量を全て連結してベクトルとして、ニューラルネットワークをトレーニングします。
ただし、特徴量をそのまま入れると学習がうまく進まないので、各次元ごとに値が平均0分散1となるように標準化します。
僕の実装では1つのニューラルネットワークで多クラス問題として扱わずに、人数分の二値問題用のニューラルネットワークを作りました。
ちなみに入力層と出力層だけの1層ニューラルネットワークを使っています。

8.テスト test
テスト時には1番から6番までの処理を行い、7番で作ったニューラルネットワークに入れます。
僕の実装では、データの水増しは左右反転と3段階のガンマ補正を行った計6枚の画像をテストして、その平均値を出力確率としています。

実際はもう少しこまごまとしたテクニックを使っていますが、せいぜい3%程度しか識別率が上がらないので省略します。
この手法の精度を測るために、sugyanさんのアイドルデータセットを使いました。
面倒なのでcase#5しか測っていませんが、正解率は96%でディープラーニングとほぼ同等の精度が出ています。

この方法を使いAV女優の検索サービスを作ったのでぜひお試し下さい。

それからこんな面倒な方法を使わずともAPIやライブラリを使えばもっと楽に顔認識ができます。
一例として以下の4つを挙げておきます。
Microsoft Face API
face++
OpenFace
OpenBR

参考文献
[1]Cootes, Tim, E. Baldock, and J. Graham. "An introduction to active shape models." Image processing and analysis (2000): 223-248.