diff --git a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp index 156fa87b6e..ad5b81f984 100644 --- a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp @@ -64,7 +64,7 @@ extern "C" { typedef struct CvHaarFeature { - int tilted; + int tilted; struct { CvRect r; @@ -328,16 +328,16 @@ public: CV_WRAP bool load(const string& filename); bool read(const FileNode& node); CV_WRAP void detectMultiScale( const Mat& image, - CV_OUT vector& objects, - double scaleFactor=1.1, - int minNeighbors=3, int flags=0, - Size minSize=Size(), - Size maxSize=Size()); + CV_OUT vector& objects, + double scaleFactor=1.1, + int minNeighbors=3, int flags=0, + Size minSize=Size(), + Size maxSize=Size()); bool setImage( Ptr&, const Mat& ); int runAt( Ptr&, Point ); - bool is_stump_based; + bool isStumpBased; int stageType; int featureType; diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp index 2510408c6d..224f89e1ea 100644 --- a/modules/objdetect/src/cascadedetect.cpp +++ b/modules/objdetect/src/cascadedetect.cpp @@ -717,26 +717,30 @@ inline int predictCategorical( CascadeClassifier& cascade, Ptr template inline int predictOrderedStump( CascadeClassifier& cascade, Ptr &_feval ) { - int si, nstages = (int)cascade.stages.size(); int nodeOfs = 0, leafOfs = 0; FEval& feval = (FEval&)*_feval; float* cascadeLeaves = &cascade.leaves[0]; CascadeClassifier::DTreeNode* cascadeNodes = &cascade.nodes[0]; CascadeClassifier::Stage* cascadeStages = &cascade.stages[0]; - for( si = 0; si < nstages; si++ ) + + int nstages = (int)cascade.stages.size(); + for( int stageIdx = 0; stageIdx < nstages; stageIdx++ ) { - CascadeClassifier::Stage& stage = cascadeStages[si]; - int wi, ntrees = stage.ntrees; - double sum = 0; - for( wi = 0; wi < ntrees; wi++, nodeOfs++, leafOfs+= 2 ) + CascadeClassifier::Stage& stage = cascadeStages[stageIdx]; + double sum = 0.0; + + int ntrees = stage.ntrees; + for( int i = 0; i < ntrees; i++, nodeOfs++, leafOfs+= 2 ) { CascadeClassifier::DTreeNode& node = cascadeNodes[nodeOfs]; - double val = feval(node.featureIdx); - sum += cascadeLeaves[ val < node.threshold ? leafOfs : leafOfs+1 ]; + double value = feval(node.featureIdx); + sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ]; } + if( sum < stage.threshold ) - return -si; + return -stageIdx; } + return 1; } @@ -773,7 +777,7 @@ inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr &_feval, Point pt ) +int CascadeClassifier::runAt( Ptr& featureEvaluator, Point pt ) { CV_Assert( oldCascade.empty() ); /*if( !oldCascade.empty() ) @@ -781,17 +785,17 @@ int CascadeClassifier::runAt( Ptr &_feval, Point pt ) assert(featureType == FeatureEvaluator::HAAR || featureType == FeatureEvaluator::LBP); - return !_feval->setWindow(pt) ? -1 : - is_stump_based ? ( featureType == FeatureEvaluator::HAAR ? - predictOrderedStump( *this, _feval ) : - predictCategoricalStump( *this, _feval ) ) : + + return !featureEvaluator->setWindow(pt) ? -1 : + isStumpBased ? ( featureType == FeatureEvaluator::HAAR ? + predictOrderedStump( *this, featureEvaluator ) : + predictCategoricalStump( *this, featureEvaluator ) ) : ( featureType == FeatureEvaluator::HAAR ? - predictOrdered( *this, _feval ) : - predictCategorical( *this, _feval ) ); + predictOrdered( *this, featureEvaluator ) : + predictCategorical( *this, featureEvaluator ) ); } - -bool CascadeClassifier::setImage( Ptr &_feval, const Mat& image ) +bool CascadeClassifier::setImage( Ptr& featureEvaluator, const Mat& image ) { /*if( !oldCascade.empty() ) { @@ -803,45 +807,48 @@ bool CascadeClassifier::setImage( Ptr &_feval, const Mat& imag cvSetImagesForHaarClassifierCascade( oldCascade, &_sum, &_sqsum, &_tilted, 1. ); return true; }*/ - return empty() ? false : _feval->setImage(image, origWinSize ); + return empty() ? false : featureEvaluator->setImage(image, origWinSize); } - + struct CascadeClassifierInvoker { CascadeClassifierInvoker( CascadeClassifier& _cc, Size _sz1, int _stripSize, int _yStep, double _factor, ConcurrentRectVector& _vec ) { - cc = &_cc; - sz1 = _sz1; + classifier = &_cc; + processingAreaSize = _sz1; stripSize = _stripSize; yStep = _yStep; - factor = _factor; - vec = &_vec; + scalingFactor = _factor; + rectangles = &_vec; } void operator()(const BlockedRange& range) const { - Ptr feval = cc->feval->clone(); - int y1 = range.begin()*stripSize, y2 = min(range.end()*stripSize, sz1.height); - Size winSize(cvRound(cc->origWinSize.width*factor), cvRound(cc->origWinSize.height*factor)); - + Ptr evaluator = classifier->feval->clone(); + Size winSize(cvRound(classifier->origWinSize.width * scalingFactor), cvRound(classifier->origWinSize.height * scalingFactor)); + + int y1 = range.begin() * stripSize; + int y2 = min(range.end() * stripSize, processingAreaSize.height); for( int y = y1; y < y2; y += yStep ) - for( int x = 0; x < sz1.width; x += yStep ) + { + for( int x = 0; x < processingAreaSize.width; x += yStep ) { - int r = cc->runAt(feval, Point(x, y)); - if( r > 0 ) - vec->push_back(Rect(cvRound(x*factor), cvRound(y*factor), - winSize.width, winSize.height)); - if( r == 0 ) + int result = classifier->runAt(evaluator, Point(x, y)); + if( result > 0 ) + rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), + winSize.width, winSize.height)); + if( result == 0 ) x += yStep; } + } } - CascadeClassifier* cc; - Size sz1; + CascadeClassifier* classifier; + ConcurrentRectVector* rectangles; + Size processingAreaSize; int stripSize, yStep; - double factor; - ConcurrentRectVector* vec; + double scalingFactor; }; @@ -849,7 +856,7 @@ struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } } void CascadeClassifier::detectMultiScale( const Mat& image, vector& objects, double scaleFactor, int minNeighbors, - int flags, Size minSize, Size maxSize ) + int flags, Size minObjectSize, Size maxObjectSize ) { const double GROUP_EPS = 0.2; @@ -863,7 +870,7 @@ void CascadeClassifier::detectMultiScale( const Mat& image, vector& object MemStorage storage(cvCreateMemStorage(0)); CvMat _image = image; CvSeq* _objects = cvHaarDetectObjects( &_image, oldCascade, storage, scaleFactor, - minNeighbors, flags, minSize ); + minNeighbors, flags, minObjectSize ); vector vecAvgComp; Seq(_objects).copyTo(vecAvgComp); objects.resize(vecAvgComp.size()); @@ -871,57 +878,60 @@ void CascadeClassifier::detectMultiScale( const Mat& image, vector& object return; } - if( maxSize.height == 0 || maxSize.width == 0 ) - maxSize = image.size(); - objects.clear(); + + if( maxObjectSize.height == 0 || maxObjectSize.width == 0 ) + maxObjectSize = image.size(); - Mat img = image, imgbuf(image.rows+1, image.cols+1, CV_8U); - - if( img.channels() > 1 ) + Mat grayImage = image; + if( grayImage.channels() > 1 ) { Mat temp; - cvtColor(img, temp, CV_BGR2GRAY); - img = temp; + cvtColor(grayImage, temp, CV_BGR2GRAY); + grayImage = temp; } - ConcurrentRectVector allCandidates; + Mat imageBuffer(image.rows + 1, image.cols + 1, CV_8U); + ConcurrentRectVector candidates; for( double factor = 1; ; factor *= scaleFactor ) { int stripCount, stripSize; - Size winSize( cvRound(origWinSize.width*factor), cvRound(origWinSize.height*factor) ); - Size sz( cvRound( img.cols/factor ), cvRound( img.rows/factor ) ); - Size sz1( sz.width - origWinSize.width, sz.height - origWinSize.height ); + + Size windowSize( cvRound(origWinSize.width*factor), cvRound(origWinSize.height*factor) ); + Size scaledImageSize( cvRound( grayImage.cols/factor ), cvRound( grayImage.rows/factor ) ); + Size processingAreaSize( scaledImageSize.width - origWinSize.width, scaledImageSize.height - origWinSize.height ); - if( sz1.width <= 0 || sz1.height <= 0 ) + if( processingAreaSize.width <= 0 || processingAreaSize.height <= 0 ) break; - if( winSize.width > maxSize.width || winSize.height > maxSize.height ) + if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height ) break; - if( winSize.width < minSize.width || winSize.height < minSize.height ) + if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height ) continue; int yStep = factor > 2. ? 1 : 2; + #ifdef HAVE_TBB const int PTS_PER_THREAD = 1000; - stripCount = ((sz1.width/yStep)*(sz1.height + yStep-1)/yStep + PTS_PER_THREAD/2)/PTS_PER_THREAD; + stripCount = ((processingAreaSize.width/yStep)*(processingAreaSize.height + yStep-1)/yStep + PTS_PER_THREAD/2)/PTS_PER_THREAD; stripCount = std::min(std::max(stripCount, 1), 100); - stripSize = (((sz1.height + stripCount - 1)/stripCount + yStep-1)/yStep)*yStep; + stripSize = (((processingAreaSize.height + stripCount - 1)/stripCount + yStep-1)/yStep)*yStep; #else stripCount = 1; - stripSize = sz1.height; + stripSize = processingAreaSize.height; #endif - Mat img1( sz, CV_8U, imgbuf.data ); - resize( img, img1, sz, 0, 0, CV_INTER_LINEAR ); - if( !feval->setImage( img1, origWinSize ) ) + Mat scaledImage( scaledImageSize, CV_8U, imageBuffer.data ); + resize( grayImage, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR ); + if( !feval->setImage( scaledImage, origWinSize ) ) break; - parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker(*this, sz1, stripSize, yStep, factor, allCandidates)); + parallel_for(BlockedRange(0, stripCount), CascadeClassifierInvoker(*this, processingAreaSize, stripSize, yStep, factor, candidates)); } - objects.resize(allCandidates.size()); - std::copy(allCandidates.begin(), allCandidates.end(), objects.begin()); + objects.resize(candidates.size()); + std::copy(candidates.begin(), candidates.end(), objects.begin()); + groupRectangles( objects, minNeighbors, GROUP_EPS ); } @@ -947,7 +957,7 @@ bool CascadeClassifier::read(const FileNode& root) origWinSize.height = (int)root[CC_HEIGHT]; CV_Assert( origWinSize.height > 0 && origWinSize.width > 0 ); - is_stump_based = (int)(root[CC_STAGE_PARAMS][CC_MAX_DEPTH]) == 1 ? true : false; + isStumpBased = (int)(root[CC_STAGE_PARAMS][CC_MAX_DEPTH]) == 1 ? true : false; // load feature params FileNode fn = root[CC_FEATURE_PARAMS]; diff --git a/modules/objdetect/src/haar.cpp b/modules/objdetect/src/haar.cpp index def50a8ce1..f52dd34fc9 100644 --- a/modules/objdetect/src/haar.cpp +++ b/modules/objdetect/src/haar.cpp @@ -112,7 +112,7 @@ CvHidHaarStageClassifier; struct CvHidHaarClassifierCascade { int count; - int is_stump_based; + int isStumpBased; int has_tilted_features; int is_tree; double inv_window_area; @@ -272,7 +272,7 @@ icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade ) haar_classifier_ptr = (CvHidHaarClassifier*)(out->stage_classifier + cascade->count); haar_node_ptr = (CvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers); - out->is_stump_based = 1; + out->isStumpBased = 1; out->has_tilted_features = has_tilted_features; out->is_tree = 0; @@ -329,12 +329,12 @@ icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade ) haar_node_ptr = (CvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*)); - out->is_stump_based &= node_count == 1; + out->isStumpBased &= node_count == 1; } } #ifdef HAVE_IPP - int can_use_ipp = !out->has_tilted_features && !out->is_tree && out->is_stump_based; + int can_use_ipp = !out->has_tilted_features && !out->is_tree && out->isStumpBased; if( can_use_ipp ) { @@ -719,7 +719,7 @@ cvRunHaarClassifierCascade( const CvHaarClassifierCascade* _cascade, } } } - else if( cascade->is_stump_based ) + else if( cascade->isStumpBased ) { for( i = start_stage; i < cascade->count; i++ ) {