//头文件为softcascade.hpp、core.hpp
//实现文件为octave.cpp
//但是还涉及到了ml.hpp和Dtree.cpp等文件
//softcascade检测器训练函数的代码如下:
bool BoostedSoftCascadeOctave::train(const Dataset* dataset, const FeaturePool* pool, int weaks, int treeDepth)
{//第1个参数dataset是一个可以与训练集通信的实例,第2个参数表示特征集,第3个参数是需要训练的弱分类器树数量,第4个参数是分类器树的深度
CV_Assert(treeDepth == 2); //?要求弱分类树的深度只能为2吗?
CV_Assert(weaks > 0);
params.max_depth = treeDepth;
params.weak_count = weaks;
// 1. fill integrals and classes,?这里计算了每个样本的所有积分图和标定了标签吗?是的,对于正样本,response向量中响应的元素值设置为了1,负样本设置为了0
processPositives(dataset);
generateNegatives(dataset);
// 2. only simple case (all features used) //使用所有的特征
int nfeatures = pool->size();
cv::Mat varIdx(1, nfeatures, CV_32SC1);
int* ptr = varIdx.ptr<int>(0);
for (int x = 0; x < nfeatures; ++x)
ptr[x] = x;
// 3. only simple case (all samples used) //使用所有训练样本
int nsamples = npositives + nnegatives;
cv::Mat sampleIdx(1, nsamples, CV_32SC1);
ptr = sampleIdx.ptr<int>(0);
for (int x = 0; x < nsamples; ++x)
ptr[x] = x;
// 4. ICF has an ordered response.
cv::Mat varType(1, nfeatures + 1, CV_8UC1); //指定按特征响应排序?最后多的一个元素表示什么意思?是不是表示将要输入训练函数train()(在倒数第3行)中的response向量保存的是类标签
uchar* uptr = varType.ptr<uchar>(0);
for (int x = 0; x < nfeatures; ++x)
uptr[x] = CV_VAR_ORDERED; //这个排序无法理解!
uptr[nfeatures] = CV_VAR_CATEGORICAL;
trainData.create(nfeatures, nsamples, CV_32FC1); //生成用来训练用的数据矩阵,看下面的双重循环就知道,其中每行对应到一个特征,每列对应到一个样本,该矩阵每个元素保存的是某样本某特征的积分图。
for (int fi = 0; fi < nfeatures; ++fi)
{
float* dptr = trainData.ptr<float>(fi);
for (int si = 0; si < nsamples; ++si)
{
dptr[si] = pool->apply(fi, si, integrals);
}
}
cv::Mat missingMask;
bool ok = train(trainData, responses, varIdx, sampleIdx, varType, missingMask); //?主要的训练函数,trainData是用特征表示的训练集矩阵,responses是样本对应的类标签,varIdx是所学习的特征的所有索引,sampleIdx是训练样本的索引,?varType表示是否对特征响应排序?,missingMask用来保存错误的分类。
if (!ok)
CV_Error(CV_StsInternal, "ERROR: tree can not be trained");
return ok;
}
//其中用到的训练函数如下,可见它调用了boost类的train()函数,并且推测得到的检测器保存在params中。
//它调用了CvBoostTree::train()函数来,并加入了params参数,看来在BoostedSoftCascadeOctave类中没有params成员,但是最终的检测器时保存在该成员中的,到现在为止还是训练整个的检测器:
bool BoostedSoftCascadeOctave::train( const cv::Mat& _trainData, const cv::Mat& _responses, const cv::Mat& varIdx,
const cv::Mat& sampleIdx, const cv::Mat& varType, const cv::Mat& missingDataMask)
{
bool update = false;
return cv::Boost::train(_trainData, CV_COL_SAMPLE, _responses, varIdx, sampleIdx, varType, missingDataMask, params,
update);
}
//boost类的train()函数定义如下(在boost.cpp中):
bool
CvBoost::train( const CvMat* _train_data, int _tflag,
const CvMat* _responses, const CvMat* _var_idx,
const CvMat* _sample_idx, const CvMat* _var_type,
const CvMat* _missing_mask,
CvBoostParams _params, bool _update )
{//顺着来,到了这里,_train_data是训练数据,每行对应到一个特征每列对应到一个样本;_tflag表明了训练数据矩阵的每列对应到一个样本;
//_responsens是各样本对应的类标签;_var_idx是特征索引(序号),_sample_idx是样本索引,_var_type在这里表示按特征响应排序;_missing_mask不知何意;
//_params保存训练得到的检测器;_update为false。这里使用CvBoost.tree->train()函数训练每一个弱分类器
//
bool ok = false;
CvMemStorage* storage = 0;
CV_FUNCNAME( "CvBoost::train" );
__BEGIN__;
int i;
set_params( _params );//初始化检测器参数
cvReleaseMat( &active_vars );
cvReleaseMat( &active_vars_abs );