Commit ff873852 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

refactored CascadeClassifier to hide implementation details (take 2)

parent 0736ede7
...@@ -149,143 +149,96 @@ enum { CASCADE_DO_CANNY_PRUNING = 1, ...@@ -149,143 +149,96 @@ enum { CASCADE_DO_CANNY_PRUNING = 1,
CASCADE_DO_ROUGH_SEARCH = 8 CASCADE_DO_ROUGH_SEARCH = 8
}; };
class CV_EXPORTS_W CascadeClassifier class CV_EXPORTS_W BaseCascadeClassifier : public Algorithm
{ {
public: public:
CV_WRAP CascadeClassifier(); virtual ~BaseCascadeClassifier();
CV_WRAP CascadeClassifier( const String& filename ); virtual bool empty() const = 0;
virtual ~CascadeClassifier(); virtual bool load( const String& filename ) = 0;
virtual void detectMultiScale( InputArray image,
CV_WRAP virtual bool empty() const; CV_OUT std::vector<Rect>& objects,
CV_WRAP bool load( const String& filename ); double scaleFactor,
virtual bool read( const FileNode& node ); int minNeighbors, int flags,
CV_WRAP virtual void detectMultiScale( InputArray image, Size minSize, Size maxSize ) = 0;
CV_OUT std::vector<Rect>& objects,
double scaleFactor = 1.1, virtual void detectMultiScale( InputArray image,
int minNeighbors = 3, int flags = 0, CV_OUT std::vector<Rect>& objects,
Size minSize = Size(), CV_OUT std::vector<int>& numDetections,
Size maxSize = Size() ); double scaleFactor,
int minNeighbors, int flags,
CV_WRAP virtual void detectMultiScale( InputArray image, Size minSize, Size maxSize ) = 0;
CV_OUT std::vector<Rect>& objects,
CV_OUT std::vector<int>& numDetections, virtual void detectMultiScale( InputArray image,
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<Rect>& objects, CV_OUT std::vector<Rect>& objects,
CV_OUT std::vector<int>& rejectLevels, CV_OUT std::vector<int>& rejectLevels,
CV_OUT std::vector<double>& levelWeights, CV_OUT std::vector<double>& levelWeights,
double scaleFactor = 1.1, double scaleFactor,
int minNeighbors = 3, int flags = 0, int minNeighbors, int flags,
Size minSize = Size(), Size minSize, Size maxSize,
Size maxSize = Size(), bool outputRejectLevels ) = 0;
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<Rect>& candidates,
std::vector<int>& rejectLevels, std::vector<double>& levelWeights, bool outputRejectLevels = false );
virtual void detectMultiScaleNoGrouping( const Mat& image, std::vector<Rect>& candidates,
std::vector<int>& rejectLevels, std::vector<double>& 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;
template<class FEval> virtual bool isOldFormatCascade() const = 0;
friend int predictOrdered( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight); virtual Size getOriginalWindowSize() const = 0;
virtual int getFeatureType() const = 0;
virtual void* getOldCascade() = 0;
template<class FEval>
friend int predictCategorical( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
template<class FEval>
friend int predictOrderedStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
template<class FEval>
friend int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
bool setImage( Ptr<FeatureEvaluator>& feval, const Mat& image);
virtual int runAt( Ptr<FeatureEvaluator>& 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<Stage> stages;
std::vector<DTree> classifiers;
std::vector<DTreeNode> nodes;
std::vector<float> leaves;
std::vector<int> subsets;
};
Data data;
Ptr<FeatureEvaluator> featureEvaluator;
Ptr<CvHaarClassifierCascade> oldCascade;
public:
class CV_EXPORTS MaskGenerator class CV_EXPORTS MaskGenerator
{ {
public: public:
virtual ~MaskGenerator() {} virtual ~MaskGenerator() {}
virtual cv::Mat generateMask(const cv::Mat& src)=0; virtual Mat generateMask(const Mat& src)=0;
virtual void initializeMask(const cv::Mat& /*src*/) {}; virtual void initializeMask(const Mat& /*src*/) {};
}; };
void setMaskGenerator(Ptr<MaskGenerator> maskGenerator); virtual void setMaskGenerator(const Ptr<MaskGenerator>& maskGenerator) = 0;
Ptr<MaskGenerator> getMaskGenerator(); virtual Ptr<MaskGenerator> 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<Rect>& 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<Rect>& objects,
CV_OUT std::vector<int>& 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<Rect>& objects,
CV_OUT std::vector<int>& rejectLevels,
CV_OUT std::vector<double>& 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>& maskGenerator);
virtual Ptr<MaskGenerator> getMaskGenerator();
protected: protected:
Ptr<MaskGenerator> maskGenerator; Ptr<BaseCascadeClassifier> cc;
}; };
CV_EXPORTS Ptr<CascadeClassifier::MaskGenerator> createFaceDetectionMaskGenerator();
//////////////// HOG (Histogram-of-Oriented-Gradients) Descriptor and Object Detector ////////////// //////////////// HOG (Histogram-of-Oriented-Gradients) Descriptor and Object Detector //////////////
// struct for detection region of interest (ROI) // struct for detection region of interest (ROI)
......
...@@ -430,7 +430,6 @@ void groupRectangles_meanshift(std::vector<Rect>& rectList, std::vector<double>& ...@@ -430,7 +430,6 @@ void groupRectangles_meanshift(std::vector<Rect>& rectList, std::vector<double>&
} }
FeatureEvaluator::~FeatureEvaluator() {} FeatureEvaluator::~FeatureEvaluator() {}
bool FeatureEvaluator::read(const FileNode&) {return true;} bool FeatureEvaluator::read(const FileNode&) {return true;}
Ptr<FeatureEvaluator> FeatureEvaluator::clone() const { return Ptr<FeatureEvaluator>(); } Ptr<FeatureEvaluator> FeatureEvaluator::clone() const { return Ptr<FeatureEvaluator>(); }
...@@ -834,25 +833,20 @@ Ptr<FeatureEvaluator> FeatureEvaluator::create( int featureType ) ...@@ -834,25 +833,20 @@ Ptr<FeatureEvaluator> FeatureEvaluator::create( int featureType )
//---------------------------------------- Classifier Cascade -------------------------------------------- //---------------------------------------- Classifier Cascade --------------------------------------------
CascadeClassifier::CascadeClassifier() CascadeClassifierImpl::CascadeClassifierImpl()
{ {
} }
CascadeClassifier::CascadeClassifier(const String& filename) CascadeClassifierImpl::~CascadeClassifierImpl()
{ {
load(filename);
} }
CascadeClassifier::~CascadeClassifier() bool CascadeClassifierImpl::empty() const
{
}
bool CascadeClassifier::empty() const
{ {
return !oldCascade && data.stages.empty(); return !oldCascade && data.stages.empty();
} }
bool CascadeClassifier::load(const String& filename) bool CascadeClassifierImpl::load(const String& filename)
{ {
oldCascade.release(); oldCascade.release();
data = Data(); data = Data();
...@@ -862,7 +856,7 @@ bool CascadeClassifier::load(const String& filename) ...@@ -862,7 +856,7 @@ bool CascadeClassifier::load(const String& filename)
if( !fs.isOpened() ) if( !fs.isOpened() )
return false; return false;
if( read(fs.getFirstTopLevelNode()) ) if( read_(fs.getFirstTopLevelNode()) )
return true; return true;
fs.release(); fs.release();
...@@ -871,7 +865,12 @@ bool CascadeClassifier::load(const String& filename) ...@@ -871,7 +865,12 @@ bool CascadeClassifier::load(const String& filename)
return !oldCascade.empty(); return !oldCascade.empty();
} }
int CascadeClassifier::runAt( Ptr<FeatureEvaluator>& evaluator, Point pt, double& weight ) void CascadeClassifierImpl::read(const FileNode& node)
{
read_(node);
}
int CascadeClassifierImpl::runAt( Ptr<FeatureEvaluator>& evaluator, Point pt, double& weight )
{ {
CV_Assert( !oldCascade ); CV_Assert( !oldCascade );
...@@ -905,33 +904,33 @@ int CascadeClassifier::runAt( Ptr<FeatureEvaluator>& evaluator, Point pt, double ...@@ -905,33 +904,33 @@ int CascadeClassifier::runAt( Ptr<FeatureEvaluator>& evaluator, Point pt, double
} }
} }
bool CascadeClassifier::setImage( Ptr<FeatureEvaluator>& evaluator, const Mat& image ) bool CascadeClassifierImpl::setImage( Ptr<FeatureEvaluator>& evaluator, const Mat& image )
{ {
return empty() ? false : evaluator->setImage(image, data.origWinSize); return empty() ? false : evaluator->setImage(image, data.origWinSize);
} }
void CascadeClassifier::setMaskGenerator(Ptr<MaskGenerator> _maskGenerator) void CascadeClassifierImpl::setMaskGenerator(const Ptr<MaskGenerator>& _maskGenerator)
{ {
maskGenerator=_maskGenerator; maskGenerator=_maskGenerator;
} }
Ptr<CascadeClassifier::MaskGenerator> CascadeClassifier::getMaskGenerator() Ptr<CascadeClassifierImpl::MaskGenerator> CascadeClassifierImpl::getMaskGenerator()
{ {
return maskGenerator; return maskGenerator;
} }
void CascadeClassifier::setFaceDetectionMaskGenerator() Ptr<CascadeClassifier::MaskGenerator> createFaceDetectionMaskGenerator()
{ {
#ifdef HAVE_TEGRA_OPTIMIZATION #ifdef HAVE_TEGRA_OPTIMIZATION
setMaskGenerator(tegra::getCascadeClassifierMaskGenerator(*this)); return tegra::getCascadeClassifierMaskGenerator(*this);
#else #else
setMaskGenerator(Ptr<CascadeClassifier::MaskGenerator>()); return Ptr<CascadeClassifierImpl::MaskGenerator>();
#endif #endif
} }
class CascadeClassifierInvoker : public ParallelLoopBody class CascadeClassifierInvoker : public ParallelLoopBody
{ {
public: 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<Rect>& _vec, std::vector<int>& _levels, std::vector<double>& _weights, bool outputLevels, const Mat& _mask, Mutex* _mtx) std::vector<Rect>& _vec, std::vector<int>& _levels, std::vector<double>& _weights, bool outputLevels, const Mat& _mask, Mutex* _mtx)
{ {
classifier = &_cc; classifier = &_cc;
...@@ -950,7 +949,8 @@ public: ...@@ -950,7 +949,8 @@ public:
{ {
Ptr<FeatureEvaluator> evaluator = classifier->featureEvaluator->clone(); Ptr<FeatureEvaluator> 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 y1 = range.start * stripSize;
int y2 = std::min(range.end * stripSize, processingRectSize.height); int y2 = std::min(range.end * stripSize, processingRectSize.height);
...@@ -995,7 +995,7 @@ public: ...@@ -995,7 +995,7 @@ public:
} }
} }
CascadeClassifier* classifier; CascadeClassifierImpl* classifier;
std::vector<Rect>* rectangles; std::vector<Rect>* rectangles;
Size processingRectSize; Size processingRectSize;
int stripSize, yStep; int stripSize, yStep;
...@@ -1010,7 +1010,7 @@ struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } } ...@@ -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; } }; 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<Rect>& candidates, int stripSize, int yStep, double factor, std::vector<Rect>& candidates,
std::vector<int>& levels, std::vector<double>& weights, bool outputRejectLevels ) std::vector<int>& levels, std::vector<double>& weights, bool outputRejectLevels )
{ {
...@@ -1051,27 +1051,33 @@ bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Siz ...@@ -1051,27 +1051,33 @@ bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Siz
return true; return true;
} }
bool CascadeClassifier::isOldFormatCascade() const bool CascadeClassifierImpl::isOldFormatCascade() const
{ {
return !oldCascade.empty(); return !oldCascade.empty();
} }
int CascadeClassifier::getFeatureType() const int CascadeClassifierImpl::getFeatureType() const
{ {
return featureEvaluator->getFeatureType(); return featureEvaluator->getFeatureType();
} }
Size CascadeClassifier::getOriginalWindowSize() const Size CascadeClassifierImpl::getOriginalWindowSize() const
{ {
return data.origWinSize; return data.origWinSize;
} }
bool CascadeClassifier::setImage(const Mat& image) bool CascadeClassifierImpl::setImage(InputArray _image)
{ {
Mat image = _image.getMat();
return featureEvaluator->setImage(image, data.origWinSize); return featureEvaluator->setImage(image, data.origWinSize);
} }
void* CascadeClassifierImpl::getOldCascade()
{
return oldCascade;
}
static void detectMultiScaleOldFormat( const Mat& image, Ptr<CvHaarClassifierCascade> oldCascade, static void detectMultiScaleOldFormat( const Mat& image, Ptr<CvHaarClassifierCascade> oldCascade,
std::vector<Rect>& objects, std::vector<Rect>& objects,
std::vector<int>& rejectLevels, std::vector<int>& rejectLevels,
...@@ -1090,7 +1096,7 @@ static void detectMultiScaleOldFormat( const Mat& image, Ptr<CvHaarClassifierCas ...@@ -1090,7 +1096,7 @@ static void detectMultiScaleOldFormat( const Mat& image, Ptr<CvHaarClassifierCas
std::transform(vecAvgComp.begin(), vecAvgComp.end(), objects.begin(), getRect()); std::transform(vecAvgComp.begin(), vecAvgComp.end(), objects.begin(), getRect());
} }
void CascadeClassifier::detectMultiScaleNoGrouping( const Mat& image, std::vector<Rect>& candidates, void CascadeClassifierImpl::detectMultiScaleNoGrouping( const Mat& image, std::vector<Rect>& candidates,
std::vector<int>& rejectLevels, std::vector<double>& levelWeights, std::vector<int>& rejectLevels, std::vector<double>& levelWeights,
double scaleFactor, Size minObjectSize, Size maxObjectSize, double scaleFactor, Size minObjectSize, Size maxObjectSize,
bool outputRejectLevels ) bool outputRejectLevels )
...@@ -1154,7 +1160,7 @@ void CascadeClassifier::detectMultiScaleNoGrouping( const Mat& image, std::vecto ...@@ -1154,7 +1160,7 @@ void CascadeClassifier::detectMultiScaleNoGrouping( const Mat& image, std::vecto
} }
} }
void CascadeClassifier::detectMultiScale( InputArray _image, std::vector<Rect>& objects, void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rect>& objects,
std::vector<int>& rejectLevels, std::vector<int>& rejectLevels,
std::vector<double>& levelWeights, std::vector<double>& levelWeights,
double scaleFactor, int minNeighbors, double scaleFactor, int minNeighbors,
...@@ -1189,7 +1195,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector<Rect>& ...@@ -1189,7 +1195,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector<Rect>&
} }
} }
void CascadeClassifier::detectMultiScale( InputArray _image, std::vector<Rect>& objects, void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rect>& objects,
double scaleFactor, int minNeighbors, double scaleFactor, int minNeighbors,
int flags, Size minObjectSize, Size maxObjectSize) int flags, Size minObjectSize, Size maxObjectSize)
{ {
...@@ -1200,7 +1206,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector<Rect>& ...@@ -1200,7 +1206,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector<Rect>&
minNeighbors, flags, minObjectSize, maxObjectSize ); minNeighbors, flags, minObjectSize, maxObjectSize );
} }
void CascadeClassifier::detectMultiScale( InputArray _image, std::vector<Rect>& objects, void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rect>& objects,
std::vector<int>& numDetections, double scaleFactor, std::vector<int>& numDetections, double scaleFactor,
int minNeighbors, int flags, Size minObjectSize, int minNeighbors, int flags, Size minObjectSize,
Size maxObjectSize ) Size maxObjectSize )
...@@ -1229,7 +1235,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector<Rect>& ...@@ -1229,7 +1235,7 @@ void CascadeClassifier::detectMultiScale( InputArray _image, std::vector<Rect>&
} }
} }
bool CascadeClassifier::Data::read(const FileNode &root) bool CascadeClassifierImpl::Data::read(const FileNode &root)
{ {
static const float THRESHOLD_EPS = 1e-5f; static const float THRESHOLD_EPS = 1e-5f;
...@@ -1339,7 +1345,7 @@ bool CascadeClassifier::Data::read(const FileNode &root) ...@@ -1339,7 +1345,7 @@ bool CascadeClassifier::Data::read(const FileNode &root)
return true; return true;
} }
bool CascadeClassifier::read(const FileNode& root) bool CascadeClassifierImpl::read_(const FileNode& root)
{ {
if( !data.read(root) ) if( !data.read(root) )
return false; return false;
...@@ -1356,4 +1362,106 @@ bool CascadeClassifier::read(const FileNode& root) ...@@ -1356,4 +1362,106 @@ bool CascadeClassifier::read(const FileNode& root)
template<> void DefaultDeleter<CvHaarClassifierCascade>::operator ()(CvHaarClassifierCascade* obj) const template<> void DefaultDeleter<CvHaarClassifierCascade>::operator ()(CvHaarClassifierCascade* obj) const
{ cvReleaseHaarClassifierCascade(&obj); } { 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<CascadeClassifierImpl>();
if(!cc->load(filename))
cc.release();
return !empty();
}
void CascadeClassifier::detectMultiScale( InputArray image,
CV_OUT std::vector<Rect>& 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<Rect>& objects,
CV_OUT std::vector<int>& 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<Rect>& objects,
CV_OUT std::vector<int>& rejectLevels,
CV_OUT std::vector<double>& 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>& maskGenerator)
{
CV_Assert(!empty());
cc->setMaskGenerator(maskGenerator);
}
Ptr<BaseCascadeClassifier::MaskGenerator> CascadeClassifier::getMaskGenerator()
{
CV_Assert(!empty());
return cc->getMaskGenerator();
}
} // namespace cv } // namespace cv
...@@ -3,6 +3,132 @@ ...@@ -3,6 +3,132 @@
namespace cv 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<Rect>& 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<Rect>& objects,
CV_OUT std::vector<int>& 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<Rect>& objects,
CV_OUT std::vector<int>& rejectLevels,
CV_OUT std::vector<double>& 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>& maskGenerator);
Ptr<MaskGenerator> getMaskGenerator();
protected:
bool detectSingleScale( const Mat& image, int stripCount, Size processingRectSize,
int stripSize, int yStep, double factor, std::vector<Rect>& candidates,
std::vector<int>& rejectLevels, std::vector<double>& levelWeights, bool outputRejectLevels = false );
void detectMultiScaleNoGrouping( const Mat& image, std::vector<Rect>& candidates,
std::vector<int>& rejectLevels, std::vector<double>& 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<class FEval>
friend int predictOrdered( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
template<class FEval>
friend int predictCategorical( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
template<class FEval>
friend int predictOrderedStump( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
template<class FEval>
friend int predictCategoricalStump( CascadeClassifierImpl& cascade, Ptr<FeatureEvaluator> &featureEvaluator, double& weight);
bool setImage( Ptr<FeatureEvaluator>& feval, const Mat& image);
int runAt( Ptr<FeatureEvaluator>& 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<Stage> stages;
std::vector<DTree> classifiers;
std::vector<DTreeNode> nodes;
std::vector<float> leaves;
std::vector<int> subsets;
};
Data data;
Ptr<FeatureEvaluator> featureEvaluator;
Ptr<CvHaarClassifierCascade> oldCascade;
Ptr<MaskGenerator> maskGenerator;
};
#define CC_CASCADE_PARAMS "cascadeParams" #define CC_CASCADE_PARAMS "cascadeParams"
#define CC_STAGE_TYPE "stageType" #define CC_STAGE_TYPE "stageType"
#define CC_FEATURE_TYPE "featureType" #define CC_FEATURE_TYPE "featureType"
...@@ -322,30 +448,31 @@ inline void HOGEvaluator::Feature :: updatePtrs( const std::vector<Mat> &_hist, ...@@ -322,30 +448,31 @@ inline void HOGEvaluator::Feature :: updatePtrs( const std::vector<Mat> &_hist,
//---------------------------------------------- predictor functions ------------------------------------- //---------------------------------------------- predictor functions -------------------------------------
template<class FEval> template<class FEval>
inline int predictOrdered( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum ) inline int predictOrdered( CascadeClassifierImpl& cascade,
Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
{ {
int nstages = (int)cascade.data.stages.size(); int nstages = (int)cascade.data.stages.size();
int nodeOfs = 0, leafOfs = 0; int nodeOfs = 0, leafOfs = 0;
FEval& featureEvaluator = (FEval&)*_featureEvaluator; FEval& featureEvaluator = (FEval&)*_featureEvaluator;
float* cascadeLeaves = &cascade.data.leaves[0]; float* cascadeLeaves = &cascade.data.leaves[0];
CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];
CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];
for( int si = 0; si < nstages; si++ ) for( int si = 0; si < nstages; si++ )
{ {
CascadeClassifier::Data::Stage& stage = cascadeStages[si]; CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si];
int wi, ntrees = stage.ntrees; int wi, ntrees = stage.ntrees;
sum = 0; sum = 0;
for( wi = 0; wi < ntrees; wi++ ) 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; int idx = 0, root = nodeOfs;
do do
{ {
CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx]; CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[root + idx];
double val = featureEvaluator(node.featureIdx); double val = featureEvaluator(node.featureIdx);
idx = val < node.threshold ? node.left : node.right; idx = val < node.threshold ? node.left : node.right;
} }
...@@ -361,7 +488,8 @@ inline int predictOrdered( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_f ...@@ -361,7 +488,8 @@ inline int predictOrdered( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_f
} }
template<class FEval> template<class FEval>
inline int predictCategorical( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum ) inline int predictCategorical( CascadeClassifierImpl& cascade,
Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
{ {
int nstages = (int)cascade.data.stages.size(); int nstages = (int)cascade.data.stages.size();
int nodeOfs = 0, leafOfs = 0; int nodeOfs = 0, leafOfs = 0;
...@@ -369,23 +497,23 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr<FeatureEvaluator> ...@@ -369,23 +497,23 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr<FeatureEvaluator>
size_t subsetSize = (cascade.data.ncategories + 31)/32; size_t subsetSize = (cascade.data.ncategories + 31)/32;
int* cascadeSubsets = &cascade.data.subsets[0]; int* cascadeSubsets = &cascade.data.subsets[0];
float* cascadeLeaves = &cascade.data.leaves[0]; float* cascadeLeaves = &cascade.data.leaves[0];
CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0]; CascadeClassifierImpl::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];
CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];
for(int si = 0; si < nstages; si++ ) for(int si = 0; si < nstages; si++ )
{ {
CascadeClassifier::Data::Stage& stage = cascadeStages[si]; CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si];
int wi, ntrees = stage.ntrees; int wi, ntrees = stage.ntrees;
sum = 0; sum = 0;
for( wi = 0; wi < ntrees; wi++ ) 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; int idx = 0, root = nodeOfs;
do do
{ {
CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx]; CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[root + idx];
int c = featureEvaluator(node.featureIdx); int c = featureEvaluator(node.featureIdx);
const int* subset = &cascadeSubsets[(root + idx)*subsetSize]; const int* subset = &cascadeSubsets[(root + idx)*subsetSize];
idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right; idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right;
...@@ -402,24 +530,25 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr<FeatureEvaluator> ...@@ -402,24 +530,25 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr<FeatureEvaluator>
} }
template<class FEval> template<class FEval>
inline int predictOrderedStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum ) inline int predictOrderedStump( CascadeClassifierImpl& cascade,
Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
{ {
int nodeOfs = 0, leafOfs = 0; int nodeOfs = 0, leafOfs = 0;
FEval& featureEvaluator = (FEval&)*_featureEvaluator; FEval& featureEvaluator = (FEval&)*_featureEvaluator;
float* cascadeLeaves = &cascade.data.leaves[0]; float* cascadeLeaves = &cascade.data.leaves[0];
CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];
int nstages = (int)cascade.data.stages.size(); int nstages = (int)cascade.data.stages.size();
for( int stageIdx = 0; stageIdx < nstages; stageIdx++ ) for( int stageIdx = 0; stageIdx < nstages; stageIdx++ )
{ {
CascadeClassifier::Data::Stage& stage = cascadeStages[stageIdx]; CascadeClassifierImpl::Data::Stage& stage = cascadeStages[stageIdx];
sum = 0.0; sum = 0.0;
int ntrees = stage.ntrees; int ntrees = stage.ntrees;
for( int i = 0; i < ntrees; i++, nodeOfs++, leafOfs+= 2 ) 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); double value = featureEvaluator(node.featureIdx);
sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ]; sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ];
} }
...@@ -432,7 +561,8 @@ inline int predictOrderedStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator ...@@ -432,7 +561,8 @@ inline int predictOrderedStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator
} }
template<class FEval> template<class FEval>
inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum ) inline int predictCategoricalStump( CascadeClassifierImpl& cascade,
Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
{ {
int nstages = (int)cascade.data.stages.size(); int nstages = (int)cascade.data.stages.size();
int nodeOfs = 0, leafOfs = 0; int nodeOfs = 0, leafOfs = 0;
...@@ -440,15 +570,15 @@ inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvalu ...@@ -440,15 +570,15 @@ inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvalu
size_t subsetSize = (cascade.data.ncategories + 31)/32; size_t subsetSize = (cascade.data.ncategories + 31)/32;
int* cascadeSubsets = &cascade.data.subsets[0]; int* cascadeSubsets = &cascade.data.subsets[0];
float* cascadeLeaves = &cascade.data.leaves[0]; float* cascadeLeaves = &cascade.data.leaves[0];
CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; CascadeClassifierImpl::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; CascadeClassifierImpl::Data::Stage* cascadeStages = &cascade.data.stages[0];
#ifdef HAVE_TEGRA_OPTIMIZATION #ifdef HAVE_TEGRA_OPTIMIZATION
float tmp = 0; // float accumulator -- float operations are quicker float tmp = 0; // float accumulator -- float operations are quicker
#endif #endif
for( int si = 0; si < nstages; si++ ) for( int si = 0; si < nstages; si++ )
{ {
CascadeClassifier::Data::Stage& stage = cascadeStages[si]; CascadeClassifierImpl::Data::Stage& stage = cascadeStages[si];
int wi, ntrees = stage.ntrees; int wi, ntrees = stage.ntrees;
#ifdef HAVE_TEGRA_OPTIMIZATION #ifdef HAVE_TEGRA_OPTIMIZATION
tmp = 0; tmp = 0;
...@@ -458,7 +588,7 @@ inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvalu ...@@ -458,7 +588,7 @@ inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvalu
for( wi = 0; wi < ntrees; wi++ ) for( wi = 0; wi < ntrees; wi++ )
{ {
CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs]; CascadeClassifierImpl::Data::DTreeNode& node = cascadeNodes[nodeOfs];
int c = featureEvaluator(node.featureIdx); int c = featureEvaluator(node.featureIdx);
const int* subset = &cascadeSubsets[nodeOfs*subsetSize]; const int* subset = &cascadeSubsets[nodeOfs*subsetSize];
#ifdef HAVE_TEGRA_OPTIMIZATION #ifdef HAVE_TEGRA_OPTIMIZATION
......
...@@ -655,7 +655,7 @@ void OclCascadeClassifier::detectMultiScale(oclMat &gimg, CV_OUT std::vector<cv: ...@@ -655,7 +655,7 @@ void OclCascadeClassifier::detectMultiScale(oclMat &gimg, CV_OUT std::vector<cv:
//CvSeq *cv::ocl::OclCascadeClassifier::oclHaarDetectObjects( oclMat &gimg, CvMemStorage *storage, double scaleFactor, //CvSeq *cv::ocl::OclCascadeClassifier::oclHaarDetectObjects( oclMat &gimg, CvMemStorage *storage, double scaleFactor,
// int minNeighbors, int flags, CvSize minSize, CvSize maxSize) // int minNeighbors, int flags, CvSize minSize, CvSize maxSize)
{ {
CvHaarClassifierCascade *cascade = oldCascade; CvHaarClassifierCascade *cascade = (CvHaarClassifierCascade*)getOldCascade();
const double GROUP_EPS = 0.2; const double GROUP_EPS = 0.2;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment