本文主要是介绍2001 Rapid object detection using a boosted cascade of simple features(Paul Viola et al)读后感,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、理论
二、类Harr特征及数量
三、Adaboost
在了解Adaboost方法之前,先了解一下Boosting方法。
回答一个是与否的问题,随机猜测可以获得50%的正确率。如果一种方法能获得比随机猜测稍微高一点的正确率,则就可以称该得到这个方法的过程为弱学习;如果一个方法可以显著提高猜测的正确率,则称获取该方法的过程为强学习。1994年,Kearns和Valiant证明,在Valiant的PAC(Probably ApproximatelyCorrect)模型中,只要数据足够多,就可以将弱学习算法通过集成的方式提高到任意精度。实际上,1990年,SChapire就首先构造出一种多项式级的算法,将弱学习算法提升为强学习算法,就是最初的Boosting算法。Boosting意思为提升、加强,现在一般指将弱学习提升为强学习的一类算法。1993年,Drucker和Schapire首次以神经网络作为弱学习器,利用Boosting算法解决实际问题。前面指出,将弱学习算法通过集成的方式提高到任意精度,是Kearns和Valiant在1994年才证明的,虽然Boosting方法在1990年已经提出,但它的真正成熟,也是在1994年之后才开始的。1995年,Freund和Schapire提出了Adaboost算法,是对Boosting算法的一大提升。Adaboost是Boosting家族的代表算法之一,全称为Adaptive Boosting。Adaptively,即适应地,该方法根据弱学习的结果反馈适应地调整假设的错误率,所以Adaboost不需要预先知道假设的错误率下限。也正因为如此,它不需要任何关于弱学习器性能的先验知识,而且和Boosting算法具有同样的效率,所以在提出之后得到了广泛的应用。
四、Cascade
级联分类器介绍:级联分类器就是将多个强分类器连接在一起进行操作。每一个强分类器都由若干个弱分类器加权组成,例如,有些强分类器可能包含10个弱分类器,有些则包含20个弱分类器,一般情况下一个级联用的强分类器包含20个左右的弱分类器,然后在将10个强分类器级联起来,就构成了一个级联强分类器,这个级联强分类器中总共包括200若分类器。因为每一个强分类器对负样本的判别准确度非常高,所以一旦发现检测到的目标位负样本,就不在继续调用下面的强分类器,减少了很多的检测时间。因为一幅图像中待检测的区域很多都是负样本,这样由级联分类器在分类器的初期就抛弃了很多负样本的复杂检测,所以级联分类器的速度是非常快的;只有正样本才会送到下一个强分类器进行再次检验,这样就保证了最后输出的正样本的伪正(false positive)的可能性非常低。
也有一些情况下不适用级联分类器,就简单的使用一个强分类器的情况,这种情况下一般强分类器都包含200个左右的弱分类器可以达到最佳效果。不过级联分类器的效果和单独的一个强分类器差不多,但是速度上却有很大的提升。
级联结构分类器由多个弱分类器组成,每一级都比前一级复杂。每个分类器可以让几乎所有的正例通过,同时滤除大部分负例。这样每一级的待检测正例就比前一级少,排除了大量的非检测目标,可大大提高检测速度。
五、opencv编程
1、vec和info数据格式
2、创建样本(opencv_createsamples)
-info 输入正样本描述文件,默认NULL
-img 输入图像文件名,默认NULL
-bg 负样本描述文件,文件中包含一系列的被随机选作物体背景的图像文件名,默认NULL
-num 生成正样本的数目,默认1000
-bgcolor 背景颜色,表示透明颜色,默认0
-bgthresh 颜色容差,所有处于bgcolor-bgthresh和bgcolor+bgthresh之间的像素被置为透明像素,也就是将白噪声加到前景图像上,默认80
-inv 前景图像颜色翻转标志,如果指定颜色翻转,默认0(不翻转)
-randinv 如果指定颜色将随机翻转,默认0
-maxidev 前景图像中像素的亮度梯度最大值,默认40
-maxxangle X轴最大旋转角度,以弧度为单位,默认1.1
-maxyangle Y轴最大旋转角度,以弧度为单位,默认1.1
-maxzangle Z轴最大旋转角度,以弧度为单位,默认0.5
输入图像沿着三个轴进行旋转,旋转角度由上述3个值限定。
-show 如果指定,每个样本都将被显示,按下Esc键,程序将继续创建样本而不在显示,默认为0(不显示)
-scale 显示图像的缩放比例,默认4.0
-w 输出样本宽度,默认24
-h 输出样本高度,默认24
-vec 输出用于训练的.vec文件,默认NULL
(1)如果设置-img和-vec
调用cvCreateTrainingSamples,采用一张图像创建训练样本
(2)如果设置-img、-bg和-info
调用cvCreateTestSamples,采用一张图像创建测试样本。-bg在这里又有什么作用?目的是作为背景创建测试图像。
(3)如果设置-info和-vec(采用正样本描述文件中的图像创建训练样本)
调用cvCreateTrainingSamplesFromInfo,在cvCreateTrainingSamplesFromInfo中将读取样本,并resize后调用icvWriteVecHeader和icvWriteVecSample创建vec文件。
(4)如果只设置-vec(只显示vec文件中的样本)
调用cvShowVecSamples查看和检查保存在vec文件中正样本
3、训练(opencv_traincascade)
使用train.dat调用%Opencv%\vs2008\bin\Release\ opencv_traincascade.exe
在traincascade.cpp中查阅参数设置
1基本参数
-data 目录名,存放训练好的分类器,如果不存在训练程序自行创建
-vec 正样本.vec文件,由opencv_createsamples生成
-bg 负样本描述文件
-numPos 每级分类器训练时所用到的正样本数目
-numNeg 每级分类器训练时所用到的负样本数目,可以大于-bg指定的图片数目
-numStages 训练分类器的级数
-precalcValBufSize 缓存大小,用于存储预先计算的特征值,单位MB
-precalcIdxBufSize 缓存大小,用于存储预先计算的特征索引,单位M币
-baseFormatSave 仅在使用Haar特征时有效,如果指定,级联分类器将以老格式存储
2级联参数cascadeParams
-stageType 级联类型,staticconst char* stageTypes[] = { CC_BOOST };
-featureType 特征类型,staticconst char* featureTypes[] = { CC_HAAR, CC_LBP, CC_HOG };
-w
-h 训练样本的尺寸,必须跟使用opencv_createsamples创建的训练样本尺寸保持一致
3Boosted分类器参数stageParams
-bt Boosted分类器类型
DAB-discrete Adaboost, RAB-RealAdaboost, LB-LogiBoost, GAB-Gentle Adaboost
-minHitRate 分类器的每一级希望得到的最小检测率,总的最大检测率大约为
min_hit_rate^number_of_stages
-maxFalseAlarmRate 分类器的每一级希望得到的最大误检率,总的误检率大约为
max_false_rate^number_of_stages
-weightTrimRate Specifies whether trimming should beused and its weight. 一个还不错的数值是0.95
-maxDepth 弱分类器的最大深度,一个不错数值是1,二叉树
-maxWeightCount 每一级中弱分类器的最大数目
4Haar特征参数featureParams
-mode 训练过程使用的Haar特征类型,CORE-Allupright ALL-All Features BASIC-Viola
上述参数设置好后调用CvCascadeClassifier::train进行训练
将上述内容在train.dat中编辑好,运行即可。训练最终生成一个-data指定级联分类器的文件夹和一个cascade.xml文件,其余文件都是中间结果,当训练程序被中断之后,再重新运行训练程序将读入之前的训练结果,无需从头重新训练,训练结束后可以删除这些文件。
在cascade.xml文件中主要有stageType,featureType,width,height,stageParams,featureParams,stageNum,stages和features节点。
stages中的stage数目是自己设定的,每个stage又包含多个weakClassifiers,每个weakClassifier又包含一个internalNodes和一个leafValues。internalNodes中四个变量代表一个node,分别为node中的left/right标记,特征池中的ID和threshold。leafValues中两个变量代表一个node,分别为leftleaf和right leaf值。
features是分类器的特征池,每个Haar特征包含一个矩形rect和要提取的特征序号,每个Hog特征/LBP特征包含一个矩形。
1 包含负样本的图像一定不小于在create中设置的尺寸
负样本图像可以是不同的尺寸,但是图像尺寸应该比训练窗口的尺寸大,在使用负样本图像时,OpenCV自动从负样本图像中抠出一块和正样本同样大小的区域作为负样本。具体可查阅icvGetNextFromBackgroundData,具体抠图过程为:
1) 确定抠图区域的左上角坐标(Point.x, Point.y)
2) 确定一个最小缩放比例,使得原负样本图像缩放后恰好包含选中负样本区域
3) 对原负样本图象按计算好的缩放比例进行缩放
4) 在缩放后的图像上抠出负样本。
2 –numPos一般比实际正样本数量少200-300,-numNeg是否存在同样的情况?正负样本选择规则?
如果出现:训练停留在一个分类器长达几小时没有相应,问题出现在取负样本的那个函数 icvGetHaarTrainingDataFromBG中;只有当之前的强分类器对负样本集内的样本全部分类正确时才会出现死循环,因为只要有一个样本会被错分为正样本,那么通过count次扫描整个负样本集就能得到count个负样本,当然这count个负样本实际上就是一个负样本的count个拷贝。为避免这种情况,负样本集中的样本数需要足够多 。
不过此时的分类器已经完全额、可以使用,因为它的误检率已经很低,从实用性上时没有任何问题的。所以我们可以通过设置-nstages 这个参数来限制分类器级数,适当时候停止并生成xml文件。
从CvCascadeBoost::train中去查阅
函数 poscount= icvGetHaarTrainingDataFromVec( training_data, 0, npos,
(CvIntHaarClassifier*)tcc, vecfilename, &consumed )负责从正样本集*.vec 文件中载入 count(npos)个正样本。在程序第一次运行到此(即训练第一个分类器之前)时,只要正样本集中有 count 个样本,就一定能取出 count 个正样本。在以后运行到此时,有可能取不到 count 个样本,因为
必须是用前面的级联强分类器((CvIntHaarClassifier*) tcc)分类为正样本(即分类正确的样本)的样本才会被取出作为下一个强分类器训练样本,具体可参考 icvGetHaarTrainingData和icvEvalTreeCascadeClassifierFilter函数。
训练负样本,具体可参考icvGetHaarTrainingDataFromBG和icvEvalTreeCascadeClassifierFilter函数。
int icvGetHaarTrainingDataFromBG(CvHaarTrainingData* data, int first, int count,
CvIntHaarClassifier*cascade, double* acceptance_ratio, const char * filename = NULL )
传递返回值的 acceptance_ratio 参数记录的是实际取出的负样本数与查询过的负样本数(如果通过前面级联stage强分类器的负样本数很少时,那么程序会循环重复读取负样本,并用thread_consumed_count计数)之比(acceptance_ratio = ((double) count) / consumed_count),也就是虚警率,用于判断已训练的级联分类器是否达到指标,若达到指标,则停止训练过程。
注意函数 icvGetHaarTrainingData中一个主要的 For 循环:
for( i = first; i < first +count; i++ ) //共读取 count 个负样本,当读取不到
{ //这么多负样本时将出现死循环!
对上面代码中的注释有必要进一步说明一下:只有当之前的强分类器对负样本集内的样本全部分类正确时才会出现死循环。因为只要有一个样本会被错分为正样本,那么通过 count次扫描整个负样本集就能得到 count 个负样本,当然这 count 个负样本实际上就是一个负样本的 count 个拷贝。为避免这些情况的发生,负样本集中的样本数需要足够多。
在负样本图像大小与正样本大小完全一致时,假设最终的分类器虚警率要求是falsealarm,参加训练的负样本要求是 count 个,则需要的负样本总数可计算如下: TotalCount = count / falsealarm
以 Rainer Lienhart 的文章中的一些参数为例,falsealarm=0.5^20=9.6e-07, count=3000,
则 TotalCount=3000/(0.5^20)= 3,145,728,000=31 亿。
函数 icvGetHaarTrainingDataFromBG ()负责从负样本集中载入 count 个负样本。在程序第一次运行到此(即训练第一个分类器之前)时,只要负样本集中有 count 个样本,就一定能取出 count 个负样本。在以后运行到此时,有可能取不到 count 个样本,因为必须是用前面的级联强分类器分类为正样本的样本(即分类错误的样本)才会被取出作为下一个强分类器的负样本输入。
对于int icvGetHaarTrainingData( CvHaarTrainingData* data,int first, int count,
CvIntHaarClassifier*cascade,
CvGetHaarTrainingDataCallbackcallback, void* userdata,
int*consumed, double* acceptance_ratio )
这个函数的解释:
这是个对于读取正负样本通用的函数,区别在于callback的调用。在这个函数中有个变量thread_getcount,表示将样本分为正样本的数目(不论这个样本是负样本还是正样本)。
传递返回值的 Consumed 参数表示为取 count 个正样本,查询过的正样本总数。对于负样本为空(null),没有返回值。
3 之前遇到过10*20的不能训练Hog特征的分类器?Hog特征是否存在尺寸限制?
查阅Hog特征的计算方法,Opencv中HogDescriptor
这篇关于2001 Rapid object detection using a boosted cascade of simple features(Paul Viola et al)读后感的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!