OpenCVの物体検出器を学習する際の注意点。
物体検出器の原理や学習方法については、ここを読んで下さい。
で、たとえば
opencv_createsamples -info positive.txt -num 1000 -vec hoge.vec -w 30 -h 30
みたいな感じで1000枚の正例画像からvecファイルを作ったとします。
次に
opencv_traincascade -data hoge -vec hoge.vec -bg negative.txt -numPos 1000 -numNeg 3000 -numStages 5 -w 30 -h 30 -minHitRate 0.995 -maxFalseAlarmRate 0.4
という感じで学習をさせると、以下のようなエラーが出ます。
OpenCV Error: Bad argument (Can not get new positive sample. The most possible reason is insufficient count of samples in given vec-file.) in get, file /home/user/opencv/apps/traincascade/imagestorage.cpp, line 159 terminate called after throwing an instance of 'cv::Exception'
この原因と対処法は、ここらへんに書いてあります。
http://answers.opencv.org/question/776/error-in-parameter-of-traincascade/?answer=792#post-id-792
http://answers.opencv.org/question/4368/traincascade-error-bad-argument-can-not-get-new/
で、要約すると対処法は以下の式にしたがってnumPos引数の値を決めればOKです。
numPos =< (N-S) / (numStage + minHitRate - minHitRate * numStage)
ここで、Nはvecファイル内のサンプル数、Sは適当なバッファです。
またnumPos、minHitRate、numStageは、それぞれopencv_traincascadeの引数で
- minHitRateは各ステージで満たすべき最小認識率
- numPosは1つのステージで使用する正例の数
- numStagesはステージ数
です。
以下、なぜそういうことになるのか興味のある人だけ読んで下さい。
学習の各ステージではvecファイル内のサンプルのうち、numPosだけが使用されます。
そして各ステージの最悪のケースでは、
numPos * (1-minHitRate)
の数だけの学習サンプル(正例)が背景と誤認識される可能性があります。
ここで背景と判断されたサンプルは、以後のステージでは使用されません。
したがって、棄却された分のサンプルを新たにvecファイルから継ぎ足してやる必要があります。
vecファイル内のサンプル数をNとすると、
N >= numPos + numPos * (1 - minHitRate) * (numStages - 1)
を満たす必要があります。さらに、各ステージでvecファイルから新たに追加されたサンプルが、現在のステージの識別器で(次のステージで使用される前に)即座に背景として棄却される場合もあり得るので、その数を仮にSとすると、
N >= numPos + numPos * (1 - minHitRate) * (numStages - 1) + S
となります。
したがって、numPosは以下の式にしたがって求めれば良いことになります。
numPos =< (N-S) / (numStage + minHitRate - minHitRate * numStage)