cv::CascadeClassifier类在多次读取新版本xml模型时的错误及其修正

2024-04-21 08:08

本文主要是介绍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中实际上封装了新旧两种分类器,对于老版本的xml模型文件,CascadeClassifier会用CvHaarClassifierCascade去解析,并用cvHaarDetectObjects去检测。而对于新版本的xml文件,CascadeClassifier会用自己的一套格式去解析。

    在程序的实现上,CascadeClassifier对老版本的xml文件读取很简单,所以不会出什么问题。但是对新版本的xml文件的读取,其实现上有很多缺陷。如果你用下面代码创建了一个分类器:

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文件格式是新版本的。

    对于老版本的xml文件是不存在这个问题的。因为读取老版本文件时,程序是不会调用CascadeClassifier::read(const FileNode &root)函数的。这个函数只会在读取新版本xml文件时,在load()中被调用。

    read()函数之所以会导致程序崩溃,其原因是CascadeClassifier类有很多vector类型的成员变量,每次调用read()函数填充这些变量时,都没有清空这些变量,而直接往这些变量里push_back元素。如此一来这些vector的长度会随着read()的调用而不断增加。其中影响最明显的成员变量是:

vector<Stage> CascadeClassifier::stages

该变量的size决定了循环的次数。如果当前模型只有20个stage,但是上次读取xml时该变量没有清空,那么CascadeClassifier::stages的长度可能会变成40。于是当前检测人脸的时候会循环40次,但是模型实际上只有20个stage,循环次数超过20的时候,索引出来的其他变量可能就是无效的,从而导致下标越界,使程序崩溃。

    要修正这个bug实际上很简单,只需要在read()函数的开头添加如下代码,清空上次的数据即可:

 stages.clear();
 classifiers.clear();
 nodes.clear();
 leaves.clear();
 subsets.clear();
 feval.release();



   按照作者的思路,应当是需要把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模型时的错误及其修正的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/922573

相关文章

使用Python将JSON,XML和YAML数据写入Excel文件

《使用Python将JSON,XML和YAML数据写入Excel文件》JSON、XML和YAML作为主流结构化数据格式,因其层次化表达能力和跨平台兼容性,已成为系统间数据交换的通用载体,本文将介绍如何... 目录如何使用python写入数据到Excel工作表用Python导入jsON数据到Excel工作表用

浅谈配置MMCV环境,解决报错,版本不匹配问题

《浅谈配置MMCV环境,解决报错,版本不匹配问题》:本文主要介绍浅谈配置MMCV环境,解决报错,版本不匹配问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录配置MMCV环境,解决报错,版本不匹配错误示例正确示例总结配置MMCV环境,解决报错,版本不匹配在col

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

Linux卸载自带jdk并安装新jdk版本的图文教程

《Linux卸载自带jdk并安装新jdk版本的图文教程》在Linux系统中,有时需要卸载预装的OpenJDK并安装特定版本的JDK,例如JDK1.8,所以本文给大家详细介绍了Linux卸载自带jdk并... 目录Ⅰ、卸载自带jdkⅡ、安装新版jdkⅠ、卸载自带jdk1、输入命令查看旧jdkrpm -qa

Tomcat版本与Java版本的关系及说明

《Tomcat版本与Java版本的关系及说明》:本文主要介绍Tomcat版本与Java版本的关系及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Tomcat版本与Java版本的关系Tomcat历史版本对应的Java版本Tomcat支持哪些版本的pythonJ

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

基于Flask框架添加多个AI模型的API并进行交互

《基于Flask框架添加多个AI模型的API并进行交互》:本文主要介绍如何基于Flask框架开发AI模型API管理系统,允许用户添加、删除不同AI模型的API密钥,感兴趣的可以了解下... 目录1. 概述2. 后端代码说明2.1 依赖库导入2.2 应用初始化2.3 API 存储字典2.4 路由函数2.5 应

Python中ModuleNotFoundError: No module named ‘timm’的错误解决

《Python中ModuleNotFoundError:Nomodulenamed‘timm’的错误解决》本文主要介绍了Python中ModuleNotFoundError:Nomodulen... 目录一、引言二、错误原因分析三、解决办法1.安装timm模块2. 检查python环境3. 解决安装路径问题