#include "boost.h"
#include "cascadeclassifier.h"
#include <queue>
+
using namespace std;
static inline double
CvCascadeBoostParams::CvCascadeBoostParams() : minHitRate( 0.995F), maxFalseAlarm( 0.5F )
{
- boost_type = CvBoost::GENTLE;
+ boost_type = CvBoost::GENTLE;
+ use_surrogates = use_1se_rule = truncate_pruned_tree = false;
}
CvCascadeBoostParams::CvCascadeBoostParams( int _boostType,
boost_type = CvBoost::GENTLE;
minHitRate = _minHitRate;
maxFalseAlarm = _maxFalseAlarm;
+ use_surrogates = use_1se_rule = truncate_pruned_tree = false;
}
void CvCascadeBoostParams::write( FileStorage &fs ) const
CvCascadeBoostTrainData::CvCascadeBoostTrainData( const CvFeatureEvaluator* _featureEvaluator,
int _numSamples,
- int _numPrecalcVal, int _numPrecalcIdx,
+ int _precalcValBufSize, int _precalcIdxBufSize,
const CvDTreeParams& _params )
{
- setData( _featureEvaluator, _numSamples, _numPrecalcVal, _numPrecalcIdx, _params );
+ setData( _featureEvaluator, _numSamples, _precalcValBufSize, _precalcIdxBufSize, _params );
}
void CvCascadeBoostTrainData::setData( const CvFeatureEvaluator* _featureEvaluator,
int _numSamples,
- int _numPrecalcVal, int _numPrecalcIdx,
+ int _precalcValBufSize, int _precalcIdxBufSize,
const CvDTreeParams& _params )
{
int* idst = 0;
responses = &_resp;
// TODO: check responses: elements must be 0 or 1
- if( _numPrecalcVal < 0 || _numPrecalcIdx < 0)
+ if( _precalcValBufSize < 0 || _precalcIdxBufSize < 0)
CV_Error( CV_StsOutOfRange, "_numPrecalcVal and _numPrecalcIdx must be positive or 0" );
var_count = var_all = featureEvaluator->getNumFeatures();
sample_count = _numSamples;
- numPrecalcVal = min( _numPrecalcVal, var_count );
- numPrecalcIdx = min( _numPrecalcIdx, var_count );
is_buf_16u = false;
if (sample_count < 65536)
- is_buf_16u = true;
+ is_buf_16u = true;
+
+ numPrecalcVal = min( (_precalcValBufSize*1048576) / int(sizeof(float)*sample_count), var_count );
+ numPrecalcIdx = min( (_precalcIdxBufSize*1048576) /
+ int((is_buf_16u ? sizeof(unsigned short) : sizeof (int))*sample_count), var_count );
- valCache.create( numPrecalcVal ? numPrecalcVal : 1, sample_count, CV_32FC1 );
+ valCache.create( numPrecalcVal, sample_count, CV_32FC1 );
var_type = cvCreateMat( 1, var_count + 2, CV_32SC1 );
if ( featureEvaluator->getMaxCatCount() > 0 )
}
var_type->data.i[var_count] = cat_var_count;
var_type->data.i[var_count+1] = cat_var_count+1;
- work_var_count = ( cat_var_count ? var_count : numPrecalcIdx ) + 1;
+ work_var_count = ( cat_var_count ? 0 : numPrecalcIdx ) + 1;
buf_size = (work_var_count + 1) * sample_count;
buf_count = 2;
buf = cvCreateMat( buf_count, buf_size, CV_32SC1 );
cat_count = cvCreateMat( 1, cat_var_count + 1, CV_32SC1 );
- pred_float_buf = (float*)cvAlloc(sample_count*sizeof(pred_float_buf[0]));
- pred_int_buf = (int*)cvAlloc(sample_count*sizeof(pred_int_buf[0]));
- resp_float_buf = (float*)cvAlloc(sample_count*sizeof(resp_float_buf[0]));
- resp_int_buf = (int*)cvAlloc(sample_count*sizeof(resp_int_buf[0]));
- cv_lables_buf = (int*)cvAlloc(sample_count*sizeof(cv_lables_buf[0]));
- sample_idx_buf = (int*)cvAlloc(sample_count*sizeof(sample_idx_buf[0]));
// precalculate valCache and set indices in buf
precalculate();
valCache.release();
}
-void CvCascadeBoostTrainData::get_class_labels( CvDTreeNode* n, int* labelsBuf, const int** labels )
+const int* CvCascadeBoostTrainData::get_class_labels( CvDTreeNode* n, int* labelsBuf)
{
int nodeSampleCount = n->sample_count;
- int* sampleIndicesBuf = sample_idx_buf;
- const int* sampleIndices = 0;
int rStep = CV_IS_MAT_CONT( responses->type ) ? 1 : responses->step / CV_ELEM_SIZE( responses->type );
- get_sample_indices(n, sampleIndicesBuf, &sampleIndices);
-
+ int* sampleIndicesBuf = labelsBuf; //
+ const int* sampleIndices = get_sample_indices(n, sampleIndicesBuf);
for( int si = 0; si < nodeSampleCount; si++ )
{
int sidx = sampleIndices[si];
labelsBuf[si] = (int)responses->data.fl[sidx*rStep];
}
- *labels = labelsBuf;
+ return labelsBuf;
}
-void CvCascadeBoostTrainData::get_sample_indices( CvDTreeNode* n, int* indicesBuf, const int** indices )
+const int* CvCascadeBoostTrainData::get_sample_indices( CvDTreeNode* n, int* indicesBuf )
{
- CvDTreeTrainData::get_cat_var_data( n, get_work_var_count(), indicesBuf, indices );
+ return CvDTreeTrainData::get_cat_var_data( n, get_work_var_count(), indicesBuf );
}
-void CvCascadeBoostTrainData::get_cv_labels( CvDTreeNode* n, int* labels_buf, const int** labels )
+const int* CvCascadeBoostTrainData::get_cv_labels( CvDTreeNode* n, int* labels_buf )
{
- CvDTreeTrainData::get_cat_var_data( n, get_work_var_count()- 1, labels_buf, labels );
+ return CvDTreeTrainData::get_cat_var_data( n, get_work_var_count() - 1, labels_buf );
}
-int CvCascadeBoostTrainData::get_ord_var_data( CvDTreeNode* n, int vi, float* ordValuesBuf, int* indicesBuf,
- const float** ordValues, const int** indices )
+void CvCascadeBoostTrainData::get_ord_var_data( CvDTreeNode* n, int vi, float* ordValuesBuf, int* sortedIndicesBuf,
+ const float** ordValues, const int** sortedIndices, int* sampleIndicesBuf )
{
int nodeSampleCount = n->sample_count;
- int* sampleIndicesBuf = sample_idx_buf;
- const int* sampleIndices = 0;
- get_sample_indices(n, sampleIndicesBuf, &sampleIndices);
+ const int* sampleIndices = get_sample_indices(n, sampleIndicesBuf);
if ( vi < numPrecalcIdx )
{
if( !is_buf_16u )
- *indices = buf->data.i + n->buf_idx*buf->cols + vi*sample_count + n->offset;
+ *sortedIndices = buf->data.i + n->buf_idx*buf->cols + vi*sample_count + n->offset;
else
{
const unsigned short* shortIndices = (const unsigned short*)(buf->data.s + n->buf_idx*buf->cols +
vi*sample_count + n->offset );
for( int i = 0; i < nodeSampleCount; i++ )
- indicesBuf[i] = shortIndices[i];
- *indices = indicesBuf;
+ sortedIndicesBuf[i] = shortIndices[i];
+ *sortedIndices = sortedIndicesBuf;
}
if ( vi < numPrecalcVal )
{
for( int i = 0; i < nodeSampleCount; i++ )
{
- int idx = (*indices)[i];
+ int idx = (*sortedIndices)[i];
idx = sampleIndices[idx];
ordValuesBuf[i] = valCache.at<float>( vi, idx);
}
{
for( int i = 0; i < nodeSampleCount; i++ )
{
- int idx = (*indices)[i];
+ int idx = (*sortedIndices)[i];
idx = sampleIndices[idx];
ordValuesBuf[i] = (*featureEvaluator)( vi, idx);
}
{
for( int i = 0; i < nodeSampleCount; i++ )
{
- indicesBuf[i] = i;
+ sortedIndicesBuf[i] = i;
((float*)sampleIndices)[i] = valCache.at<float>( vi, sampleIndices[i] );
}
}
else
{
- for( int i = 0; i < nodeSampleCount; i++ )
+ for( int i = 0; i < nodeSampleCount; i++ )
{
- indicesBuf[i] = i;
+ sortedIndicesBuf[i] = i;
((float*)sampleIndices)[i] = (*featureEvaluator)( vi, sampleIndices[i]);
}
}
- icvSortIntAux( indicesBuf, sample_count, (float *)sampleIndices );
+ icvSortIntAux( sortedIndicesBuf, sample_count, (float *)sampleIndices );
for( int i = 0; i < nodeSampleCount; i++ )
- ordValuesBuf[i] = ((float*)sampleIndices)[indicesBuf[i]];
- *indices = indicesBuf;
+ ordValuesBuf[i] = ((float*)sampleIndices)[sortedIndicesBuf[i]];
+ *sortedIndices = sortedIndicesBuf;
}
*ordValues = ordValuesBuf;
- return 0;
}
-int CvCascadeBoostTrainData::get_cat_var_data( CvDTreeNode* n, int vi, int* catValuesBuf, const int** catValues )
+const int* CvCascadeBoostTrainData::get_cat_var_data( CvDTreeNode* n, int vi, int* catValuesBuf)
{
int nodeSampleCount = n->sample_count;
- int* sampleIndicesBuf = sample_idx_buf;
- const int* sampleIndices = 0;
- get_sample_indices(n, sampleIndicesBuf, &sampleIndices);
+ int* sampleIndicesBuf = catValuesBuf; //
+ const int* sampleIndices = get_sample_indices(n, sampleIndicesBuf);
if ( vi < numPrecalcVal )
{
for( int i = 0; i < nodeSampleCount; i++ )
catValuesBuf[i] = (int)(*featureEvaluator)( vi, sampleIndices[i] );
}
- *catValues = catValuesBuf;
-
- return 0;
+ return catValuesBuf;
}
float CvCascadeBoostTrainData::getVarValue( int vi, int si )
return (*featureEvaluator)( vi, si );
}
-void CvCascadeBoostTrainData::precalculate()
+
+struct FeatureIdxOnlyPrecalc
{
- int minNum = MIN( numPrecalcVal, numPrecalcIdx);
- unsigned short* udst = (unsigned short*)buf->data.s;
- int* idst = buf->data.i;
-
- CV_DbgAssert( !valCache.empty() );
- double proctime = -TIME( 0 );
-
- for ( int fi = numPrecalcVal; fi < numPrecalcIdx; fi++)
+ FeatureIdxOnlyPrecalc( const CvFeatureEvaluator* _feval, CvMat* _buf, int _sample_count, bool _is_buf_16u )
+ {
+ feval = _feval;
+ sample_count = _sample_count;
+ udst = (unsigned short*)_buf->data.s;
+ idst = _buf->data.i;
+ is_buf_16u = _is_buf_16u;
+ }
+ void operator()( const BlockedRange& range ) const
{
- for( int si = 0; si < sample_count; si++ )
+ cv::AutoBuffer<float> valCache(sample_count);
+ float* valCachePtr = (float*)valCache;
+ for ( int fi = range.begin(); fi < range.end(); fi++)
{
- valCache.ptr<float>(0)[si] = (*featureEvaluator)( fi, si );
+ for( int si = 0; si < sample_count; si++ )
+ {
+ valCachePtr[si] = (*feval)( fi, si );
+ if ( is_buf_16u )
+ *(udst + fi*sample_count + si) = (unsigned short)si;
+ else
+ *(idst + fi*sample_count + si) = si;
+ }
if ( is_buf_16u )
- *(udst + fi*sample_count + si) = (unsigned short)si;
+ icvSortUShAux( udst + fi*sample_count, sample_count, valCachePtr );
else
- *(idst + fi*sample_count + si) = si;
+ icvSortIntAux( idst + fi*sample_count, sample_count, valCachePtr );
}
- if ( is_buf_16u )
- icvSortUShAux( udst + fi*sample_count, sample_count, (float*)valCache.data );
- else
- icvSortIntAux( idst + fi*sample_count, sample_count, (float*)valCache.data );
}
-
- for ( int fi = 0; fi < minNum; fi++)
+ const CvFeatureEvaluator* feval;
+ int sample_count;
+ int* idst;
+ unsigned short* udst;
+ bool is_buf_16u;
+};
+
+struct FeatureValAndIdxPrecalc
+{
+ FeatureValAndIdxPrecalc( const CvFeatureEvaluator* _feval, CvMat* _buf, Mat* _valCache, int _sample_count, bool _is_buf_16u )
+ {
+ feval = _feval;
+ valCache = _valCache;
+ sample_count = _sample_count;
+ udst = (unsigned short*)_buf->data.s;
+ idst = _buf->data.i;
+ is_buf_16u = _is_buf_16u;
+ }
+ void operator()( const BlockedRange& range ) const
{
- for( int si = 0; si < sample_count; si++ )
+ for ( int fi = range.begin(); fi < range.end(); fi++)
{
- valCache.ptr<float>(fi)[si] = (*featureEvaluator)( fi, si );
+ for( int si = 0; si < sample_count; si++ )
+ {
+ valCache->at<float>(fi,si) = (*feval)( fi, si );
+ if ( is_buf_16u )
+ *(udst + fi*sample_count + si) = (unsigned short)si;
+ else
+ *(idst + fi*sample_count + si) = si;
+ }
if ( is_buf_16u )
- *(udst + fi*sample_count + si) = (unsigned short)si;
+ icvSortUShAux( udst + fi*sample_count, sample_count, valCache->ptr<float>(fi) );
else
- *(idst + fi*sample_count + si) = si;
+ icvSortIntAux( idst + fi*sample_count, sample_count, valCache->ptr<float>(fi) );
}
- if ( is_buf_16u )
- icvSortUShAux( udst + fi*sample_count, sample_count, (float*)valCache.data );
- else
- icvSortIntAux( idst + fi*sample_count, sample_count, (float*)valCache.data );
}
+ const CvFeatureEvaluator* feval;
+ Mat* valCache;
+ int sample_count;
+ int* idst;
+ unsigned short* udst;
+ bool is_buf_16u;
+};
+
+struct FeatureValOnlyPrecalc
+{
+ FeatureValOnlyPrecalc( const CvFeatureEvaluator* _feval, Mat* _valCache, int _sample_count )
+ {
+ feval = _feval;
+ valCache = _valCache;
+ sample_count = _sample_count;
+ }
+ void operator()( const BlockedRange& range ) const
+ {
+ for ( int fi = range.begin(); fi < range.end(); fi++)
+ for( int si = 0; si < sample_count; si++ )
+ valCache->at<float>(fi,si) = (*feval)( fi, si );
+ }
+ const CvFeatureEvaluator* feval;
+ Mat* valCache;
+ int sample_count;
+};
- for ( int fi = minNum; fi < numPrecalcVal; fi++)
- for( int si = 0; si < sample_count; si++ )
- valCache.ptr<float>(fi)[si] = (*featureEvaluator)( fi, si );
+void CvCascadeBoostTrainData::precalculate()
+{
+ int minNum = MIN( numPrecalcVal, numPrecalcIdx);
+ CV_DbgAssert( !valCache.empty() );
+ double proctime = -TIME( 0 );
+ parallel_for( BlockedRange(numPrecalcVal, numPrecalcIdx),
+ FeatureIdxOnlyPrecalc(featureEvaluator, buf, sample_count, is_buf_16u) );
+ parallel_for( BlockedRange(0, minNum),
+ FeatureValAndIdxPrecalc(featureEvaluator, buf, &valCache, sample_count, is_buf_16u) );
+ parallel_for( BlockedRange(minNum, numPrecalcVal),
+ FeatureValOnlyPrecalc(featureEvaluator, &valCache, sample_count) );
cout << "Precalculation time: " << (proctime + TIME( 0 )) << endl;
}
prntNode->split = data->new_split_cat( 0, 0 );
for( int j = subsetN-1; j>=0; j--)
{
- internalNodesIt >> prntNode->split->subset[j]; internalNodesIt -=2;
+ *internalNodesIt >> prntNode->split->subset[j]; internalNodesIt--;
}
}
else
{
float split_value;
- internalNodesIt >> split_value; internalNodesIt -=2;
+ *internalNodesIt >> split_value; internalNodesIt--;
prntNode->split = data->new_split_ord( 0, split_value, 0, 0, 0);
}
- internalNodesIt >> prntNode->split->var_idx; internalNodesIt -=2;
+ *internalNodesIt >> prntNode->split->var_idx; internalNodesIt--;
int ridx, lidx;
- internalNodesIt >> ridx; internalNodesIt -=2;
- internalNodesIt >> lidx;internalNodesIt -=2;
+ *internalNodesIt >> ridx; internalNodesIt--;
+ *internalNodesIt >> lidx;internalNodesIt--;
if ( ridx <= 0)
{
prntNode->right = cldNode = data->new_node( 0, 0, 0, 0 );
- leafValsuesIt >> cldNode->value; leafValsuesIt-=2;
+ *leafValsuesIt >> cldNode->value; leafValsuesIt--;
cldNode->parent = prntNode;
}
else
if ( lidx <= 0)
{
prntNode->left = cldNode = data->new_node( 0, 0, 0, 0 );
- leafValsuesIt >> cldNode->value; leafValsuesIt-=2;
+ *leafValsuesIt >> cldNode->value; leafValsuesIt--;
cldNode->parent = prntNode;
}
else
int newBufIdx = data->get_child_buf_idx( node );
int workVarCount = data->get_work_var_count();
CvMat* buf = data->buf;
- int* tempBuf = (int*)cvStackAlloc(n*sizeof(tempBuf[0]));
+ cv::AutoBuffer<uchar> inn_buf(n*(3*sizeof(int)+sizeof(float)));
+ int* tempBuf = (int*)(uchar*)inn_buf;
bool splitInputData;
complete_node_dir(node);
(node->left->sample_count > data->params.min_sample_count ||
node->right->sample_count > data->params.min_sample_count);
- // split ordered variables, keep both halves sorted.
+ // split ordered variables, keep both halves sorted.
for( int vi = 0; vi < ((CvCascadeBoostTrainData*)data)->numPrecalcIdx; vi++ )
{
int ci = data->get_var_type(vi);
- int n1 = node->get_num_valid(vi);
- int *src_idx_buf = data->pred_int_buf;
- const int* src_idx = 0;
- float *src_val_buf = data->pred_float_buf;
- const float* src_val = 0;
-
if( ci >= 0 || !splitInputData )
continue;
- data->get_ord_var_data(node, vi, src_val_buf, src_idx_buf, &src_val, &src_idx);
+ int n1 = node->get_num_valid(vi);
+ float *src_val_buf = (float*)(tempBuf + n);
+ int *src_sorted_idx_buf = (int*)(src_val_buf + n);
+ int *src_sample_idx_buf = src_sorted_idx_buf + n;
+ const int* src_sorted_idx = 0;
+ const float* src_val = 0;
+ data->get_ord_var_data(node, vi, src_val_buf, src_sorted_idx_buf, &src_val, &src_sorted_idx, src_sample_idx_buf);
for(int i = 0; i < n; i++)
- tempBuf[i] = src_idx[i];
+ tempBuf[i] = src_sorted_idx[i];
if (data->is_buf_16u)
{
}
// split cv_labels using newIdx relocation table
- int *src_lbls_buf = data->pred_int_buf;
- const int* src_lbls = 0;
- data->get_cv_labels(node, src_lbls_buf, &src_lbls);
+ int *src_lbls_buf = tempBuf + n;
+ const int* src_lbls = data->get_cv_labels(node, src_lbls_buf);
for(int i = 0; i < n; i++)
tempBuf[i] = src_lbls[i];
}
// split sample indices
- int *sampleIdx_src_buf = data->sample_idx_buf;
- const int* sampleIdx_src = 0;
- data->get_sample_indices(node, sampleIdx_src_buf, &sampleIdx_src);
+ int *sampleIdx_src_buf = tempBuf + n;
+ const int* sampleIdx_src = data->get_sample_indices(node, sampleIdx_src_buf);
for(int i = 0; i < n; i++)
tempBuf[i] = sampleIdx_src[i];
bool CvCascadeBoost::train( const CvFeatureEvaluator* _featureEvaluator,
int _numSamples,
- int _numPrecalcVal, int _numPrecalcIdx,
+ int _precalcValBufSize, int _precalcIdxBufSize,
const CvCascadeBoostParams& _params )
{
CV_Assert( !data );
clear();
data = new CvCascadeBoostTrainData( _featureEvaluator, _numSamples,
- _numPrecalcVal, _numPrecalcIdx, _params );
+ _precalcValBufSize, _precalcIdxBufSize, _params );
CvMemStorage *storage = cvCreateMemStorage();
weak = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvBoostTree*), storage );
storage = 0;
float* fdata = 0;
int *sampleIdxBuf;
const int* sampleIdx = 0;
+ int inn_buf_size = ((params.boost_type == LOGIT) || (params.boost_type == GENTLE) ? n*sizeof(int) : 0) +
+ ( !tree ? n*sizeof(int) : 0 );
+ cv::AutoBuffer<uchar> inn_buf(inn_buf_size);
+ uchar* cur_inn_buf_pos = (uchar*)inn_buf;
if ( (params.boost_type == LOGIT) || (params.boost_type == GENTLE) )
{
step = CV_IS_MAT_CONT(data->responses_copy->type) ?
1 : data->responses_copy->step / CV_ELEM_SIZE(data->responses_copy->type);
fdata = data->responses_copy->data.fl;
- sampleIdxBuf = (int*)cvStackAlloc(data->sample_count*sizeof(sampleIdxBuf[0]));
- data->get_sample_indices( data->data_root, sampleIdxBuf, &sampleIdx );
+ sampleIdxBuf = (int*)cur_inn_buf_pos; cur_inn_buf_pos = (uchar*)(sampleIdxBuf + n);
+ sampleIdx = data->get_sample_indices( data->data_root, sampleIdxBuf );
}
CvMat* buf = data->buf;
if( !tree ) // before training the first tree, initialize weights and other parameters
{
- int* classLabelsBuf = data->resp_int_buf;
- const int* classLabels = 0;
- data->get_class_labels(data->data_root, classLabelsBuf, &classLabels);
+ int* classLabelsBuf = (int*)cur_inn_buf_pos; cur_inn_buf_pos = (uchar*)(classLabelsBuf + n);
+ const int* classLabels = data->get_class_labels(data->data_root, classLabelsBuf);
// in case of logitboost and gentle adaboost each weak tree is a regression tree,
// so we need to convert class labels to floating-point values
- float* responses_buf = data->resp_float_buf;
- const float* responses = 0;
- data->get_ord_responses(data->data_root, responses_buf, &responses);
-
double w0 = 1./n;
double p[2] = { 1, 1 };
const double lbWeightThresh = FLT_EPSILON;
const double lbZMax = 10.;
- float* responsesBuf = data->resp_float_buf;
- const float* responses = 0;
- data->get_ord_responses(data->data_root, responsesBuf, &responses);
for( int i = 0; i < n; i++ )
{
CvCascadeBoostTree* weakTree = *((CvCascadeBoostTree**) cvGetSeqElem( weak, wi ));
weakTree->markFeaturesInMap( featureMap );
}
-}
\ No newline at end of file
+}