diff --git a/openbr/core/boost.cpp b/openbr/core/boost.cpp index f3699c1..16ed736 100644 --- a/openbr/core/boost.cpp +++ b/openbr/core/boost.cpp @@ -826,7 +826,80 @@ CvDTreeNode* CascadeBoostTree::predict( int sampleIdx ) const return node; } -void CascadeBoostTree::write( FileStorage &fs, const Mat& featureMap ) +/* +static void writeRecursive(FileStorage &fs, CvDTreeNode *node, int maxCatCount) +{ + bool hasChildren = node->left ? true : false; + fs << "hasChildren" << hasChildren; + + if (!hasChildren) // Write the leaf value + fs << "value" << node->value; // value of the node. Only relevant for leaf nodes + else { // Write the splitting information and then the children + if (maxCatCount > 0) { + fs << "subset" << "[:"; + for (int i = 0; i < ((maxCatCount + 31) / 32); i++) + fs << node->split->subset[i]; // subset to split on (categorical features) + fs << "]"; + } else { + fs << "threshold" << node->split->ord.c; // threshold to split on (ordered features) + } + + fs << "feature_idx" << node->split->var_idx; // feature idx of node + + fs << "left" << "{"; writeRecursive(fs, node->left, maxCatCount); fs << "}"; // write left child + fs << "right" << "{"; writeRecursive(fs, node->right, maxCatCount); fs << "}"; // write right child + } +} + +void CascadeBoostTree::write(FileStorage &fs) +{ + fs << "{"; + writeRecursive(fs, root, ((CascadeBoostTrainData*)data)->featureEvaluator->getMaxCatCount()); + fs << "}"; +} + +static void readRecursive(const FileNode &fn, CvDTreeNode *node, CvDTreeTrainData *data) +{ + bool hasChildren = (int)fn["hasChildren"]; + + if (!hasChildren) + node->value = (float)fn["value"]; + else { + int maxCatCount = ((CascadeBoostTrainData*)data)->featureEvaluator->getMaxCatCount(); + if (maxCatCount > 0) { + node->split = data->new_split_cat(0, 0); + FileNode subset_node = fn["subset"]; FileNodeIterator subset_it = subset_node.begin(); + for (int i = 0; i < (maxCatCount + 31) / 32; i++, ++subset_it) + node->split->subset[i] = (int)*subset_it; + } else { + float threshold = (float)fn["threshold"]; + node->split = data->new_split_ord(0, threshold, 0, 0, 0); + } + + node->split->var_idx = (int)fn["feature_idx"]; + + CvDTreeNode *leftChild = data->new_node(node, 0, 0, 0); + node->left = leftChild; + readRecursive(fn["left"], leftChild, data); + + CvDTreeNode *rightChild = data->new_node(node, 0, 0, 0); + node->right = rightChild; + readRecursive(fn["right"], rightChild, data); + } +} + +void CascadeBoostTree::read(const FileNode &fn, CvBoost* _ensemble, CvDTreeTrainData* _data) +{ + clear(); + data = _data; + ensemble = _ensemble; + pruned_tree_idx = 0; + + root = data->new_node(0, 0, 0, 0); + readRecursive(fn, root, data); +}*/ + +void CascadeBoostTree::write(FileStorage &fs) { int maxCatCount = ((CascadeBoostTrainData*)data)->featureEvaluator->getMaxCatCount(); int subsetN = (maxCatCount + 31)/32; @@ -868,7 +941,7 @@ void CascadeBoostTree::write( FileStorage &fs, const Mat& featureMap ) fs << internalNodeIdx++; } int fidx = tempNode->split->var_idx; - fidx = featureMap.empty() ? fidx : featureMap.at(0, fidx); + fs << fidx; if ( !maxCatCount ) fs << tempNode->split->ord.c; @@ -1104,21 +1177,6 @@ void CascadeBoostTree::split_node_data( CvDTreeNode* node ) data->free_node_data(node); } -static void auxMarkFeaturesInMap( const CvDTreeNode* node, Mat& featureMap) -{ - if ( node && node->split ) - { - featureMap.ptr(0)[node->split->var_idx] = 1; - auxMarkFeaturesInMap( node->left, featureMap ); - auxMarkFeaturesInMap( node->right, featureMap ); - } -} - -void CascadeBoostTree::markFeaturesInMap( Mat& featureMap ) -{ - auxMarkFeaturesInMap( root, featureMap ); -} - //----------------------------------- CascadeBoost -------------------------------------- bool CascadeBoost::train( const FeatureEvaluator* _featureEvaluator, @@ -1484,7 +1542,7 @@ bool CascadeBoost::isErrDesired() return falseAlarm <= maxFalseAlarm; } -void CascadeBoost::write( FileStorage &fs, const Mat& featureMap ) const +void CascadeBoost::write(FileStorage &fs) const { // char cmnt[30]; CascadeBoostTree* weakTree; @@ -1496,17 +1554,8 @@ void CascadeBoost::write( FileStorage &fs, const Mat& featureMap ) const /*sprintf( cmnt, "tree %i", wi ); cvWriteComment( fs, cmnt, 0 );*/ weakTree = *((CascadeBoostTree**) cvGetSeqElem( weak, wi )); - weakTree->write( fs, featureMap ); + weakTree->write(fs); } fs << "]"; } -void CascadeBoost::markUsedFeaturesInMap( Mat& featureMap ) -{ - for( int wi = 0; wi < weak->total; wi++ ) - { - CascadeBoostTree* weakTree = *((CascadeBoostTree**) cvGetSeqElem( weak, wi )); - weakTree->markFeaturesInMap( featureMap ); - } -} - diff --git a/openbr/core/boost.h b/openbr/core/boost.h index 9710d26..136143a 100644 --- a/openbr/core/boost.h +++ b/openbr/core/boost.h @@ -113,8 +113,7 @@ class CascadeBoostTree : public CvBoostTree { public: virtual CvDTreeNode* predict(int sampleIdx) const; - void write(cv::FileStorage &fs, const cv::Mat& featureMap); - void markFeaturesInMap(cv::Mat& featureMap); + void write(cv::FileStorage &fs); protected: virtual void split_node_data(CvDTreeNode* n); @@ -129,8 +128,7 @@ public: virtual float predict( int sampleIdx, bool returnSum = false ) const; float getThreshold() const { return threshold; } - void write(cv::FileStorage &fs, const cv::Mat& featureMap) const; - void markUsedFeaturesInMap(cv::Mat& featureMap); + void write(cv::FileStorage &fs) const; protected: virtual bool set_params(const CvBoostParams& _params); diff --git a/openbr/core/cascade.cpp b/openbr/core/cascade.cpp index fecd53c..22ecf8c 100644 --- a/openbr/core/cascade.cpp +++ b/openbr/core/cascade.cpp @@ -113,109 +113,73 @@ void br::groupRectangles(vector& rectList, vector& weights, int group { groupRectangles(rectList, groupThreshold, eps, &weights, 0); } -//used for cascade detection algorithm for ROC-curve calculating + void br::groupRectangles(vector& rectList, vector& rejectLevels, vector& levelWeights, int groupThreshold, double eps) { groupRectangles(rectList, groupThreshold, eps, &rejectLevels, &levelWeights); } -bool _FeatureEvaluator::Feature::read(const FileNode& node ) -{ - FileNode rnode = node[CC_RECT]; - FileNodeIterator it = rnode.begin(); - it >> rect.x >> rect.y >> rect.width >> rect.height; - return true; -} - -bool _FeatureEvaluator::read( const FileNode& node ) -{ - features->resize(node.size()); - featuresPtr = &(*features)[0]; - FileNodeIterator it = node.begin(), it_end = node.end(); - for(int i = 0; it != it_end; ++it, i++) - { - if(!featuresPtr[i].read(*it)) - return false; - } - return true; -} - -bool _FeatureEvaluator::setImage( const Mat& image, Size _origWinSize ) -{ - int rn = image.rows+1, cn = image.cols+1; - origWinSize = _origWinSize; - - if( image.cols < origWinSize.width || image.rows < origWinSize.height ) - return false; - - if( sum0.rows < rn || sum0.cols < cn ) - sum0.create(rn, cn, CV_32S); - sum = Mat(rn, cn, CV_32S, sum0.data); - integral(image, sum); - - size_t fi, nfeatures = features->size(); - - for( fi = 0; fi < nfeatures; fi++ ) - featuresPtr[fi].updatePtrs( sum ); - return true; -} - -bool _FeatureEvaluator::setWindow( Point pt ) -{ - if( pt.x < 0 || pt.y < 0 || - pt.x + origWinSize.width >= sum.cols || - pt.y + origWinSize.height >= sum.rows ) - return false; - offset = pt.y * ((int)sum.step/sizeof(int)) + pt.x; - return true; -} - // --------------------------------- Cascade Classifier ---------------------------------- bool _CascadeClassifier::load(const string& filename) { data = Data(); - featureEvaluator.release(); FileStorage fs(filename, FileStorage::READ); - if( !fs.isOpened() ) - return false; - - if( read(fs.getFirstTopLevelNode()) ) - return true; - - return false; -} - -bool _CascadeClassifier::read(const FileNode& root) -{ - if( !data.read(root) ) - return false; - - // load features - featureEvaluator = Ptr<_FeatureEvaluator>(new _FeatureEvaluator()); - FileNode fn = root[CC_FEATURES]; - if( fn.empty() ) + if (!fs.isOpened()) return false; - return featureEvaluator->read(fn); + return data.read(fs.getFirstTopLevelNode()); } -int _CascadeClassifier::runAt(Point pt, double& weight) +int _CascadeClassifier::predict(const Mat &image, double &sum) const { - if( !featureEvaluator->setWindow(pt) ) - return -1; + int nstages = (int)data.stages.size(); + int nodeOfs = 0, leafOfs = 0; + + size_t subsetSize = (data.ncategories + 31)/32; + const int *cascadeSubsets = &data.subsets[0]; + + const float *cascadeLeaves = &data.leaves[0]; + const Data::DTreeNode *cascadeNodes = &data.nodes[0]; + const Data::DTree *cascadeWeaks = &data.classifiers[0]; + const Data::Stage *cascadeStages = &data.stages[0]; + + for (int stageIdx = 0; stageIdx < nstages; stageIdx++) { + const Data::Stage &stage = cascadeStages[stageIdx]; + sum = 0; + + for (int wi = 0; wi < stage.ntrees; wi++) { + const Data::DTree &weak = cascadeWeaks[stage.first + wi]; + int idx = 0, root = nodeOfs; + + do { + const Data::DTreeNode &node = cascadeNodes[root + idx]; + if (data.ncategories > 0) { + int c = (int)representation->evaluate(image, node.featureIdx); + const int* subset = &cascadeSubsets[(root + idx)*subsetSize]; + idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right; + } else { + double val = representation->evaluate(image, node.featureIdx); + idx = val < node.threshold ? node.left : node.right; + } + } while( idx > 0 ); - if( data.isStumpBased ) - return predictCategoricalStump<_FeatureEvaluator>( *this, featureEvaluator, weight ); - return predictCategorical<_FeatureEvaluator>( *this, featureEvaluator, weight ); + sum += cascadeLeaves[leafOfs - idx]; + nodeOfs += weak.nodeCount; + leafOfs += weak.nodeCount + 1; + } + if( sum < stage.threshold ) + return -stageIdx; + } + return 1; } void _CascadeClassifier::detectMultiScale( const Mat& image, vector& objects, vector& rejectLevels, vector& levelWeights, double scaleFactor, int minNeighbors, - int flags, Size minObjectSize, Size maxObjectSize, + Size minObjectSize, Size maxObjectSize, bool outputRejectLevels ) { const double GROUP_EPS = 0.2; @@ -246,14 +210,17 @@ void _CascadeClassifier::detectMultiScale( const Mat& image, vector& objec Mat scaledImage(scaledImageSize, CV_8U, imageBuffer.data); resize(image, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR); - if (!featureEvaluator->setImage(scaledImage, originalWindowSize)) - qFatal("Couldn't set the image"); + + Mat repImage; + representation->preprocess(scaledImage, repImage); int yStep = factor > 2. ? 1 : 2; for (int y = 0; y < processingRectSize.height; y += yStep) { for (int x = 0; x < processingRectSize.width; x += yStep) { + Mat window = repImage(Rect(Point(x, y), representation->postWindowSize())).clone(); + double gypWeight; - int result = runAt(Point(x, y), gypWeight); + int result = predict(window, gypWeight); if (outputRejectLevels) { if (result == 1) @@ -279,29 +246,19 @@ void _CascadeClassifier::detectMultiScale( const Mat& image, vector& objec groupRectangles(objects, minNeighbors, GROUP_EPS); } -void _CascadeClassifier::detectMultiScale( const Mat& image, vector& objects, - double scaleFactor, int minNeighbors, - int flags, Size minObjectSize, Size maxObjectSize) +void _CascadeClassifier::detectMultiScale(const Mat& image, vector& objects, + double scaleFactor, int minNeighbors, Size minObjectSize, Size maxObjectSize) { vector fakeLevels; vector fakeWeights; detectMultiScale( image, objects, fakeLevels, fakeWeights, scaleFactor, - minNeighbors, flags, minObjectSize, maxObjectSize, false ); + minNeighbors, minObjectSize, maxObjectSize, false ); } bool _CascadeClassifier::Data::read(const FileNode &root) { static const float THRESHOLD_EPS = 1e-5f; - // load stage params - string stageTypeStr = (string)root[CC_STAGE_TYPE]; - if( stageTypeStr == CC_BOOST ) - stageType = BOOST; - else - return false; - - featureType = _FeatureEvaluator::LBP; - origWinSize.width = (int)root[CC_WIDTH]; origWinSize.height = (int)root[CC_HEIGHT]; CV_Assert( origWinSize.height > 0 && origWinSize.width > 0 ); diff --git a/openbr/core/cascade.h b/openbr/core/cascade.h index b63adab..7a2eb7e 100644 --- a/openbr/core/cascade.h +++ b/openbr/core/cascade.h @@ -26,33 +26,7 @@ #define CC_FEATURE_PARAMS "featureParams" #define CC_MAX_CAT_COUNT "maxCatCount" -#define CC_HAAR "HAAR" -#define CC_RECTS "rects" -#define CC_TILTED "tilted" - #define CC_LBP "LBP" -#define CC_RECT "rect" - -#define CC_HOG "HOG" -#define CC_HOGMulti "HOGMulti" - -#define CC_NPD "NPD" -#define CC_POINTS "points" - -#define CV_SUM_PTRS( p0, p1, p2, p3, sum, rect, step ) \ - /* (x, y) */ \ - (p0) = sum + (rect).x + (step) * (rect).y, \ - /* (x + w, y) */ \ - (p1) = sum + (rect).x + (rect).width + (step) * (rect).y, \ - /* (x, y + h) */ \ - (p2) = sum + (rect).x + (step) * ((rect).y + (rect).height), \ - /* (x + w, y + h) */ \ - (p3) = sum + (rect).x + (rect).width + (step) * ((rect).y + (rect).height) - -#define CALC_SUM_(p0, p1, p2, p3, offset) \ - ((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset]) - -#define CALC_SUM(rect,offset) CALC_SUM_((rect)[0], (rect)[1], (rect)[2], (rect)[3], offset) using namespace std; @@ -83,132 +57,32 @@ void groupRectangles(vector& rectList, vector& weights, int groupThre void groupRectangles(vector& rectList, int groupThreshold, double eps, vector* weights, vector* levelWeights ); void groupRectangles(vector& rectList, vector& rejectLevels, vector& levelWeights, int groupThreshold, double eps=0.2); -class _FeatureEvaluator -{ -public: - enum { LBP = 0 }; - - _FeatureEvaluator() : features(new vector()) {} - virtual ~_FeatureEvaluator() {} - - virtual bool read( const FileNode& node ); - - virtual bool setImage(const Mat& image, Size _origWinSize); - virtual bool setWindow(Point pt); - - int operator()(int featureIdx) const { return featuresPtr[featureIdx].calc(offset); } - virtual int calcCat(int featureIdx) const { return (*this)(featureIdx); } - -protected: - struct Feature - { - Feature(); - Feature( int x, int y, int _block_w, int _block_h ) : - rect(x, y, _block_w, _block_h) {} - - int calc( int offset ) const; - void updatePtrs( const Mat& sum ); - bool read(const FileNode& node ); - - Rect rect; // weight and height for block - const int* p[16]; // fast - }; - - Size origWinSize; - Ptr > features; - Feature* featuresPtr; // optimization - Mat sum0, sum, window; - Rect normrect; - - int offset; -}; - -inline _FeatureEvaluator::Feature::Feature() -{ - rect = Rect(); - for( int i = 0; i < 16; i++ ) - p[i] = 0; -} - -inline int _FeatureEvaluator::Feature::calc( int _offset ) const -{ - int cval = CALC_SUM_( p[5], p[6], p[9], p[10], _offset ); - - return (CALC_SUM_( p[0], p[1], p[4], p[5], _offset ) >= cval ? 128 : 0) | // 0 - (CALC_SUM_( p[1], p[2], p[5], p[6], _offset ) >= cval ? 64 : 0) | // 1 - (CALC_SUM_( p[2], p[3], p[6], p[7], _offset ) >= cval ? 32 : 0) | // 2 - (CALC_SUM_( p[6], p[7], p[10], p[11], _offset ) >= cval ? 16 : 0) | // 5 - (CALC_SUM_( p[10], p[11], p[14], p[15], _offset ) >= cval ? 8 : 0)| // 8 - (CALC_SUM_( p[9], p[10], p[13], p[14], _offset ) >= cval ? 4 : 0)| // 7 - (CALC_SUM_( p[8], p[9], p[12], p[13], _offset ) >= cval ? 2 : 0)| // 6 - (CALC_SUM_( p[4], p[5], p[8], p[9], _offset ) >= cval ? 1 : 0); -} - -inline void _FeatureEvaluator::Feature::updatePtrs( const Mat& _sum ) -{ - const int* ptr = (const int*)_sum.data; - size_t step = _sum.step/sizeof(ptr[0]); - Rect tr = rect; - CV_SUM_PTRS( p[0], p[1], p[4], p[5], ptr, tr, step ); - tr.x += 2*rect.width; - CV_SUM_PTRS( p[2], p[3], p[6], p[7], ptr, tr, step ); - tr.y += 2*rect.height; - CV_SUM_PTRS( p[10], p[11], p[14], p[15], ptr, tr, step ); - tr.x -= 2*rect.width; - CV_SUM_PTRS( p[8], p[9], p[12], p[13], ptr, tr, step ); -} - -enum -{ - CASCADE_DO_CANNY_PRUNING=1, - CASCADE_SCALE_IMAGE=2, - CASCADE_FIND_BIGGEST_OBJECT=4, - CASCADE_DO_ROUGH_SEARCH=8 -}; - class _CascadeClassifier { public: - _CascadeClassifier() {} - _CascadeClassifier( const string& filename ) { load(filename); } + _CascadeClassifier() : representation(Representation::make("MBLBP(24,24)", NULL)) {} + _CascadeClassifier(const string& filename) : representation(Representation::make("MBLBP(24,24)", NULL)) { load(filename); } ~_CascadeClassifier() {} - bool load( const string& filename ); - bool read( const FileNode& node ); - void detectMultiScale( const Mat& image, + bool load(const string& filename); + void detectMultiScale(const Mat& image, vector& objects, double scaleFactor=1.1, - int minNeighbors=3, int flags=0, + int minNeighbors=3, Size minSize=Size(), - Size maxSize=Size() ); + Size maxSize=Size()); void detectMultiScale( const Mat& image, vector& objects, vector& rejectLevels, vector& levelWeights, double scaleFactor=1.1, - int minNeighbors=3, int flags=0, + int minNeighbors=3, Size minSize=Size(), Size maxSize=Size(), bool outputRejectLevels=false ); - enum { BOOST = 0 }; - enum { DO_CANNY_PRUNING = 1, SCALE_IMAGE = 2, - FIND_BIGGEST_OBJECT = 4, DO_ROUGH_SEARCH = 8 }; - - template - friend int predictOrdered( _CascadeClassifier& cascade, Ptr<_FeatureEvaluator> &featureEvaluator, double& weight); - - template - friend int predictCategorical( _CascadeClassifier& cascade, Ptr<_FeatureEvaluator> &featureEvaluator, double& weight); - - template - friend int predictOrderedStump( _CascadeClassifier& cascade, Ptr<_FeatureEvaluator> &featureEvaluator, double& weight); - - template - friend int predictCategoricalStump( _CascadeClassifier& cascade, Ptr<_FeatureEvaluator> &featureEvaluator, double& weight); - - virtual int runAt(Point pt, double& weight ); + int predict(const Mat &image, double &weight) const; class Data { @@ -250,157 +124,9 @@ public: }; Data data; - Ptr<_FeatureEvaluator> featureEvaluator; + Representation *representation; }; -template -inline int predictOrdered( _CascadeClassifier& cascade, Ptr<_FeatureEvaluator> &_featureEvaluator, double& sum ) -{ - int nstages = (int)cascade.data.stages.size(); - int nodeOfs = 0, leafOfs = 0; - FEval& featureEvaluator = (FEval&)*_featureEvaluator; - float* cascadeLeaves = &cascade.data.leaves[0]; - _CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; - _CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; - _CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; - - for( int si = 0; si < nstages; si++ ) - { - _CascadeClassifier::Data::Stage& stage = cascadeStages[si]; - int wi, ntrees = stage.ntrees; - sum = 0; - - for( wi = 0; wi < ntrees; wi++ ) - { - _CascadeClassifier::Data::DTree& weak = cascadeWeaks[stage.first + wi]; - int idx = 0, root = nodeOfs; - - do - { - _CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx]; - double val = featureEvaluator(node.featureIdx); - idx = val < node.threshold ? node.left : node.right; - } - while( idx > 0 ); - sum += cascadeLeaves[leafOfs - idx]; - nodeOfs += weak.nodeCount; - leafOfs += weak.nodeCount + 1; - } - if( sum < stage.threshold ) - return -si; - } - return 1; -} - -template -inline int predictCategorical( _CascadeClassifier& cascade, Ptr<_FeatureEvaluator> &_featureEvaluator, double& sum ) -{ - int nstages = (int)cascade.data.stages.size(); - int nodeOfs = 0, leafOfs = 0; - FEval& featureEvaluator = (FEval&)*_featureEvaluator; - size_t subsetSize = (cascade.data.ncategories + 31)/32; - int* cascadeSubsets = &cascade.data.subsets[0]; - float* cascadeLeaves = &cascade.data.leaves[0]; - _CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; - _CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; - _CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; - - for(int si = 0; si < nstages; si++ ) - { - _CascadeClassifier::Data::Stage& stage = cascadeStages[si]; - int wi, ntrees = stage.ntrees; - sum = 0; - - for( wi = 0; wi < ntrees; wi++ ) - { - _CascadeClassifier::Data::DTree& weak = cascadeWeaks[stage.first + wi]; - int idx = 0, root = nodeOfs; - do - { - _CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx]; - int c = featureEvaluator(node.featureIdx); - const int* subset = &cascadeSubsets[(root + idx)*subsetSize]; - idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right; - } - while( idx > 0 ); - sum += cascadeLeaves[leafOfs - idx]; - nodeOfs += weak.nodeCount; - leafOfs += weak.nodeCount + 1; - } - if( sum < stage.threshold ) - return -si; - } - return 1; -} - -template -inline int predictOrderedStump( _CascadeClassifier& cascade, Ptr<_FeatureEvaluator> &_featureEvaluator, double& sum ) -{ - int nodeOfs = 0, leafOfs = 0; - FEval& featureEvaluator = (FEval&)*_featureEvaluator; - float* cascadeLeaves = &cascade.data.leaves[0]; - _CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; - _CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; - - int nstages = (int)cascade.data.stages.size(); - for( int stageIdx = 0; stageIdx < nstages; stageIdx++ ) - { - _CascadeClassifier::Data::Stage& stage = cascadeStages[stageIdx]; - sum = 0.0; - - int ntrees = stage.ntrees; - for( int i = 0; i < ntrees; i++, nodeOfs++, leafOfs+= 2 ) - { - _CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs]; - double value = featureEvaluator(node.featureIdx); - sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ]; - } - - if( sum < stage.threshold ) - return -stageIdx; - } - - return 1; -} - -template -inline int predictCategoricalStump( _CascadeClassifier& cascade, Ptr<_FeatureEvaluator> &_featureEvaluator, double& sum ) -{ - int nstages = (int)cascade.data.stages.size(); - int nodeOfs = 0, leafOfs = 0; - FEval& featureEvaluator = (FEval&)*_featureEvaluator; - size_t subsetSize = (cascade.data.ncategories + 31)/32; - int* cascadeSubsets = &cascade.data.subsets[0]; - float* cascadeLeaves = &cascade.data.leaves[0]; - _CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; - _CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; - - for( int si = 0; si < nstages; si++ ) - { - _CascadeClassifier::Data::Stage& stage = cascadeStages[si]; - int wi, ntrees = stage.ntrees; - - sum = 0; - - for( wi = 0; wi < ntrees; wi++ ) - { - _CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs]; - int c = featureEvaluator(node.featureIdx); - const int* subset = &cascadeSubsets[nodeOfs*subsetSize]; - - sum += cascadeLeaves[ subset[c>>5] & (1 << (c & 31)) ? leafOfs : leafOfs+1]; - - nodeOfs++; - leafOfs += 2; - } - - if( sum < stage.threshold ) - return -si; - } - - return 1; -} - } // namespace br #endif // CASCADE_H diff --git a/openbr/openbr_plugin.h b/openbr/openbr_plugin.h index f8ebf59..5a34821 100644 --- a/openbr/openbr_plugin.h +++ b/openbr/openbr_plugin.h @@ -1436,9 +1436,8 @@ public: // OpenCV compatibility virtual int numFeatures() const = 0; virtual int maxCatCount() const = 0; - virtual void getUsedFeatures(cv::Mat &featureMap) const { (void)featureMap; return; } - virtual void write(cv::FileStorage &fs, const cv::Mat &featureMap) const { (void)fs; (void)featureMap; } - virtual void writeFeatures(cv::FileStorage &fs, const cv::Mat &featureMap) const { (void)fs; (void)featureMap; } + virtual void write(cv::FileStorage &fs) const { (void)fs; } + virtual void read(const cv::FileNode &node) { (void)node; } }; /*! diff --git a/openbr/plugins/classification/boostedforest.cpp b/openbr/plugins/classification/boostedforest.cpp index 3756536..fc4bb09 100644 --- a/openbr/plugins/classification/boostedforest.cpp +++ b/openbr/plugins/classification/boostedforest.cpp @@ -62,19 +62,9 @@ class BoostedForestClassifier : public Classifier return representation->preWindowSize(); } - void getUsedFeatures(Mat &featureMap) const + void write(FileStorage &fs) const { - boost->markUsedFeaturesInMap(featureMap); - } - - void write(FileStorage &fs, const Mat &featureMap) const - { - boost->write(fs, featureMap); - } - - void writeFeatures(FileStorage &fs, const Mat &featureMap) const - { - featureEvaluator->writeFeatures(fs, featureMap); + boost->write(fs); } }; diff --git a/openbr/plugins/classification/cascade.cpp b/openbr/plugins/classification/cascade.cpp index 4dad1a3..ec00c67 100644 --- a/openbr/plugins/classification/cascade.cpp +++ b/openbr/plugins/classification/cascade.cpp @@ -176,13 +176,7 @@ class CascadeClassifier : public Classifier return stages.first()->windowSize(); } - void getUsedFeatures(Mat &featureMap) const - { - foreach (const Classifier *stage, stages) - stage->getUsedFeatures(featureMap); - } - - void write(FileStorage &fs, const Mat &featureMap) const + void write(FileStorage &fs) const { fs << CC_STAGE_TYPE << CC_BOOST; fs << CC_FEATURE_TYPE << CC_LBP; @@ -199,24 +193,15 @@ class CascadeClassifier : public Classifier fs << CC_STAGE_NUM << stages.size(); - char cmnt[30]; - int i = 0; fs << CC_STAGES << "["; foreach (const Classifier *stage, stages) { - sprintf( cmnt, "stage %d", i ); - cvWriteComment( fs.fs, cmnt, 0 ); fs << "{"; - stage->write(fs, featureMap); + stage->write(fs); fs << "}"; } fs << "]"; } - void writeFeatures(FileStorage &fs, const Mat& featureMap) const - { - stages.first()->writeFeatures(fs, featureMap); - } - private: float fillTrainingSet(ImageHandler &imgHandler, QList &images, QList &labels) { diff --git a/openbr/plugins/imgproc/slidingwindow.cpp b/openbr/plugins/imgproc/slidingwindow.cpp index 7d32f81..76eef9e 100644 --- a/openbr/plugins/imgproc/slidingwindow.cpp +++ b/openbr/plugins/imgproc/slidingwindow.cpp @@ -155,17 +155,7 @@ class SlidingWindowTransform : public Transform fs << FileStorage::getDefaultObjectName(filename) << "{"; - Mat featureMap(1, classifier->numFeatures(), CV_32SC1); - featureMap.setTo(Scalar(-1)); - - classifier->getUsedFeatures(featureMap); - - for (int fi = 0, idx = 0; fi < classifier->numFeatures(); fi++) - if (featureMap.at(0, fi) >= 0) - featureMap.ptr(0)[fi] = idx++; - - classifier->write(fs, featureMap); - classifier->writeFeatures(fs, featureMap); + classifier->write(fs); fs << "}"; } diff --git a/openbr/plugins/metadata/cascade.cpp b/openbr/plugins/metadata/cascade.cpp index d99c8c5..6ab8c8b 100644 --- a/openbr/plugins/metadata/cascade.cpp +++ b/openbr/plugins/metadata/cascade.cpp @@ -112,8 +112,8 @@ class CascadeTransform : public UntrainableMetaTransform std::vector rects; std::vector rejectLevels; std::vector levelWeights; - if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, 1.2, minNeighbors, (enrollAll ? 0 : CASCADE_FIND_BIGGEST_OBJECT) | CASCADE_SCALE_IMAGE, Size(minSize, minSize), Size(), true); - else cascade->detectMultiScale(m, rects, 1.2, minNeighbors, enrollAll ? 0 : CASCADE_FIND_BIGGEST_OBJECT, Size(minSize, minSize)); + if (ROCMode) cascade->detectMultiScale(m, rects, rejectLevels, levelWeights, 1.2, minNeighbors, Size(minSize, minSize), Size(), true); + else cascade->detectMultiScale(m, rects, 1.2, minNeighbors, Size(minSize, minSize)); if (!enrollAll && rects.empty()) rects.push_back(Rect(0, 0, m.cols, m.rows));