Infinite loop in opencv_traincascade CvCascadeClassifier :: fillPassedSamples
So, I played with the newest LBA waterfall trainer, but I keep working in an endless loop. I believe the reason may be due to my limited negative (background) set of images. However, the program should not run in an infinite loop ... I was able to locate the infinite loop and make some changes to the source code not only to avoid an infinite loop, but also to improve detection performance in the resulting cascading file. However, I would still like someone who understands the code to tell me if this is the correct fix and why it works (or otherwise):
Sample preparation: So I have one positive image and use "creates samples" to generate 100 distorted / rotated positive samples:
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
I only have 5 negative samples in the "negative" directory. Then my tutorial command:
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
Note that I have set -numNeg to 200, although I only have 5 negative images in "neg.txt". Later I learned that numNeg does not need to match the number of negative images, as the program "multiplies" image fragments from your negative images several times to use against positive images for training.
At stage 4, I am in an infinite loop and it is in (see "// !!!!!"):
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;
}
I think the problem is that imgReader.getNeg (img) keeps trimming from the negative set until the "preduct (i) == 1" condition is met to exit the infinite loop. I don't understand what "predict (i)" does, but my guess is that if the negative set is small and limited it will run out of "variety" of images for "predict (i)" to return 1 ... so the loop never does not end. One solution is to increase the negative set, which I will try to do next. Another faster solution is the code I added to // !!!!! to limit the number of attempts to 200 on negative images on average, then forcefully exit the loop if no good candidate is found.
With this fix, my workout resumed stage 5 and then stopped. I put the cascading xml in my application and it performed well enough, better than if I stopped at step 4 to avoid an infinite loop.
Hope someone who understands this code will enlighten us even more ...
Thank you
source to share
Joe
you may come across the same problem as mine.
The problem occurs because opencv_traincascade.exe does not get the correct width and height of the image, and the width and height of the original image is less than the size of the training window.
You can add the two lines indicated by the arrow in the following code to opencv / appa / traincascade / imagestorage.cpp to solve the problem.
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;
....
Hope this solution helps you.
source to share