在看了文档[2,3]后开始对照着看OpenCV代码,看得晕头转向啊。又搜了网上的一些帖子,先针对自己的理解做笔记如下,日后好在此基础上补充。
OpenCV人脸检测之数据结构:
所有的结构都代表一个级联boosted Haar分类器。级联有下面的等级结构:
Cascade:
Stage1:
Classifier11:
Feature11
Classifier12:
Feature12
...
Stage2:
Classifier21:
Feature21
...
...
关于特征
![](https://img-my.csdn.net/uploads/201209/28/1348826838_8045.jpg)
typedef struct CvTHaarFeature//Haar-like 特征
{
char desc[CV_HAAR_FEATURE_DESC_MAX];// haar_x3等描述feature的形状
int tilted;//0->up-rightfeature, 1->45 rotated feature 见上图。
struct
{
CvRect r;
float weight;
} rect[CV_HAAR_FEATURE_MAX];//一个feature由2-3个长方形组成
} CvTHaarFeature;
typedef struct CvFastHaarFeature
{
int tilted; //0->up-right feature, 1->45rotated feature 见上图。
struct
{
int p0, p1, p2, p3;//把上面的Feature中的r的四个角点位置按照图像左上角开始算起第几个(offset)。这样方便后面等积分图算出来后直接把p0,p1,p2,p3当做下标来取积分数值即可。
float weight;
} rect[CV_HAAR_FEATURE_MAX];
} CvFastHaarFeature;
typedef struct CvIntHaarFeatures
{
CvSize winsize;
int count;
CvTHaarFeature* feature;
CvFastHaarFeature* fastfeature;
} CvIntHaarFeatures;
/* Prepared for training samples */
typedef struct CvHaarTrainingData
{
CvSize winsize; /* training image size */
int maxnum; /* maximumnumber of samples *///(2000+2000)
CvMat sum; /* sumimages (each row represents image) *///(2000+2000) x (20x20)
CvMat tilted; /* tilted sumimages (each row represents image) *///(2000+2000) x (20x20)
CvMat normfactor; /* normalizationfactor */
CvMat cls; /* classes.1.0 - object, 0.0 - background */// 1 x (2000+2000)
CvMat weights; /* weights *///1 x (2000+2000)Adaboost训练的时候需要的样本权值
CvMat* valcache; /* precalculated feature values (CV_32FC1) */
CvMat* idxcache; /* presorted indices (CV_IDX_MAT_TYPE) */
} CvHaarTrainigData;
typedef struct CvUserdata
{
CvHaarTrainingData* trainingData;
CvIntHaarFeatures* haarFeatures;
} CvUserdata;
以上描述的结构体可总结如下[1].
关于分类器
typedef struct CvCARTHaarClassifier//基于Haar-like特征的弱分类器
{
CV_INT_HAAR_CLASSIFIER_FIELDS()
int count;//这个弱分类器需要的Haar-like特征数目,如果上传调用时nsplits为1这个count值即为1,也就是说一般理解的弱分类器。
int* compidx;//选择出的这个弱分类器的Haar-like特征的序号
CvTHaarFeature* feature; //选择出的这个弱分类器的Haar-like特征
CvFastHaarFeature* fastfeature; //选择出的这个弱分类器的Haar-like特征
float* threshold; //选择出的这个弱分类器的Haar-like特征的threshold
int* left;//跟CART树有关,应该是Node的序号
int* right; //跟CART树有关,应该是Node的序号
float* val;//跟上面的threshold比较后的output值,其实是code里面的Curleft和curright
} CvCARTHaarClassifier;
typedef struct CvStageHaarClassifier//基于Haar-like特征的强分类器
{
CV_INT_HAAR_CLASSIFIER_FIELDS()
int count;
float threshold;//强分类器的threshold,大于此值的output为1,小于此值的output为0
CvIntHaarClassifier** classifier;//被转化为弱分类器CvCARTHaarClassifier,
} CvStageHaarClassifier;
typedef struct CvCascadeHaarClassifier//基于Haar-like特征的级联强分类器
{
CV_INT_HAAR_CLASSIFIER_FIELDS()
int count;
CvIntHaarClassifier** classifier; //被转化为强分类器CvStageHaarClassifier
} CvCascadeHaarClassifier;
/* internal weak classifier*/
typedef struct CvIntHaarClassifier
{//感觉像是c++里的抽象类的意思
CV_INT_HAAR_CLASSIFIER_FIELDS()
} CvIntHaarClassifier;
那么这里为什么要使用一个如此复杂的结构呢。大体来说有两个好处:
1、 方便弱分类器之间的切换,当我们不选用CART而是其他的弱分类器结构的时候,就可以调用CvIntHaarClassifier时转换成其他的指针
2、 这样方便了Haar训练的过程和Boost过程的衔接。
训练部分的接口及流程图
OpenCV 有cvCreateTreeCascadeClassifier和cvCreateCascadeClassifier两种级联分类器,目前先讨论后者。
创建Cascade分类器:
void cvCreateCascadeClassifier(
const char* dirname,//工作目录
const char* vecfilename,//正样本的描述文件,其中包含正样本的数目,宽高,以及所有样本图像数据
const char* bgfilename,//负样本的描述文件,只包含负样本的路径
int npos, //用于训练的正样本的数目
int nneg, //用于训练的负样本的数目
int nstages,//训练多少层
int numprecalculated, //MB
int numsplits, //在一个弱分类器中用的feature数目,1->stump classifier; 2或更多 -> CARTclassifier
float minhitrate, //每一个stage在训练的时候需要达到的最低hit rate
float maxfalsealarm,//每一个stage在训练的时候允许达到的最高的false alarm rate
float weightfraction,//boosting算法的一个参数
int mode, //BASIC-> only uprightfeatures; ALL->full set of upright and 45度features;
int symmetric,//对称的话可以加快训练进程
int equalweights,//enable equal weightsfor positives and negatives.
int winwidth, //width of training images
int winheight, //height of training images
int boosttype, //DAB->Discrete Ada Boost;RAB->Real Ada Boost; LB->Logic Boost; GAB->Gentle Adaboost
int stumperror,//跟DAB有关的一个参数
)
创建Gentle Adaboost强分类器:
创建弱分类器:(以stump为例)
下图不是我做的,是[1]里的,openCV里的代码顺序跟这个稍有出入,但是基本一致。
Curleft和curright 即为跟threshold比较后的output
Reference
1. http://wenku.baidu.com/view/87fccf09581b6bd97f19ea12.html
2. "Empirical Analysis of Detection Cascades of Boosted Classifiers for Rapid Object Detection" , Rainer Lienhart, Alexander Kuranov, Vadim Pisarevsky,2002
3. “Rapid Object Detection using a Boosted Cascade of Simple Features”, Paul Viola, Michael Jones, 2001