所以我一直在玩opencv最新的LBP级联训练器,我一直在遇到无限循环。我相信原因可能是由于我有限的负片(背景)图像集造成的。但是,程序不应该陷入无限循环...我设法确定了无限循环的位置,并对源代码进行了一些修改,不仅避免了无限循环,而且还提高了生成的级联文件中的检测性能。但是,我仍然希望了解代码的人告诉我这是否是一个正确的修复程序以及为什么它有效(或其他方式):
样品制备:所以我有一个正图像,并使用"创建样本"生成 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
请注意,我设置了 -numNeg 200,即使我在"neg.txt"中只有 5 个负片图像。后来我发现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;
}
我认为问题是 imgReader.getNeg(img) 不断从负集裁剪,直到满足"preduct(i) == 1"条件退出无限循环。我不明白"predict(i)"是做什么的,但我确实猜测,如果负集很小且有限,那么"predict(i)"返回 1 的图像"种类"就会用完......所以循环永远不会结束。一种解决方案是创建负集,这就是我接下来要尝试的。另一个更快的解决方案是我在//中添加的代码!!!! 要将每个负图像的平均 try 数量限制为 200 个,如果未找到好的候选图像,则强制退出循环。
通过此修复,我的训练课程进入第 5 阶段,然后停在那里。我将级联 xml 放在我的应用程序中,它的性能相当不错,比我在阶段 4 设置停止以避免无限循环要好。
我希望更了解代码的人能进一步启发我们......
谢谢
joe
您可能会遇到与我相同的问题。
导致此问题的原因是opencv_traincascade.exe未正确获取图像宽度和高度,或者原始图像宽度和高度小于训练窗口大小。
您可以在下面的代码中添加两条箭头指向的行到 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;
....
希望此解决方案对您有所帮助。