From ff8738520147707d7fad1a19c926530453f942b5 Mon Sep 17 00:00:00 2001 From: Vadim Pisarevsky Date: Wed, 4 Dec 2013 19:00:39 +0400 Subject: [PATCH] refactored CascadeClassifier to hide implementation details (take 2) --- .../objdetect/include/opencv2/objdetect.hpp | 193 +++++++----------- modules/objdetect/src/cascadedetect.cpp | 172 +++++++++++++--- modules/objdetect/src/cascadedetect.hpp | 178 +++++++++++++--- modules/ocl/src/haar.cpp | 2 +- 4 files changed, 368 insertions(+), 177 deletions(-) diff --git a/modules/objdetect/include/opencv2/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect.hpp index c3dee4a2bbe4..26419bc59675 100644 --- a/modules/objdetect/include/opencv2/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect.hpp @@ -149,143 +149,96 @@ enum { CASCADE_DO_CANNY_PRUNING = 1, CASCADE_DO_ROUGH_SEARCH = 8 }; -class CV_EXPORTS_W CascadeClassifier +class CV_EXPORTS_W BaseCascadeClassifier : public Algorithm { public: - CV_WRAP CascadeClassifier(); - CV_WRAP CascadeClassifier( const String& filename ); - virtual ~CascadeClassifier(); - - CV_WRAP virtual bool empty() const; - CV_WRAP bool load( const String& filename ); - virtual bool read( const FileNode& node ); - CV_WRAP virtual void detectMultiScale( InputArray image, - CV_OUT std::vector& objects, - double scaleFactor = 1.1, - int minNeighbors = 3, int flags = 0, - Size minSize = Size(), - Size maxSize = Size() ); - - CV_WRAP virtual void detectMultiScale( InputArray image, - CV_OUT std::vector& objects, - CV_OUT std::vector& numDetections, - double scaleFactor=1.1, - int minNeighbors=3, int flags=0, - Size minSize=Size(), - Size maxSize=Size() ); - - CV_WRAP virtual void detectMultiScale( InputArray image, + virtual ~BaseCascadeClassifier(); + virtual bool empty() const = 0; + virtual bool load( const String& filename ) = 0; + virtual void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize ) = 0; + + virtual void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& numDetections, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize ) = 0; + + virtual void detectMultiScale( InputArray image, CV_OUT std::vector& objects, CV_OUT std::vector& rejectLevels, CV_OUT std::vector& levelWeights, - double scaleFactor = 1.1, - int minNeighbors = 3, int flags = 0, - Size minSize = Size(), - Size maxSize = Size(), - bool outputRejectLevels = false ); - - - bool isOldFormatCascade() const; - virtual Size getOriginalWindowSize() const; - int getFeatureType() const; - bool setImage( const Mat& ); - -protected: - virtual bool detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, - int stripSize, int yStep, double factor, std::vector& candidates, - std::vector& rejectLevels, std::vector& levelWeights, bool outputRejectLevels = false ); - - virtual void detectMultiScaleNoGrouping( const Mat& image, std::vector& candidates, - std::vector& rejectLevels, std::vector& levelWeights, - double scaleFactor, Size minObjectSize, Size maxObjectSize, - bool outputRejectLevels = false ); - -protected: - enum { BOOST = 0 - }; - enum { DO_CANNY_PRUNING = CASCADE_DO_CANNY_PRUNING, - SCALE_IMAGE = CASCADE_SCALE_IMAGE, - FIND_BIGGEST_OBJECT = CASCADE_FIND_BIGGEST_OBJECT, - DO_ROUGH_SEARCH = CASCADE_DO_ROUGH_SEARCH - }; - - friend class CascadeClassifierInvoker; + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize, + bool outputRejectLevels ) = 0; - template - friend int predictOrdered( CascadeClassifier& cascade, Ptr &featureEvaluator, double& weight); + virtual bool isOldFormatCascade() const = 0; + virtual Size getOriginalWindowSize() const = 0; + virtual int getFeatureType() const = 0; + virtual void* getOldCascade() = 0; - template - friend int predictCategorical( CascadeClassifier& cascade, Ptr &featureEvaluator, double& weight); - - template - friend int predictOrderedStump( CascadeClassifier& cascade, Ptr &featureEvaluator, double& weight); - - template - friend int predictCategoricalStump( CascadeClassifier& cascade, Ptr &featureEvaluator, double& weight); - - bool setImage( Ptr& feval, const Mat& image); - virtual int runAt( Ptr& feval, Point pt, double& weight ); - - class Data - { - public: - struct CV_EXPORTS DTreeNode - { - int featureIdx; - float threshold; // for ordered features only - int left; - int right; - }; - - struct CV_EXPORTS DTree - { - int nodeCount; - }; - - struct CV_EXPORTS Stage - { - int first; - int ntrees; - float threshold; - }; - - bool read(const FileNode &node); - - bool isStumpBased; - - int stageType; - int featureType; - int ncategories; - Size origWinSize; - - std::vector stages; - std::vector classifiers; - std::vector nodes; - std::vector leaves; - std::vector subsets; - }; - - Data data; - Ptr featureEvaluator; - Ptr oldCascade; - -public: class CV_EXPORTS MaskGenerator { public: virtual ~MaskGenerator() {} - virtual cv::Mat generateMask(const cv::Mat& src)=0; - virtual void initializeMask(const cv::Mat& /*src*/) {}; + virtual Mat generateMask(const Mat& src)=0; + virtual void initializeMask(const Mat& /*src*/) {}; }; - void setMaskGenerator(Ptr maskGenerator); - Ptr getMaskGenerator(); + virtual void setMaskGenerator(const Ptr& maskGenerator) = 0; + virtual Ptr getMaskGenerator() = 0; +}; - void setFaceDetectionMaskGenerator(); +class CV_EXPORTS_W CascadeClassifier : public BaseCascadeClassifier +{ +public: + CV_WRAP CascadeClassifier(); + CV_WRAP explicit CascadeClassifier(const String& filename); + virtual ~CascadeClassifier(); + CV_WRAP virtual bool empty() const; + CV_WRAP virtual bool load( const String& filename ); + CV_WRAP virtual void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + double scaleFactor = 1.1, + int minNeighbors = 3, int flags = 0, + Size minSize = Size(), + Size maxSize = Size() ); + + CV_WRAP virtual void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& numDetections, + double scaleFactor=1.1, + int minNeighbors=3, int flags=0, + Size minSize=Size(), + Size maxSize=Size() ); + CV_WRAP virtual void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& rejectLevels, + CV_OUT std::vector& levelWeights, + double scaleFactor = 1.1, + int minNeighbors = 3, int flags = 0, + Size minSize = Size(), + Size maxSize = Size(), + bool outputRejectLevels = false ); + + CV_WRAP virtual bool isOldFormatCascade() const; + CV_WRAP virtual Size getOriginalWindowSize() const; + CV_WRAP virtual int getFeatureType() const; + virtual void* getOldCascade(); + + virtual void setMaskGenerator(const Ptr& maskGenerator); + virtual Ptr getMaskGenerator(); protected: - Ptr maskGenerator; + Ptr cc; }; +CV_EXPORTS Ptr createFaceDetectionMaskGenerator(); + //////////////// HOG (Histogram-of-Oriented-Gradients) Descriptor and Object Detector ////////////// // struct for detection region of interest (ROI) diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp index 92b685c5ddb1..10c1b17a3ce3 100644 --- a/modules/objdetect/src/cascadedetect.cpp +++ b/modules/objdetect/src/cascadedetect.cpp @@ -430,7 +430,6 @@ void groupRectangles_meanshift(std::vector& rectList, std::vector& } - FeatureEvaluator::~FeatureEvaluator() {} bool FeatureEvaluator::read(const FileNode&) {return true;} Ptr FeatureEvaluator::clone() const { return Ptr(); } @@ -834,25 +833,20 @@ Ptr FeatureEvaluator::create( int featureType ) //---------------------------------------- Classifier Cascade -------------------------------------------- -CascadeClassifier::CascadeClassifier() +CascadeClassifierImpl::CascadeClassifierImpl() { } -CascadeClassifier::CascadeClassifier(const String& filename) +CascadeClassifierImpl::~CascadeClassifierImpl() { - load(filename); } -CascadeClassifier::~CascadeClassifier() -{ -} - -bool CascadeClassifier::empty() const +bool CascadeClassifierImpl::empty() const { return !oldCascade && data.stages.empty(); } -bool CascadeClassifier::load(const String& filename) +bool CascadeClassifierImpl::load(const String& filename) { oldCascade.release(); data = Data(); @@ -862,7 +856,7 @@ bool CascadeClassifier::load(const String& filename) if( !fs.isOpened() ) return false; - if( read(fs.getFirstTopLevelNode()) ) + if( read_(fs.getFirstTopLevelNode()) ) return true; fs.release(); @@ -871,7 +865,12 @@ bool CascadeClassifier::load(const String& filename) return !oldCascade.empty(); } -int CascadeClassifier::runAt( Ptr& evaluator, Point pt, double& weight ) +void CascadeClassifierImpl::read(const FileNode& node) +{ + read_(node); +} + +int CascadeClassifierImpl::runAt( Ptr& evaluator, Point pt, double& weight ) { CV_Assert( !oldCascade ); @@ -905,33 +904,33 @@ int CascadeClassifier::runAt( Ptr& evaluator, Point pt, double } } -bool CascadeClassifier::setImage( Ptr& evaluator, const Mat& image ) +bool CascadeClassifierImpl::setImage( Ptr& evaluator, const Mat& image ) { return empty() ? false : evaluator->setImage(image, data.origWinSize); } -void CascadeClassifier::setMaskGenerator(Ptr _maskGenerator) +void CascadeClassifierImpl::setMaskGenerator(const Ptr& _maskGenerator) { maskGenerator=_maskGenerator; } -Ptr CascadeClassifier::getMaskGenerator() +Ptr CascadeClassifierImpl::getMaskGenerator() { return maskGenerator; } -void CascadeClassifier::setFaceDetectionMaskGenerator() +Ptr createFaceDetectionMaskGenerator() { #ifdef HAVE_TEGRA_OPTIMIZATION - setMaskGenerator(tegra::getCascadeClassifierMaskGenerator(*this)); + return tegra::getCascadeClassifierMaskGenerator(*this); #else - setMaskGenerator(Ptr()); + return Ptr(); #endif } class CascadeClassifierInvoker : public ParallelLoopBody { public: - CascadeClassifierInvoker( CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, + CascadeClassifierInvoker( CascadeClassifierImpl& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, std::vector& _vec, std::vector& _levels, std::vector& _weights, bool outputLevels, const Mat& _mask, Mutex* _mtx) { classifier = &_cc; @@ -950,7 +949,8 @@ class CascadeClassifierInvoker : public ParallelLoopBody { Ptr evaluator = classifier->featureEvaluator->clone(); - Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), cvRound(classifier->data.origWinSize.height * scalingFactor)); + Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), + cvRound(classifier->data.origWinSize.height * scalingFactor)); int y1 = range.start * stripSize; int y2 = std::min(range.end * stripSize, processingRectSize.height); @@ -995,7 +995,7 @@ class CascadeClassifierInvoker : public ParallelLoopBody } } - CascadeClassifier* classifier; + CascadeClassifierImpl* classifier; std::vector* rectangles; Size processingRectSize; int stripSize, yStep; @@ -1010,7 +1010,7 @@ struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } } struct getNeighbors { int operator ()(const CvAvgComp& e) const { return e.neighbors; } }; -bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, +bool CascadeClassifierImpl::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, int stripSize, int yStep, double factor, std::vector& candidates, std::vector& levels, std::vector& weights, bool outputRejectLevels ) { @@ -1051,27 +1051,33 @@ bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Siz return true; } -bool CascadeClassifier::isOldFormatCascade() const +bool CascadeClassifierImpl::isOldFormatCascade() const { return !oldCascade.empty(); } -int CascadeClassifier::getFeatureType() const +int CascadeClassifierImpl::getFeatureType() const { return featureEvaluator->getFeatureType(); } -Size CascadeClassifier::getOriginalWindowSize() const +Size CascadeClassifierImpl::getOriginalWindowSize() const { return data.origWinSize; } -bool CascadeClassifier::setImage(const Mat& image) +bool CascadeClassifierImpl::setImage(InputArray _image) { + Mat image = _image.getMat(); return featureEvaluator->setImage(image, data.origWinSize); } +void* CascadeClassifierImpl::getOldCascade() +{ + return oldCascade; +} + static void detectMultiScaleOldFormat( const Mat& image, Ptr oldCascade, std::vector& objects, std::vector& rejectLevels, @@ -1090,7 +1096,7 @@ static void detectMultiScaleOldFormat( const Mat& image, Ptr& candidates, +void CascadeClassifierImpl::detectMultiScaleNoGrouping( const Mat& image, std::vector& candidates, std::vector& rejectLevels, std::vector& levelWeights, double scaleFactor, Size minObjectSize, Size maxObjectSize, bool outputRejectLevels ) @@ -1154,7 +1160,7 @@ void CascadeClassifier::detectMultiScaleNoGrouping( const Mat& image, std::vecto } } -void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& objects, +void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector& objects, std::vector& rejectLevels, std::vector& levelWeights, double scaleFactor, int minNeighbors, @@ -1189,7 +1195,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& } } -void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& objects, +void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector& objects, double scaleFactor, int minNeighbors, int flags, Size minObjectSize, Size maxObjectSize) { @@ -1200,7 +1206,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& minNeighbors, flags, minObjectSize, maxObjectSize ); } -void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& objects, +void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector& objects, std::vector& numDetections, double scaleFactor, int minNeighbors, int flags, Size minObjectSize, Size maxObjectSize ) @@ -1229,7 +1235,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector& } } -bool CascadeClassifier::Data::read(const FileNode &root) +bool CascadeClassifierImpl::Data::read(const FileNode &root) { static const float THRESHOLD_EPS = 1e-5f; @@ -1339,7 +1345,7 @@ bool CascadeClassifier::Data::read(const FileNode &root) return true; } -bool CascadeClassifier::read(const FileNode& root) +bool CascadeClassifierImpl::read_(const FileNode& root) { if( !data.read(root) ) return false; @@ -1356,4 +1362,106 @@ bool CascadeClassifier::read(const FileNode& root) template<> void DefaultDeleter::operator ()(CvHaarClassifierCascade* obj) const { cvReleaseHaarClassifierCascade(&obj); } + +BaseCascadeClassifier::~BaseCascadeClassifier() +{ +} + +CascadeClassifier::CascadeClassifier() {} +CascadeClassifier::CascadeClassifier(const String& filename) +{ + load(filename); +} + +CascadeClassifier::~CascadeClassifier() +{ +} + +bool CascadeClassifier::empty() const +{ + return cc.empty() || cc->empty(); +} + +bool CascadeClassifier::load( const String& filename ) +{ + cc = makePtr(); + if(!cc->load(filename)) + cc.release(); + return !empty(); +} + +void CascadeClassifier::detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, + Size maxSize ) +{ + CV_Assert(!empty()); + cc->detectMultiScale(image, objects, scaleFactor, minNeighbors, flags, minSize, maxSize); +} + +void CascadeClassifier::detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& numDetections, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize ) +{ + CV_Assert(!empty()); + cc->detectMultiScale(image, objects, numDetections, + scaleFactor, minNeighbors, flags, minSize, maxSize); +} + +void CascadeClassifier::detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& rejectLevels, + CV_OUT std::vector& levelWeights, + double scaleFactor, + int minNeighbors, int flags, + Size minSize, Size maxSize, + bool outputRejectLevels ) +{ + CV_Assert(!empty()); + cc->detectMultiScale(image, objects, rejectLevels, levelWeights, + scaleFactor, minNeighbors, flags, + minSize, maxSize, outputRejectLevels); +} + +bool CascadeClassifier::isOldFormatCascade() const +{ + CV_Assert(!empty()); + return cc->isOldFormatCascade(); +} + +Size CascadeClassifier::getOriginalWindowSize() const +{ + CV_Assert(!empty()); + return cc->getOriginalWindowSize(); +} + +int CascadeClassifier::getFeatureType() const +{ + CV_Assert(!empty()); + return cc->getFeatureType(); +} + +void* CascadeClassifier::getOldCascade() +{ + CV_Assert(!empty()); + return cc->getOldCascade(); +} + +void CascadeClassifier::setMaskGenerator(const Ptr& maskGenerator) +{ + CV_Assert(!empty()); + cc->setMaskGenerator(maskGenerator); +} + +Ptr CascadeClassifier::getMaskGenerator() +{ + CV_Assert(!empty()); + return cc->getMaskGenerator(); +} + } // namespace cv diff --git a/modules/objdetect/src/cascadedetect.hpp b/modules/objdetect/src/cascadedetect.hpp index de3303e4aa03..862a273dcf74 100644 --- a/modules/objdetect/src/cascadedetect.hpp +++ b/modules/objdetect/src/cascadedetect.hpp @@ -3,6 +3,132 @@ namespace cv { +class CascadeClassifierImpl : public BaseCascadeClassifier +{ +public: + CascadeClassifierImpl(); + virtual ~CascadeClassifierImpl(); + + bool empty() const; + bool load( const String& filename ); + void read( const FileNode& node ); + bool read_( const FileNode& node ); + void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + double scaleFactor = 1.1, + int minNeighbors = 3, int flags = 0, + Size minSize = Size(), + Size maxSize = Size() ); + + void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& numDetections, + double scaleFactor=1.1, + int minNeighbors=3, int flags=0, + Size minSize=Size(), + Size maxSize=Size() ); + + void detectMultiScale( InputArray image, + CV_OUT std::vector& objects, + CV_OUT std::vector& rejectLevels, + CV_OUT std::vector& levelWeights, + double scaleFactor = 1.1, + int minNeighbors = 3, int flags = 0, + Size minSize = Size(), + Size maxSize = Size(), + bool outputRejectLevels = false ); + + + bool isOldFormatCascade() const; + Size getOriginalWindowSize() const; + int getFeatureType() const; + bool setImage( InputArray ); + void* getOldCascade(); + + void setMaskGenerator(const Ptr& maskGenerator); + Ptr getMaskGenerator(); + +protected: + bool detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, + int stripSize, int yStep, double factor, std::vector& candidates, + std::vector& rejectLevels, std::vector& levelWeights, bool outputRejectLevels = false ); + + void detectMultiScaleNoGrouping( const Mat& image, std::vector& candidates, + std::vector& rejectLevels, std::vector& levelWeights, + double scaleFactor, Size minObjectSize, Size maxObjectSize, + bool outputRejectLevels = false ); + + enum { BOOST = 0 + }; + enum { DO_CANNY_PRUNING = CASCADE_DO_CANNY_PRUNING, + SCALE_IMAGE = CASCADE_SCALE_IMAGE, + FIND_BIGGEST_OBJECT = CASCADE_FIND_BIGGEST_OBJECT, + DO_ROUGH_SEARCH = CASCADE_DO_ROUGH_SEARCH + }; + + friend class CascadeClassifierInvoker; + + template + friend int predictOrdered( CascadeClassifierImpl& cascade, Ptr &featureEvaluator, double& weight); + + template + friend int predictCategorical( CascadeClassifierImpl& cascade, Ptr &featureEvaluator, double& weight); + + template + friend int predictOrderedStump( CascadeClassifierImpl& cascade, Ptr &featureEvaluator, double& weight); + + template + friend int predictCategoricalStump( CascadeClassifierImpl& cascade, Ptr &featureEvaluator, double& weight); + + bool setImage( Ptr& feval, const Mat& image); + int runAt( Ptr& feval, Point pt, double& weight ); + + class Data + { + public: + struct CV_EXPORTS DTreeNode + { + int featureIdx; + float threshold; // for ordered features only + int left; + int right; + }; + + struct CV_EXPORTS DTree + { + int nodeCount; + }; + + struct CV_EXPORTS Stage + { + int first; + int ntrees; + float threshold; + }; + + bool read(const FileNode &node); + + bool isStumpBased; + + int stageType; + int featureType; + int ncategories; + Size origWinSize; + + std::vector stages; + std::vector classifiers; + std::vector nodes; + std::vector leaves; + std::vector subsets; + }; + + Data data; + Ptr featureEvaluator; + Ptr oldCascade; + + Ptr maskGenerator; +}; + #define CC_CASCADE_PARAMS "cascadeParams" #define CC_STAGE_TYPE "stageType" #define CC_FEATURE_TYPE "featureType" @@ -322,30 +448,31 @@ inline void HOGEvaluator::Feature :: updatePtrs( const std::vector &_hist, //---------------------------------------------- predictor functions ------------------------------------- template -inline int predictOrdered( CascadeClassifier& cascade, Ptr &_featureEvaluator, double& sum ) +inline int predictOrdered( CascadeClassifierImpl& cascade, + Ptr &_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]; + CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; + CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; + CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0]; for( int si = 0; si < nstages; si++ ) { - CascadeClassifier::Data::Stage& stage = cascadeStages[si]; + CascadeClassifierImpl::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]; + CascadeClassifierImpl::Data::DTree& weak = cascadeWeaks[stage.first + wi]; int idx = 0, root = nodeOfs; do { - CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx]; + CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[root + idx]; double val = featureEvaluator(node.featureIdx); idx = val < node.threshold ? node.left : node.right; } @@ -361,7 +488,8 @@ inline int predictOrdered( CascadeClassifier& cascade, Ptr &_f } template -inline int predictCategorical( CascadeClassifier& cascade, Ptr &_featureEvaluator, double& sum ) +inline int predictCategorical( CascadeClassifierImpl& cascade, + Ptr &_featureEvaluator, double& sum ) { int nstages = (int)cascade.data.stages.size(); int nodeOfs = 0, leafOfs = 0; @@ -369,23 +497,23 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr 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]; + CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; + CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; + CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0]; for(int si = 0; si < nstages; si++ ) { - CascadeClassifier::Data::Stage& stage = cascadeStages[si]; + CascadeClassifierImpl::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]; + CascadeClassifierImpl::Data::DTree& weak = cascadeWeaks[stage.first + wi]; int idx = 0, root = nodeOfs; do { - CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx]; + CascadeClassifierImpl::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; @@ -402,24 +530,25 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr } template -inline int predictOrderedStump( CascadeClassifier& cascade, Ptr &_featureEvaluator, double& sum ) +inline int predictOrderedStump( CascadeClassifierImpl& cascade, + Ptr &_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]; + CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; + CascadeClassifierImpl::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]; + CascadeClassifierImpl::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]; + CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[nodeOfs]; double value = featureEvaluator(node.featureIdx); sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ]; } @@ -432,7 +561,8 @@ inline int predictOrderedStump( CascadeClassifier& cascade, Ptr -inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr &_featureEvaluator, double& sum ) +inline int predictCategoricalStump( CascadeClassifierImpl& cascade, + Ptr &_featureEvaluator, double& sum ) { int nstages = (int)cascade.data.stages.size(); int nodeOfs = 0, leafOfs = 0; @@ -440,15 +570,15 @@ inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr