OpenCVを使って動体検出(face-detectionとか)を行う場合に使用するCascadeClassifier.detectMultiScaleについて、パラメータを変えて試してみる。
Method Detail
public void detectMultiScale(Mat image, MatOfRect objects, double scaleFactor, int minNeighbors, int flag, Size minSize, Size maxSize)
- image:
- objects:
- scaleFactor:
- minNeighbors:
- flags:
- minSize:
- maxSize:
CV_8U型の行列。ここに格納されていいる画像中から物体が検出されます。
矩形を要素とするベクトル。それぞれの矩形には、検出した物体を含みます。
画像スケールにおける縮小量を表します。
物体候補となる矩形は、最低でもこの数だけの近傍矩形を含む必要があります。
このパラメータは、新しいカスケードでは使用されません。古いカスケードに対しては、cvHaarDetectObjects関数の場合と同じ意味を持ちます。
物体が取り得る最小サイズ。これよりも小さい物体は無視されます。
物体が取り得る最大サイズ。
scaleFactorの意味については、物体検出のアルゴリズムを当たるべきだとは思いますが…今回は後回しにして動かしてみました。
ざっとネット調べて見た結果、ある特定の大きさの画像で学習した分類器を使って、様々なサイズの画像に対し検出を行うために、画像を異なるスケールで複数回の探索処理を行う必要があり、そのスケール変更のパラメータとしてscaleFactorが使用されるようです。
scaleFactorに設定した値(>=1.01)を使って画像を縮小(1.01なら1%ずつ縮小)しながら何度も探索を行っている。
<参考>
カスケード型分類器
how-does-the-parameter-scalefactor-in-detectmultiscale-affect-face-detection/
今回試したこと
顔検出プログラムで、scaleFactorの値を変化させて、
・検出精度(誤認識数、見逃し率)
・処理時間
を調べてみました。
実験に使った顔画像は、フリー素材で見つけてきたサイズの異なる29枚(顔90個)の画像です。
例)
環境
・Ubuntu 14.04 64bit (CPU:Intel Core i5 660@3.33GHzx4, MEM:3.9GB)
・OpenCV 2.4.10
・Java 1.8.0_40
実験プログラムはJavaで記述しています。
カスケード型分類器にはhaarcascade_frontalface_default.xmlを使用しています。
scaleFactor以外のパラメータは、minNeighbors=3, flags=CASCADE_SCALE_IMAGE, minSize=30×30, maxSize=なしです。
結果
scaleFactorを1.01から0.1刻みで1.71まで変化させた場合
顔以外の場所を検出した数
1.01が飛び抜けて多く1.11以降は数件に減少しました。
例:1.01の結果
顔を検出できなかった率
1.21から半分以上見落とすという結果になりました。
(実験に使用した画像の影響が大きいとも思いますが…若干ピンぼけや顔が傾いている画像だと検知しない場合が多かったです)
誤検出数と合わせて考えると、scaleFactorは1.11以下の方がいいパフォーマンスを発揮しそうです。
そこで、次は1.11以下をもう少し細かく調べてみました。
scaleFactorを1.03から0.02刻みで1.11まで変化させた場合
顔以外の場所を検出した数
顔を検出できなかった率
1.11以下をもう少し細かく見てみましたが、今回の実験の結果からだと1.11が最も誤検知が少なく、且つ検出漏れが少ないという結果になりました。
処理時間
detectMultiScale関数の処理時間です。
実験画像の中からサイズが大きい6画像(W1600xH1060前後)について、処理時間を測りました。
処理時間はscaleFactorが大きくなるほど減少します。
scaleFactor=1.11で平均2569msでした。さすがに2秒もかかると動画でリアルタイム検出とかは無理なので、カメラの解像度を落とすなどの対策が必要そうですね。
ちなみに幅481×高さ322pxをscaleFactor=1.11で実行した場合は、約200msでした。5fps…う〜む。
(Javaからコールするオーバーヘッドが結構あるような気もします)
前回試したAndroidでのFaceDetctionデモだと幅320x高さ240で10〜15fpsぐらいでした。
今回試してみたことは以上です。
あとがき
スマホで物体検出をやろうと思って、最近OpenCVを勉強し始めました。
まだ勉強始めたばかりで分からないことだらけですが、これからもいろいろ実験した結果をブログに書いていこうと思います。
顔検出の精度向上案としては、目や口の検出と併せて、「顔の中に目や口があるか」というような検出ロジックにすれば、誤検知率を低く抑えることができそな気がします。
でもはやり、スマホでリアルタイム検知をすとなると処理負荷が一番のネックかも。