From 630288fdef125b53c7220d7d39546401d92f89ac Mon Sep 17 00:00:00 2001 From: Leonid Beynenson Date: Wed, 5 Oct 2011 13:21:28 +0000 Subject: [PATCH] Added possibility of prefiltering into CascadeClassifier. Now OpenCV users can implement their own mask generators and insert them into CascadeClassifier. --- .../include/opencv2/objdetect/objdetect.hpp | 12 +++++ modules/objdetect/src/cascadedetect.cpp | 52 +++++++++++++------ 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp index 2d08dcc48b..126e6210c1 100644 --- a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp @@ -468,6 +468,18 @@ protected: Data data; Ptr featureEvaluator; Ptr oldCascade; + +public: + class MaskGenerator + { + public: + virtual cv::Mat generateMask(const cv::Mat& src)=0; + }; + void setMaskGenerator(Ptr maskGenerator); + Ptr getMaskGenerator(); +protected: + Ptr maskGenerator; + Ptr getDefaultMaskGenerator(); }; diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp index f71e9bf88c..5d67764c74 100644 --- a/modules/objdetect/src/cascadedetect.cpp +++ b/modules/objdetect/src/cascadedetect.cpp @@ -787,10 +787,14 @@ Ptr FeatureEvaluator::create( int featureType ) CascadeClassifier::CascadeClassifier() { + maskGenerator=getDefaultMaskGenerator(); } CascadeClassifier::CascadeClassifier(const string& filename) -{ load(filename); } +{ + load(filename); + maskGenerator=getDefaultMaskGenerator(); +} CascadeClassifier::~CascadeClassifier() { @@ -859,12 +863,29 @@ bool CascadeClassifier::setImage( Ptr& featureEvaluator, const return empty() ? false : featureEvaluator->setImage(image, data.origWinSize); } +void CascadeClassifier::setMaskGenerator(Ptr _maskGenerator) +{ + maskGenerator=_maskGenerator; +} +Ptr CascadeClassifier::getMaskGenerator() +{ + return maskGenerator; +} + +Ptr CascadeClassifier::getDefaultMaskGenerator() +{ +#ifdef HAVE_TEGRA_OPTIMIZATION + return tegra::getCascadeClassifierMaskGenerator(*this); +#else + return Ptr(); +#endif +} + struct CascadeClassifierInvoker { - CascadeClassifierInvoker( const Mat& _image, CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, - ConcurrentRectVector& _vec, vector& _levels, vector& _weights, bool outputLevels = false ) + CascadeClassifierInvoker( CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, + ConcurrentRectVector& _vec, vector& _levels, vector& _weights, bool outputLevels, const Mat& _mask) { - image=_image; classifier = &_cc; processingRectSize = _sz1; stripSize = _stripSize; @@ -873,15 +894,13 @@ struct CascadeClassifierInvoker rectangles = &_vec; rejectLevels = outputLevels ? &_levels : 0; levelWeights = outputLevels ? &_weights : 0; + mask=_mask; } void operator()(const BlockedRange& range) const { Ptr evaluator = classifier->featureEvaluator->clone(); -#ifdef HAVE_TEGRA_OPTIMIZATION - Mat currentMask=tegra::getCascadeClassifierMask(image, classifier->data.origWinSize); -#endif Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), cvRound(classifier->data.origWinSize.height * scalingFactor)); int y1 = range.begin() * stripSize; @@ -890,11 +909,9 @@ struct CascadeClassifierInvoker { for( int x = 0; x < processingRectSize.width; x += yStep ) { -#ifdef HAVE_TEGRA_OPTIMIZATION - if ( (!currentMask.empty()) && (currentMask.at(Point(x,y))==0)) { + if ( (!mask.empty()) && (mask.at(Point(x,y))==0)) { continue; } -#endif double gypWeight; int result = classifier->runAt(evaluator, Point(x, y), gypWeight); @@ -918,7 +935,6 @@ struct CascadeClassifierInvoker } } - Mat image; CascadeClassifier* classifier; ConcurrentRectVector* rectangles; Size processingRectSize; @@ -926,6 +942,7 @@ struct CascadeClassifierInvoker double scalingFactor; vector *rejectLevels; vector *levelWeights; + Mat mask; }; struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } }; @@ -937,20 +954,25 @@ bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Siz if( !featureEvaluator->setImage( image, data.origWinSize ) ) return false; + Mat currentMask; + if (!maskGenerator.empty()) { + currentMask=maskGenerator->generateMask(image); + } + ConcurrentRectVector concurrentCandidates; vector rejectLevels; vector levelWeights; if( outputRejectLevels ) { - parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( image, *this, processingRectSize, stripSize, yStep, factor, - concurrentCandidates, rejectLevels, levelWeights, true)); + parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor, + concurrentCandidates, rejectLevels, levelWeights, true, currentMask)); levels.insert( levels.end(), rejectLevels.begin(), rejectLevels.end() ); weights.insert( weights.end(), levelWeights.begin(), levelWeights.end() ); } else { - parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( image, *this, processingRectSize, stripSize, yStep, factor, - concurrentCandidates, rejectLevels, levelWeights, false)); + parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor, + concurrentCandidates, rejectLevels, levelWeights, false, currentMask)); } candidates.insert( candidates.end(), concurrentCandidates.begin(), concurrentCandidates.end() );