3

だから私はopencvの最新のLBPカスケードトレーナーで遊んでいて、無限ループに陥り続けています。その理由は、限られたネガ (背景) 画像セットが原因である可能性があると思います。ただし、プログラムは無限ループに陥ってはいけません... 無限ループの場所を特定し、無限ループを回避するためだけでなく、生成されたカスケード ファイルでの検出パフォーマンスを改善するためにソース コードにいくつかの変更を加えました。ただし、コードを理解している人に、これが適切な修正であるかどうか、およびそれが機能する理由 (またはそれ以外の場合) を教えてもらいたいと思います。

サンプルの準備: 1 つのポジ画像があり、「createsamples」を使用して 100 の歪んだ/回転したポジ サンプルを生成しました。

opencv_createsamples -img positive1.png -num 100 -bg neg.txt -vec samples.vec -maxidev 50 -w 100 -h 62 -maxxangle 0 -maxyangle 0.6 -maxzangle 0.4 -show 1

「ネガティブ」ディレクトリにはネガティブサンプルが 5 つしかありません。次に、私のトレーニング コマンド:

opencv_traincascade -data cascade_result -vec samples.vec -bg neg.txt -numStages 10 -numPos 100 -numNeg 200 -featureType LBP -w 100 -h 62 -bt DAB -minHitRate 0.99 -maxFalseAlarmRate 0.2 -weightTrimRate 0.95 -maxDepth 1

「neg.txt」にネガ画像が 5 つしかないにもかかわらず、-numNeg 200 を設定したことに注意してください。後で、numNeg がネガティブ画像の数と一致する必要がないことがわかりました。これは、プログラムがネガティブ画像から画像の一部を繰り返し「トリミング」して、トレーニングのためにポジティブ画像に対して使用するためです。

ステージ 4 で、無限ループに遭遇します ("// !!!!!" を参照):

int CvCascadeClassifier::fillPassedSamples( int first, int count, bool isPositive, int64& consumed )
{
    int getcount = 0;
    Mat img(cascadeParams.winSize, CV_8UC1);
cout << "isPos: "<< isPositive << "; first: "<< first << "; count: "<< count << endl;
    for( int i = first; i < first + count; i++ )
    {
  int inner_count = 0;
  // !!!!! Here is the start of infinite loop
        for( ; ; )
        {
            // !!!!! This is my code to fix the infinite loop:
        /*
        inner_count++;
        if (inner_count > numNeg * 200) // there should be less than 200 crops of negative images per negative image
        {
            cout << "force exit the loop: inner count: "<< inner_count << "; consumed: " << consumed << endl;
            break;
        }
    */
            bool isGetImg = isPositive ? imgReader.getPos( img ) :
                                       imgReader.getNeg( img );
            if( !isGetImg )
                return getcount;
            consumed++;

            featureEvaluator->setImage( img, isPositive ? 1 : 0, i );
            if( predict( i ) == 1 )
            {
                getcount++;
                break;
            }
        }
    }
    return getcount;
}

問題は、「preduct(i) == 1」条件が満たされて無限ループを終了するまで、 imgReader.getNeg(img) が負のセットからトリミングし続けることだと思います。「predict(i)」が何をするのかわかりませんが、負のセットが小さくて制限されている場合、「predict(i)」が 1 を返すための「さまざまな」画像が不足すると思います...ループは決して終了しません。解決策の 1 つは、次に試みるネガティブ セットを作成することです。他のより迅速な解決策は、// !!!!! で追加したコードです。試行回数を負の画像ごとに平均 200 に制限し、適切な候補が見つからない場合は強制的にループを終了します。

この修正により、私のトレーニング セッションはステージ 5 に進み、そこで停止しました。アプリにカスケード xml を配置したところ、ステージ 4 で停止を設定して無限ループを回避した場合よりもパフォーマンスが向上しました。

コードをもっと理解している人が私たちをさらに啓発してくれることを願っています...

ありがとうございました

4

1 に答える 1

2

ジョー

あなたは私のような同じ問題に遭遇するかもしれません。

この問題は、opencv_traincascade.exe が画像の幅と高さを正しく取得しないか、元の画像の幅と高さがトレーニング ウィンドウのサイズよりも小さいために発生します。

この問題を解決するには、次のコードの矢印で示された 2 行を opencv/appa/traincascade/imagestorage.cpp に追加します。

bool CvCascadeImageReader::NegReader::nextImg()
{
    Point _offset = Point(0,0);
    size_t count = imgFilenames.size();
    for( size_t i = 0; i < count; i++ )
    {
        src = imread( imgFilenames[last++], 0 );
        if(src.rows<winSize.height || src.cols < winSize.width)   <-----------
            continue;                                             <-----------
        if( src.empty() )
            continue;
....

このソリューションがお役に立てば幸いです。

于 2013-03-19T09:17:35.977 に答える