Path: blob/master/modules/objdetect/src/cascadedetect.hpp
16337 views
#pragma once12#include "opencv2/core/ocl.hpp"34namespace cv5{67void clipObjects(Size sz, std::vector<Rect>& objects,8std::vector<int>* a, std::vector<double>* b);910class FeatureEvaluator11{12public:13enum14{15HAAR = 0,16LBP = 1,17HOG = 218};1920struct ScaleData21{22ScaleData() { scale = 0.f; layer_ofs = ystep = 0; }23Size getWorkingSize(Size winSize) const24{25return Size(std::max(szi.width - winSize.width, 0),26std::max(szi.height - winSize.height, 0));27}2829float scale;30Size szi;31int layer_ofs, ystep;32};3334virtual ~FeatureEvaluator();3536virtual bool read(const FileNode& node, Size origWinSize);37virtual Ptr<FeatureEvaluator> clone() const;38virtual int getFeatureType() const;39int getNumChannels() const { return nchannels; }4041virtual bool setImage(InputArray img, const std::vector<float>& scales);42virtual bool setWindow(Point p, int scaleIdx);43const ScaleData& getScaleData(int scaleIdx) const44{45CV_Assert( 0 <= scaleIdx && scaleIdx < (int)scaleData->size());46return scaleData->at(scaleIdx);47}48virtual void getUMats(std::vector<UMat>& bufs);49virtual void getMats();5051Size getLocalSize() const { return localSize; }52Size getLocalBufSize() const { return lbufSize; }5354virtual float calcOrd(int featureIdx) const;55virtual int calcCat(int featureIdx) const;5657static Ptr<FeatureEvaluator> create(int type);5859protected:60enum { SBUF_VALID=1, USBUF_VALID=2 };61int sbufFlag;6263bool updateScaleData( Size imgsz, const std::vector<float>& _scales );64virtual void computeChannels( int, InputArray ) {}65virtual void computeOptFeatures() {}6667Size origWinSize, sbufSize, localSize, lbufSize;68int nchannels;69Mat sbuf, rbuf;70UMat urbuf, usbuf, ufbuf, uscaleData;7172Ptr<std::vector<ScaleData> > scaleData;73};747576class CascadeClassifierImpl CV_FINAL : public BaseCascadeClassifier77{78public:79CascadeClassifierImpl();80virtual ~CascadeClassifierImpl() CV_OVERRIDE;8182bool empty() const CV_OVERRIDE;83bool load( const String& filename ) CV_OVERRIDE;84void read( const FileNode& node ) CV_OVERRIDE;85bool read_( const FileNode& node );86void detectMultiScale( InputArray image,87CV_OUT std::vector<Rect>& objects,88double scaleFactor = 1.1,89int minNeighbors = 3, int flags = 0,90Size minSize = Size(),91Size maxSize = Size() ) CV_OVERRIDE;9293void detectMultiScale( InputArray image,94CV_OUT std::vector<Rect>& objects,95CV_OUT std::vector<int>& numDetections,96double scaleFactor=1.1,97int minNeighbors=3, int flags=0,98Size minSize=Size(),99Size maxSize=Size() ) CV_OVERRIDE;100101void detectMultiScale( InputArray image,102CV_OUT std::vector<Rect>& objects,103CV_OUT std::vector<int>& rejectLevels,104CV_OUT std::vector<double>& levelWeights,105double scaleFactor = 1.1,106int minNeighbors = 3, int flags = 0,107Size minSize = Size(),108Size maxSize = Size(),109bool outputRejectLevels = false ) CV_OVERRIDE;110111112bool isOldFormatCascade() const CV_OVERRIDE;113Size getOriginalWindowSize() const CV_OVERRIDE;114int getFeatureType() const CV_OVERRIDE;115void* getOldCascade() CV_OVERRIDE;116117void setMaskGenerator(const Ptr<MaskGenerator>& maskGenerator) CV_OVERRIDE;118Ptr<MaskGenerator> getMaskGenerator() CV_OVERRIDE;119120protected:121enum { SUM_ALIGN = 64 };122123bool detectSingleScale( InputArray image, Size processingRectSize,124int yStep, double factor, std::vector<Rect>& candidates,125std::vector<int>& rejectLevels, std::vector<double>& levelWeights,126Size sumSize0, bool outputRejectLevels = false );127#ifdef HAVE_OPENCL128bool ocl_detectMultiScaleNoGrouping( const std::vector<float>& scales,129std::vector<Rect>& candidates );130#endif131void detectMultiScaleNoGrouping( InputArray image, std::vector<Rect>& candidates,132std::vector<int>& rejectLevels, std::vector<double>& levelWeights,133double scaleFactor, Size minObjectSize, Size maxObjectSize,134bool outputRejectLevels = false );135136enum { MAX_FACES = 10000 };137enum { BOOST = 0 };138enum { DO_CANNY_PRUNING = CASCADE_DO_CANNY_PRUNING,139SCALE_IMAGE = CASCADE_SCALE_IMAGE,140FIND_BIGGEST_OBJECT = CASCADE_FIND_BIGGEST_OBJECT,141DO_ROUGH_SEARCH = CASCADE_DO_ROUGH_SEARCH142};143144friend class CascadeClassifierInvoker;145friend class SparseCascadeClassifierInvoker;146147template<class FEval>148friend int predictOrdered( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);149150template<class FEval>151friend int predictCategorical( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);152153template<class FEval>154friend int predictOrderedStump( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);155156template<class FEval>157friend int predictCategoricalStump( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);158159int runAt( Ptr<FeatureEvaluator>& feval, Point pt, int scaleIdx, double& weight );160161class Data162{163public:164struct DTreeNode165{166int featureIdx;167float threshold; // for ordered features only168int left;169int right;170};171172struct DTree173{174int nodeCount;175};176177struct Stage178{179int first;180int ntrees;181float threshold;182};183184struct Stump185{186Stump() : featureIdx(0), threshold(0), left(0), right(0) { }187Stump(int _featureIdx, float _threshold, float _left, float _right)188: featureIdx(_featureIdx), threshold(_threshold), left(_left), right(_right) {}189190int featureIdx;191float threshold;192float left;193float right;194};195196Data();197198bool read(const FileNode &node);199200int stageType;201int featureType;202int ncategories;203int minNodesPerTree, maxNodesPerTree;204Size origWinSize;205206std::vector<Stage> stages;207std::vector<DTree> classifiers;208std::vector<DTreeNode> nodes;209std::vector<float> leaves;210std::vector<int> subsets;211std::vector<Stump> stumps;212};213214Data data;215Ptr<FeatureEvaluator> featureEvaluator;216Ptr<CvHaarClassifierCascade> oldCascade;217218Ptr<MaskGenerator> maskGenerator;219UMat ugrayImage;220UMat ufacepos, ustages, unodes, uleaves, usubsets;221#ifdef HAVE_OPENCL222ocl::Kernel haarKernel, lbpKernel;223bool tryOpenCL;224#endif225226Mutex mtx;227};228229#define CC_CASCADE_PARAMS "cascadeParams"230#define CC_STAGE_TYPE "stageType"231#define CC_FEATURE_TYPE "featureType"232#define CC_HEIGHT "height"233#define CC_WIDTH "width"234235#define CC_STAGE_NUM "stageNum"236#define CC_STAGES "stages"237#define CC_STAGE_PARAMS "stageParams"238239#define CC_BOOST "BOOST"240#define CC_MAX_DEPTH "maxDepth"241#define CC_WEAK_COUNT "maxWeakCount"242#define CC_STAGE_THRESHOLD "stageThreshold"243#define CC_WEAK_CLASSIFIERS "weakClassifiers"244#define CC_INTERNAL_NODES "internalNodes"245#define CC_LEAF_VALUES "leafValues"246247#define CC_FEATURES "features"248#define CC_FEATURE_PARAMS "featureParams"249#define CC_MAX_CAT_COUNT "maxCatCount"250251#define CC_HAAR "HAAR"252#define CC_RECTS "rects"253#define CC_TILTED "tilted"254255#define CC_LBP "LBP"256#define CC_RECT "rect"257258#define CC_HOG "HOG"259260#define CV_SUM_PTRS( p0, p1, p2, p3, sum, rect, step ) \261/* (x, y) */ \262(p0) = sum + (rect).x + (step) * (rect).y, \263/* (x + w, y) */ \264(p1) = sum + (rect).x + (rect).width + (step) * (rect).y, \265/* (x, y + h) */ \266(p2) = sum + (rect).x + (step) * ((rect).y + (rect).height), \267/* (x + w, y + h) */ \268(p3) = sum + (rect).x + (rect).width + (step) * ((rect).y + (rect).height)269270#define CV_TILTED_PTRS( p0, p1, p2, p3, tilted, rect, step ) \271/* (x, y) */ \272(p0) = tilted + (rect).x + (step) * (rect).y, \273/* (x - h, y + h) */ \274(p1) = tilted + (rect).x - (rect).height + (step) * ((rect).y + (rect).height), \275/* (x + w, y + w) */ \276(p2) = tilted + (rect).x + (rect).width + (step) * ((rect).y + (rect).width), \277/* (x + w - h, y + w + h) */ \278(p3) = tilted + (rect).x + (rect).width - (rect).height \279+ (step) * ((rect).y + (rect).width + (rect).height)280281#define CALC_SUM_(p0, p1, p2, p3, offset) \282((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset])283284#define CALC_SUM(rect,offset) CALC_SUM_((rect)[0], (rect)[1], (rect)[2], (rect)[3], offset)285286#define CV_SUM_OFS( p0, p1, p2, p3, sum, rect, step ) \287/* (x, y) */ \288(p0) = sum + (rect).x + (step) * (rect).y, \289/* (x + w, y) */ \290(p1) = sum + (rect).x + (rect).width + (step) * (rect).y, \291/* (x, y + h) */ \292(p2) = sum + (rect).x + (step) * ((rect).y + (rect).height), \293/* (x + w, y + h) */ \294(p3) = sum + (rect).x + (rect).width + (step) * ((rect).y + (rect).height)295296#define CV_TILTED_OFS( p0, p1, p2, p3, tilted, rect, step ) \297/* (x, y) */ \298(p0) = tilted + (rect).x + (step) * (rect).y, \299/* (x - h, y + h) */ \300(p1) = tilted + (rect).x - (rect).height + (step) * ((rect).y + (rect).height), \301/* (x + w, y + w) */ \302(p2) = tilted + (rect).x + (rect).width + (step) * ((rect).y + (rect).width), \303/* (x + w - h, y + w + h) */ \304(p3) = tilted + (rect).x + (rect).width - (rect).height \305+ (step) * ((rect).y + (rect).width + (rect).height)306307#define CALC_SUM_OFS_(p0, p1, p2, p3, ptr) \308((ptr)[p0] - (ptr)[p1] - (ptr)[p2] + (ptr)[p3])309310#define CALC_SUM_OFS(rect, ptr) CALC_SUM_OFS_((rect)[0], (rect)[1], (rect)[2], (rect)[3], ptr)311312//---------------------------------------------- HaarEvaluator ---------------------------------------313class HaarEvaluator CV_FINAL : public FeatureEvaluator314{315public:316struct Feature317{318Feature();319bool read( const FileNode& node );320321bool tilted;322323enum { RECT_NUM = 3 };324struct325{326Rect r;327float weight;328} rect[RECT_NUM];329};330331struct OptFeature332{333OptFeature();334335enum { RECT_NUM = Feature::RECT_NUM };336float calc( const int* pwin ) const;337void setOffsets( const Feature& _f, int step, int tofs );338339int ofs[RECT_NUM][4];340float weight[4];341};342343HaarEvaluator();344virtual ~HaarEvaluator() CV_OVERRIDE;345346virtual bool read( const FileNode& node, Size origWinSize) CV_OVERRIDE;347virtual Ptr<FeatureEvaluator> clone() const CV_OVERRIDE;348virtual int getFeatureType() const CV_OVERRIDE { return FeatureEvaluator::HAAR; }349350virtual bool setWindow(Point p, int scaleIdx) CV_OVERRIDE;351Rect getNormRect() const;352int getSquaresOffset() const;353354float operator()(int featureIdx) const355{ return optfeaturesPtr[featureIdx].calc(pwin) * varianceNormFactor; }356virtual float calcOrd(int featureIdx) const CV_OVERRIDE357{ return (*this)(featureIdx); }358359protected:360virtual void computeChannels( int i, InputArray img ) CV_OVERRIDE;361virtual void computeOptFeatures() CV_OVERRIDE;362363Ptr<std::vector<Feature> > features;364Ptr<std::vector<OptFeature> > optfeatures;365Ptr<std::vector<OptFeature> > optfeatures_lbuf;366bool hasTiltedFeatures;367368int tofs, sqofs;369Vec4i nofs;370Rect normrect;371const int* pwin;372OptFeature* optfeaturesPtr; // optimization373float varianceNormFactor;374};375376inline HaarEvaluator::Feature :: Feature()377{378tilted = false;379rect[0].r = rect[1].r = rect[2].r = Rect();380rect[0].weight = rect[1].weight = rect[2].weight = 0;381}382383inline HaarEvaluator::OptFeature :: OptFeature()384{385weight[0] = weight[1] = weight[2] = 0.f;386387ofs[0][0] = ofs[0][1] = ofs[0][2] = ofs[0][3] =388ofs[1][0] = ofs[1][1] = ofs[1][2] = ofs[1][3] =389ofs[2][0] = ofs[2][1] = ofs[2][2] = ofs[2][3] = 0;390}391392inline float HaarEvaluator::OptFeature :: calc( const int* ptr ) const393{394float ret = weight[0] * CALC_SUM_OFS(ofs[0], ptr) +395weight[1] * CALC_SUM_OFS(ofs[1], ptr);396397if( weight[2] != 0.0f )398ret += weight[2] * CALC_SUM_OFS(ofs[2], ptr);399400return ret;401}402403//---------------------------------------------- LBPEvaluator -------------------------------------404405class LBPEvaluator CV_FINAL : public FeatureEvaluator406{407public:408struct Feature409{410Feature();411Feature( int x, int y, int _block_w, int _block_h ) :412rect(x, y, _block_w, _block_h) {}413414bool read(const FileNode& node );415416Rect rect; // weight and height for block417};418419struct OptFeature420{421OptFeature();422423int calc( const int* pwin ) const;424void setOffsets( const Feature& _f, int step );425int ofs[16];426};427428LBPEvaluator();429virtual ~LBPEvaluator() CV_OVERRIDE;430431virtual bool read( const FileNode& node, Size origWinSize ) CV_OVERRIDE;432virtual Ptr<FeatureEvaluator> clone() const CV_OVERRIDE;433virtual int getFeatureType() const CV_OVERRIDE { return FeatureEvaluator::LBP; }434435virtual bool setWindow(Point p, int scaleIdx) CV_OVERRIDE;436437int operator()(int featureIdx) const438{ return optfeaturesPtr[featureIdx].calc(pwin); }439virtual int calcCat(int featureIdx) const CV_OVERRIDE440{ return (*this)(featureIdx); }441protected:442virtual void computeChannels( int i, InputArray img ) CV_OVERRIDE;443virtual void computeOptFeatures() CV_OVERRIDE;444445Ptr<std::vector<Feature> > features;446Ptr<std::vector<OptFeature> > optfeatures;447Ptr<std::vector<OptFeature> > optfeatures_lbuf;448OptFeature* optfeaturesPtr; // optimization449450const int* pwin;451};452453454inline LBPEvaluator::Feature :: Feature()455{456rect = Rect();457}458459inline LBPEvaluator::OptFeature :: OptFeature()460{461for( int i = 0; i < 16; i++ )462ofs[i] = 0;463}464465inline int LBPEvaluator::OptFeature :: calc( const int* p ) const466{467int cval = CALC_SUM_OFS_( ofs[5], ofs[6], ofs[9], ofs[10], p );468469return (CALC_SUM_OFS_( ofs[0], ofs[1], ofs[4], ofs[5], p ) >= cval ? 128 : 0) | // 0470(CALC_SUM_OFS_( ofs[1], ofs[2], ofs[5], ofs[6], p ) >= cval ? 64 : 0) | // 1471(CALC_SUM_OFS_( ofs[2], ofs[3], ofs[6], ofs[7], p ) >= cval ? 32 : 0) | // 2472(CALC_SUM_OFS_( ofs[6], ofs[7], ofs[10], ofs[11], p ) >= cval ? 16 : 0) | // 5473(CALC_SUM_OFS_( ofs[10], ofs[11], ofs[14], ofs[15], p ) >= cval ? 8 : 0)| // 8474(CALC_SUM_OFS_( ofs[9], ofs[10], ofs[13], ofs[14], p ) >= cval ? 4 : 0)| // 7475(CALC_SUM_OFS_( ofs[8], ofs[9], ofs[12], ofs[13], p ) >= cval ? 2 : 0)| // 6476(CALC_SUM_OFS_( ofs[4], ofs[5], ofs[8], ofs[9], p ) >= cval ? 1 : 0);477}478479480//---------------------------------------------- predictor functions -------------------------------------481482template<class FEval>483inline int predictOrdered( CascadeClassifierImpl& cascade,484Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )485{486CV_INSTRUMENT_REGION();487488int nstages = (int)cascade.data.stages.size();489int nodeOfs = 0, leafOfs = 0;490FEval& featureEvaluator = (FEval&)*_featureEvaluator;491float* cascadeLeaves = &cascade.data.leaves[0];492CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];493CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];494CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];495496for( int si = 0; si < nstages; si++ )497{498CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si];499int wi, ntrees = stage.ntrees;500sum = 0;501502for( wi = 0; wi < ntrees; wi++ )503{504CascadeClassifierImpl::Data::DTree& weak = cascadeWeaks[stage.first + wi];505int idx = 0, root = nodeOfs;506507do508{509CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[root + idx];510double val = featureEvaluator(node.featureIdx);511idx = val < node.threshold ? node.left : node.right;512}513while( idx > 0 );514sum += cascadeLeaves[leafOfs - idx];515nodeOfs += weak.nodeCount;516leafOfs += weak.nodeCount + 1;517}518if( sum < stage.threshold )519return -si;520}521return 1;522}523524template<class FEval>525inline int predictCategorical( CascadeClassifierImpl& cascade,526Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )527{528CV_INSTRUMENT_REGION();529530int nstages = (int)cascade.data.stages.size();531int nodeOfs = 0, leafOfs = 0;532FEval& featureEvaluator = (FEval&)*_featureEvaluator;533size_t subsetSize = (cascade.data.ncategories + 31)/32;534int* cascadeSubsets = &cascade.data.subsets[0];535float* cascadeLeaves = &cascade.data.leaves[0];536CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];537CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];538CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];539540for(int si = 0; si < nstages; si++ )541{542CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si];543int wi, ntrees = stage.ntrees;544sum = 0;545546for( wi = 0; wi < ntrees; wi++ )547{548CascadeClassifierImpl::Data::DTree& weak = cascadeWeaks[stage.first + wi];549int idx = 0, root = nodeOfs;550do551{552CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[root + idx];553int c = featureEvaluator(node.featureIdx);554const int* subset = &cascadeSubsets[(root + idx)*subsetSize];555idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right;556}557while( idx > 0 );558sum += cascadeLeaves[leafOfs - idx];559nodeOfs += weak.nodeCount;560leafOfs += weak.nodeCount + 1;561}562if( sum < stage.threshold )563return -si;564}565return 1;566}567568template<class FEval>569inline int predictOrderedStump( CascadeClassifierImpl& cascade,570Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )571{572CV_INSTRUMENT_REGION();573574CV_Assert(!cascade.data.stumps.empty());575FEval& featureEvaluator = (FEval&)*_featureEvaluator;576const CascadeClassifierImpl::Data::Stump* cascadeStumps = &cascade.data.stumps[0];577const CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];578579int nstages = (int)cascade.data.stages.size();580double tmp = 0;581582for( int stageIdx = 0; stageIdx < nstages; stageIdx++ )583{584const CascadeClassifierImpl::Data::Stage& stage = cascadeStages[stageIdx];585tmp = 0;586587int ntrees = stage.ntrees;588for( int i = 0; i < ntrees; i++ )589{590const CascadeClassifierImpl::Data::Stump& stump = cascadeStumps[i];591double value = featureEvaluator(stump.featureIdx);592tmp += value < stump.threshold ? stump.left : stump.right;593}594595if( tmp < stage.threshold )596{597sum = (double)tmp;598return -stageIdx;599}600cascadeStumps += ntrees;601}602603sum = (double)tmp;604return 1;605}606607template<class FEval>608inline int predictCategoricalStump( CascadeClassifierImpl& cascade,609Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )610{611CV_INSTRUMENT_REGION();612613CV_Assert(!cascade.data.stumps.empty());614int nstages = (int)cascade.data.stages.size();615FEval& featureEvaluator = (FEval&)*_featureEvaluator;616size_t subsetSize = (cascade.data.ncategories + 31)/32;617const int* cascadeSubsets = &cascade.data.subsets[0];618const CascadeClassifierImpl::Data::Stump* cascadeStumps = &cascade.data.stumps[0];619const CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];620621double tmp = 0;622for( int si = 0; si < nstages; si++ )623{624const CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si];625int wi, ntrees = stage.ntrees;626tmp = 0;627628for( wi = 0; wi < ntrees; wi++ )629{630const CascadeClassifierImpl::Data::Stump& stump = cascadeStumps[wi];631int c = featureEvaluator(stump.featureIdx);632const int* subset = &cascadeSubsets[wi*subsetSize];633tmp += (subset[c>>5] & (1 << (c & 31))) ? stump.left : stump.right;634}635636if( tmp < stage.threshold )637{638sum = tmp;639return -si;640}641642cascadeStumps += ntrees;643cascadeSubsets += ntrees*subsetSize;644}645646sum = (double)tmp;647return 1;648}649}650651652