2015. 3. 1.
2015.10.26. 全面的に書き換え
2017.10. 4. OpenCV3.3.0とVisual C++ 2017で動作確認済み、ただし、文末の付記参照

石立 喬

OpenCVとVisual C++による画像処理と認識(13)

----- カスケード分類器と訓練済みデータで顔と人物を検出する -----

 OpenCVの本格的な応用分野の一つである顔と人(歩行者)の検出を行う。分類器にはカスケード分類器を用い、豊富な学習済みデータと便利な関数を用いて、いろいろな方法を比較した。

顔の検出と人物(歩行者)の検出
 顔の検出は、デジカメのピント合わせや電子広告板の制御などに使われ、人物(歩行者)の検出は、クルマの運転の際の警報や不審者の発見などに用いられている。検出は、認識と異なり、特定の個人を識別するものではない。顔や人物の検出は、古くからの研究を経て、二つのアルゴリズムの組み合わせが主流となっている。一つは特徴(量)の選び方で、Haar-like特徴、LBP(Local Binary Patterns)特徴、HOG(Histogram of Oriented Gradients)特徴などがあり、他は分類器(識別器)の選択で、ここで取り上げたAdaBoostを用いたカスケード分類器の他に、SVM(Support Vector Machines)などがある。
 顔に比べて、人物の検出は難しい。衣服や姿勢によって変化し、背景との区別も困難である。静止画ではなく動画の場合は、移動物体としての検出が助けになる。
 Haar-lile特徴は、Haar氏の考えたHaarウエーブレットに似ているところから、この名前が付けられた。白黒の部分に分けられた矩形をテンプレートマッチングさせ、局所的に、エッジ、直線、コーナーなどを検出し、これらを特徴とする。
 LBP特徴は、注目するピクセルの周囲のピクセルと濃淡を比較し、周辺の方が明かるけれは1を、暗ければ0を割り当てて二進符号化し、それを10進値で表す。計算時間が短縮でき、照明などの明暗の影響を受けにくい。
 HOG特徴は、セルごとに9方向の濃度の勾配をデータ化した、一種のエッジ情報の集まりである。セルの集まりであるブロック内でコントラストの正規化が行われるので、明暗には強い。
 AdaBoostはadaptive boostの意味で、適応的に分類器の能力を強化するアルゴリズムである。能力の低い個々の弱い分類器の出力に重みを掛けて合計して結果を求め、正しい結果と比較して、重みを修正して学習させ、これを繰り返して、全体として能力の高い強い分類器を作る仕組みである。

カスケード分類器による顔と人(歩行者)の検出
◎カスケード分類器とは
 カスケードとは、本来、何段かに分かれて落ちる滝のことで、電子工学では、増幅器のカスケード接続で知られている。ネットワーク接続でも使われる。ここでは、分類器を何段も直列に並べ(プログラム的には、データを何回も分類器に通し)、一段ごとに、検出対象でないと判断された部分を除去して行くプロセスをカスケードと称している。より具体的には、Haar-like特徴などを使い、数多くの正しいサンプルと偽サンプルで十分訓練し、ブーストされた分類器をカスケード状に直列に並べるアルゴリズムである。
◎カスケード分類器の設定方法
 CascadeClassifierクラスを用いる。このクラスをコンストラクトする際に、引数として、訓練済みのデータファイルを指定すると、目的に応じた分類器ができる。訓練済みデータファイルには、表1に示すものが用意されているので、カスケード分類器に、読み込んで使用する。これらはopencv/sources/data/にあり、必要なファイルをプロジェクトフォルダにコピーしておくか、フルパスで指定する。

表1 OpenCVのcascadeClassifierに備わっている訓練済みデータ


◎ここで紹介する内容
 OpenCVに備わっているCascadaClassifierを用いて、表1に従って、下記のように性能を確認する。
 1)顔の検出
   Haar-Like特徴を用い、複数の訓練済みデータファイルを比較する(プログラムは図1、結果は図2)
   LBP特徴を用いて、専用の訓練済みデータファイルを確認する(プログラムは図1、結果は図3)
 2)人(歩行者)の検出
   Haar-like特徴を用いて、専用の訓練済みデータファイルを確認する(プログラムは図4、結果は図5)
   HOG特徴を用いて、専用の訓練済みデータファイルを確認する(プログラムは図4、結果は図6)

カスケード分類器で顔を検出するプログラム
 図1は、カスケード分類器で顔を検出プログラムで、下記から成っている。
 1)被検索原画像を読み込み、グレイスケール化して、さらにヒストグラムの平坦化(コントラストの向上)を行う。
 2)使用する訓練済みデータを選んで、カスケード分類器cascadeを生成する。
 3)カスケード分類器を、デフォルトや条件設定のいずれかを選んで実行させ、結果をベクトルfacesに入れる。
 4)ベクトルfacesを読み取って、原画像上に黄色で矩形を描く。

使用したOpenCV関数の説明
◎CascadeClassifierクラス
 このコンストラクタには、
   CascadeClassifier classifier(ファイル名);
があり、ファイル名には、用途に応じて訓練済みデータを入れる(表1参照)。
◎CascadeClassifier::detectMultiScale関数
 カスケード分類器を実際に使用する際に用いる関数で、複数のオーバーロードされた関数のうち、一番簡単なものを紹介する。この関数は、被探索画像と探索窓との相対的なサイズを変えながら検出を繰り返すので時間がかかる。引数は、
   image ------------- 被探索画像、CV_8UC1のグレイスケール
   objects ------------ vector<Rect>型の検出結果出力
   scaleFactor = 1.1 ---- 探索窓のスライドが一回終わる度に探索窓の相対的サイズを拡大する比率
   minNeighbors = 3 ---- 候補の検出物に対する近傍の矩形の最小数(別途説明を参照)
   flags = 0 ----------- 処理フラグ(別途説明を参照)
   minSize = Size() ----- これ以内の対象物は無視する、デフォルトは無視しない
   maxSize = Size() ---- これ以上の対象物は無視する、デフォルトは無視しない
で、戻り値はない。
 minNeighborsは、若干のずれを伴って複数の位置に検出結果が出た場合、その値未満の個数しかないときは、顔または人と判定しない値である。これにより偽検出が防げるが、見落とす恐れもある。デフォルトの3を、2に減らすと、より多くの検出が可能になるが、偽検出も増える。ここでは、条件設定の場合に、minNeighbors = 2として比較した。
 処理フラグについては、「最近のCascadeClassifierでは使用しない」とあるが、試みてみたところ、flags = 2で、顔検出に関して、やや良い結果が得られた。人の場合では、かえって悪くなることもあった。理由については、分からない。
 処理フラグについては、下記に示す。= の後の数字が、関連づけられた整数値である。
  デフォルト = 0 --------------------------------- 下記のいずれも行わない
  CASCADE_DO_CANNY_PRUNING = 1 -------------- キャニーでエッジが検出されなかった場所は省いて高速化
  CASCADE_SCALE_IMAGE = 2 --------------------- 探索窓を拡大する代わりに、被検索画像を縮小する
  CASCADE_FIND_BIGGEST_OBJECT = 4 ------------ 最大の検出顔を一個だけ取り出す
  CASCADE_DO_ROUGH_SEARCH = 8 --------------- 粗くスキャンして高速化
 上記各フラグは、複数個同時に使用でき、論理和記号「|」で区切って使用する。その場合、デフォルトの「0」を含める必要はない。



図1 カスケード分類器で顔を検出する


カスケード分類器でHaar-like特徴を用いて顔を検出した結果
 図2は得られた結果で、図1のプログラムで、26~28行を選択的に使用した。_alt.xmlを使い、minNeighbors = 2、flags = 2の場合が、最も多くの顔(一部が欠けた顔も含めて、9人)を検出できた。完全な横顔と、半分近くが隠れた顔は、検出できなかった。これは、やむを得ないものと思われ、十分優れた性能が得られている。



上から、frontface_default.xml、_alt、_alt2の順、左はminNeighbors = 3(デフォルト)、右はminNeighbors = 2(条件設定)

図2 Haar-like特徴では、alt.xmlを用い、detectMultiScaleを条件設定した結果が一番が良かった


カスケード分類器でLBP(Local Binary Patterns)特徴を用いて顔を検出した結果
 Haar-like特徴に似ているが、周辺ピクセルとの濃度比較を二進符号化して使用する。精度はやや低いが、学習、検索共にHaar-like特徴よりも高速なのが長所である。OpenCVにも、既述の通り、LBP用の二つのデーターファイルがあるので、ここでは、lbpcascade_frontface.xmlをcascadeに設定して使用した。プログラムは、図1において29行を選択して使用した。detectMultiScale関数をデフォルトと条件設定で使用した結果は全く同じであったので、条件設定による場合のみを図3に示す。条件設定をいろいろ変えて見たが、特に改善されなかった。一部が欠けた顔には弱いようである。


図3 LBP特徴では、detectMultiScaleの条件設定を変えても、デフォルトと同じで、良くならなかった


カスケード分類器で人(歩行者)を検出するプログラム
 プログラム的には、CascadeClassifierのコンストラクタで、haarcascade_fullbody.xmlを読み込めばよいだけであるので、変更部分のみを図4に示す。detectMultiScaleで、flags = 2を選ぶと悪くなったので、条件設定は、minNeighbors = 2のみである。


図4 カスケード分類器で人(歩行者)を検出する


カスケード分類器でHaar-like特徴を用いて人(歩行者)を検出した結果
 図5は得られた結果で、いずれもデフォルトの方が良いか、または同等の結果が得られている。条件設定とは、この場合、最小近傍矩形数 minNeighbors = 2とすることである。


左はminNeighbors = 3(デフォルト)、右はminNeighbors = 2(条件設定)

図5 Haar-like特徴とカスケードで人物検出の結果

カスケード分類器でHOG(Histogram of Oriented Gradients)特徴を用いて歩行者を検出した結果
 HOGの検出窓は、セルと呼ぶ8x8ピクセル程度の小さな領域に分割され、各セルについて濃度の勾配のヒストグラム情報を付加する。勾配は9方向あり(デフォルト)、各セルは、セルを2x2個程度に集めた、より大きい領域のブロックごとに、コンストラストを正規化する。近傍のブロックとはオーバーラップさせる。図4のプログラムで、27行を選択した。HOG記述子を、細かく設定できれば、より良い結果が得られたのではないかと思われる。



図6 HOG特徴とカスケードで人物検出の結果


カスケード分類器を用いた顔の検出で分かったこと
 特定の画像についてのみの結果であるので、確定的なことは言えないが、下記の結論を得た。
1)顔検出の訓練済みデータファイルでは、frontalface_altが最もよく、_alt2、_defaultが僅差で続いた。
2)lbpcascadeは、欠け(occlusion)のない、ほぼ正面を向いた顔しか検出できなかった。
3)最小近傍矩形数(minNeighbors)は、デフォルトの3よりは、2に減らした方が良い傾向があった。
4)処理フラグでは、flags = 2(CASCADE_SCALE_IMAGE)がやや良かった。理由についてはわからない。

カスケード分類器を用いた人(歩行者)の検出で分かったこと
 特定の画像についてのみの結果であるので、確定的なことは言えないが、下記の結論を得た。
1)Haar-like特徴を用いた場合には、デフォルトの設定(minNeighbors = 3)の方が良い結果が得られた。
2)LBP特徴は、人物用の訓練データがないので使えない。
3)HOG特徴は、全く検出できない例があり、一部検出できても、人物よりも広い範囲検出された。HOG特徴の記述子の条件設定が、小さい対象物の検出には無理なのかもしれない。

結 論
 カスケード分類器は、AdaBoostと言う学習アルゴリズムを用い、検出能力を高めている。これは、局所的な単純な判断を積み重ねて行くHaar-like特徴と相性が良いのかも知れない。ここでは、カスケード分類器では、Haar-like特徴が良いとの結果が出た。
 現在は使われなくなったとの説明がある処理フラグであるが、これは使用できた。設定内容については一長一短があり、被探索画像によって異なるようである。一般的には、デフォルト設定のflags = 0で使うのが無難であった(最善ではないが、大きな欠点も無かった)。
 顔の検出は、Haar-like特徴の使用で、ほぼ良好な結果が得られたが、人物(歩行者)の検出については、静止画の場合、背景との識別が困難で、十分とは言えなかった。特に、OpenCVに付属の訓練済みデータを使った限りでは、Haar-like特徴に比べて、HOG特徴が劣っていた。
 これらの結論は、OpenCV付属の訓練済みデータのみに基づくもので、被探索画像の内容や数量による差である可能性がある。したがって、アルゴリズムの良否を断定できるものではない。

付 記
 OpenCV3.3.0とVisual C++ 2017を使用するにあたり、下記を参照されたい。それ以外は、古いプログラムをそのまま使用できる。
 1)従来のインクルードファイルをそのまま使用しても良いが、#include <opencv2/opencv.hpp>と変更しても問題はない。
 2)従来のint _tmain(int argc, _TCHAR* argv[])をそのまま使用しても良いが、int main()にしても差支えない。
 3)vectorを使用するのに、using namespace std;の追加が必要である(従来は無くても良かったような気がする)。
 4)OpenCV3.2.0からOpenCV3.3.0になって、lbpcascade_frontface_improved.xmlが追加になったので、使用してみたが、ここで使用している場合と条件に限っては、かえって性能が悪かった。





参考文献
 P.Viola and M.Jones, "Rapid Object Detection Using a Boosted Cascade of Simple Features"(2001)
 http://www.merl.com/publications/docs/TR2004-043.pdf

 R.Lienhart and J.Maydt, "An Extended Set of Haar-like Features for Rapid Object Detection"(2002)
 http://www.lienhart.de/Prof._Dr._Rainer_Lienhart/Source_Code_files/ICIP2002.pdf

 N.Dalal and B.Triggs, "Histogram of Oriented Gradientsfor Human Detector"(2005)
 http://eprints.pascal-network.org/archive/00000802/01/Dalal-cvpr05.pdf

 T.Ahonen, A.Hadid and M.Pietikairen, "Face Recognition with Local Binary Patterns"(2006)
 http://masters.donntu.org/2011/frt/dyrul/library/article8.pdf





「Visual C++の勉強部屋」(目次)へ