本文主要是介绍cv::CascadeClassifier类在多次读取新版本xml模型时的错误及其修正,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
偶然机会,试了试opencv中自带的人脸检测器,自带的haar和hog分类器xml文件读入时都不会有错误,但是在用lbp文件时发生了类似于vector越界的问题,找到了相应的vector,的确是这个提示,但是由于xml文件读取时只有一句load含税,调用的dll也无法跟进去浸提函数,也没有怀疑过opencv会出现错误。因此换了台电脑想用侥幸的办法试试,依旧是相同的问题。之后又想可能是我的opencv300版本来自民间,不稳定,难免会有bug,因此从别处copy另一版本的(opencv247)的lbpcascade_frontalface.xml文件,还是同样的问题,文件是一样的。。。然后又用opencv247建了新的工程,相同问题。。。好吧,看来可能opencv还真有问题。于是乎网上搜索,看到了类似问题的帖子 :http://blog.sina.com.cn/s/blog_4298002e010153hn.html。原文如下:
在现在的OpenCV版本中,使用级联分类器做人脸检测的时候,有两种选择:一是使用老版本的CvHaarClassifierCascade,一是使用新版本的CascadeClassifier类。老版本的分类器只支持类Haar特征,而新版本的分类器既可以使用Haar,也可以使用LBP特征。
CascadeClassifier *pClassifier = new CascadeClassifier;
若在程序的使用中,不释放该对象,只是来回在Haar特征和LBP特征之间切换,比较两种特征检测人脸的效果,如下:
Mat matImage;
vector<Rect> objs;
pClassifier->load("haarcascade_frontalface_default.xml");
pClassifier->detectMultiScale(matImage, objs, 1.1, 3);
pClassifier->load("lbpcascade_frontalface.xml");
pClassifier->detectMultiScale(matImage, objs, 1.1, 3);
pClassifier->load("haarcascade_frontalface_default.xml");
pClassifier->detectMultiScale(matImage, objs, 1.1, 3);
pClassifier->load("lbpcascade_frontalface.xml");
pClassifier->detectMultiScale(matImage, objs, 1.1, 3);
那么程序会果断的崩溃,因为lbpcascade_frontalface.xml文件格式是新版本的。
vector<Stage> CascadeClassifier::stages
该变量的size决定了循环的次数。如果当前模型只有20个stage,但是上次读取xml时该变量没有清空,那么CascadeClassifier::stages的长度可能会变成40。于是当前检测人脸的时候会循环40次,但是模型实际上只有20个stage,循环次数超过20的时候,索引出来的其他变量可能就是无效的,从而导致下标越界,使程序崩溃。
按照作者的思路,应当是需要把objdetect对应的文件夹中的源文件考到自己的工程中,然后,修改需要修改的部分,再与自己的程序一起编译即可。找了半天,终于找到了类似的地方,按照类似的方法改过,成功了。在文件cascadedetect.cpp中大概960行的位置,修改为:
bool CascadeClassifierImpl::load(const String& filename)
{oldCascade.release();data = Data();featureEvaluator.release();node.stages.clear(); //modify 20150505node.classifiers.clear();node.nodes.clear();node.leaves.clear();node.subsets.clear();FileStorage fs(filename, FileStorage::READ);if( !fs.isOpened() )return false;if( read_(fs.getFirstTopLevelNode()) )return true;fs.release();oldCascade.reset((CvHaarClassifierCascade*)cvLoad(filename.c_str(), 0, 0, 0));return !oldCascade.empty();
}
这篇关于cv::CascadeClassifier类在多次读取新版本xml模型时的错误及其修正的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!