From dcad6ce65afa7eab3242fcfe1607998c6ed56772 Mon Sep 17 00:00:00 2001 From: Bahram Dahi <xivxix@gmail.com> Date: Fri, 24 May 2013 18:25:23 -0400 Subject: [PATCH] Reverted back to the previous method where a public method groupRectangles was added to HOGDescriptor to take care of ROI and weight grouping --- .../include/opencv2/objdetect/objdetect.hpp | 54 ++++++++---- modules/objdetect/src/cascadedetect.cpp | 18 ---- modules/objdetect/src/hog.cpp | 82 ++++++++++++++++++- 3 files changed, 115 insertions(+), 39 deletions(-) diff --git a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp index 8d7efb0ba..d5d6f0b24 100644 --- a/modules/objdetect/include/opencv2/objdetect/objdetect.hpp +++ b/modules/objdetect/include/opencv2/objdetect/objdetect.hpp @@ -192,12 +192,12 @@ typedef struct CvLSVMFilterObject{ // data type: STRUCT CvLatentSvmDetector // structure contains internal representation of trained Latent SVM detector -// num_filters - total number of filters (root plus part) in model -// num_components - number of components in model -// num_part_filters - array containing number of part filters for each component -// filters - root and part filters for all model components -// b - biases for all model components -// score_threshold - confidence level threshold +// num_filters - total number of filters (root plus part) in model +// num_components - number of components in model +// num_part_filters - array containing number of part filters for each component +// filters - root and part filters for all model components +// b - biases for all model components +// score_threshold - confidence level threshold typedef struct CvLatentSvmDetector { int num_filters; @@ -211,8 +211,8 @@ CvLatentSvmDetector; // data type: STRUCT CvObjectDetection // structure contains the bounding box and confidence level for detected object -// rect - bounding box for a detected object -// score - confidence level +// rect - bounding box for a detected object +// score - confidence level typedef struct CvObjectDetection { CvRect rect; @@ -228,7 +228,7 @@ typedef struct CvObjectDetection // API // CvLatentSvmDetector* cvLoadLatentSvmDetector(const char* filename); // INPUT -// filename - path to the file containing the parameters of +// filename - path to the file containing the parameters of - trained Latent SVM detector // OUTPUT // trained Latent SVM detector in internal representation @@ -241,7 +241,7 @@ CVAPI(CvLatentSvmDetector*) cvLoadLatentSvmDetector(const char* filename); // API // void cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector); // INPUT -// detector - CvLatentSvmDetector structure to be released +// detector - CvLatentSvmDetector structure to be released // OUTPUT */ CVAPI(void) cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector); @@ -252,16 +252,16 @@ CVAPI(void) cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector); // // API // CvSeq* cvLatentSvmDetectObjects(const IplImage* image, -// CvLatentSvmDetector* detector, -// CvMemStorage* storage, -// float overlap_threshold = 0.5f, +// CvLatentSvmDetector* detector, +// CvMemStorage* storage, +// float overlap_threshold = 0.5f, // int numThreads = -1); // INPUT -// image - image to detect objects in -// detector - Latent SVM detector in internal representation -// storage - memory storage to store the resultant sequence -// of the object candidate rectangles -// overlap_threshold - threshold for the non-maximum suppression algorithm +// image - image to detect objects in +// detector - Latent SVM detector in internal representation +// storage - memory storage to store the resultant sequence +// of the object candidate rectangles +// overlap_threshold - threshold for the non-maximum suppression algorithm = 0.5f [here will be the reference to original paper] // OUTPUT // sequence of detected objects (bounding boxes and confidence levels stored in CvObjectDetection structures) @@ -327,6 +327,23 @@ private: vector<string> classNames; }; +// class for grouping object candidates, detected by Cascade Classifier, HOG etc. +// instance of the class is to be passed to cv::partition (see cxoperations.hpp) +class CV_EXPORTS SimilarRects +{ +public: + SimilarRects(double _eps) : eps(_eps) {} + inline bool operator()(const Rect& r1, const Rect& r2) const + { + double delta = eps*(std::min(r1.width, r2.width) + std::min(r1.height, r2.height))*0.5; + return std::abs(r1.x - r2.x) <= delta && + std::abs(r1.y - r2.y) <= delta && + std::abs(r1.x + r1.width - r2.x - r2.width) <= delta && + std::abs(r1.y + r1.height - r2.y - r2.height) <= delta; + } + double eps; +}; + CV_EXPORTS void groupRectangles(CV_OUT CV_IN_OUT vector<Rect>& rectList, int groupThreshold, double eps=0.2); CV_EXPORTS_W void groupRectangles(CV_OUT CV_IN_OUT vector<Rect>& rectList, CV_OUT vector<int>& weights, int groupThreshold, double eps=0.2); CV_EXPORTS void groupRectangles( vector<Rect>& rectList, int groupThreshold, double eps, vector<int>* weights, vector<double>* levelWeights ); @@ -611,6 +628,7 @@ public: // read/parse Dalal's alt model file void readALTModel(std::string modelfile); + void groupRectangles(vector<cv::Rect>& rectList, vector<double>& weights, int groupThreshold, double eps) const; }; diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp index 46a232ed6..de46a6899 100644 --- a/modules/objdetect/src/cascadedetect.cpp +++ b/modules/objdetect/src/cascadedetect.cpp @@ -114,24 +114,6 @@ struct Logger namespace cv { -// class for grouping object candidates, detected by Cascade Classifier, HOG etc. -// instance of the class is to be passed to cv::partition (see cxoperations.hpp) -class CV_EXPORTS SimilarRects -{ -public: - SimilarRects(double _eps) : eps(_eps) {} - inline bool operator()(const Rect& r1, const Rect& r2) const - { - double delta = eps*(std::min(r1.width, r2.width) + std::min(r1.height, r2.height))*0.5; - return std::abs(r1.x - r2.x) <= delta && - std::abs(r1.y - r2.y) <= delta && - std::abs(r1.x + r1.width - r2.x - r2.width) <= delta && - std::abs(r1.y + r1.height - r2.y - r2.height) <= delta; - } - double eps; -}; - - void groupRectangles(vector<Rect>& rectList, int groupThreshold, double eps, vector<int>* weights, vector<double>* levelWeights) { if( groupThreshold <= 0 || rectList.empty() ) diff --git a/modules/objdetect/src/hog.cpp b/modules/objdetect/src/hog.cpp index 0ed9bbca4..9e5fd1ba5 100644 --- a/modules/objdetect/src/hog.cpp +++ b/modules/objdetect/src/hog.cpp @@ -1060,9 +1060,7 @@ void HOGDescriptor::detectMultiScale( } else { - vector<int> dummy; - dummy.resize(foundLocations.size(), INT_MAX); - groupRectangles(foundLocations, (int)finalThreshold, 0.2, &dummy, &foundWeights); + groupRectangles(foundLocations, foundWeights, (int)finalThreshold, 0.2); } } @@ -2636,4 +2634,82 @@ void HOGDescriptor::readALTModel(std::string modelfile) fclose(modelfl); } +void HOGDescriptor::groupRectangles(vector<cv::Rect>& rectList, vector<double>& weights, int groupThreshold, double eps) const +{ + if( groupThreshold <= 0 || rectList.empty() ) + { + return; + } + + CV_Assert(rectList.size() == weights.size()); + + vector<int> labels; + int nclasses = partition(rectList, labels, SimilarRects(eps)); + + vector<cv::Rect_<double>> rrects(nclasses); + vector<int> numInClass(nclasses, 0); + vector<double> foundWeights(nclasses, DBL_MIN); + vector<double> totalFactorsPerClass(nclasses, 1); + int i, j, nlabels = (int)labels.size(); + + for( i = 0; i < nlabels; i++ ) + { + int cls = labels[i]; + rrects[cls].x += rectList[i].x; + rrects[cls].y += rectList[i].y; + rrects[cls].width += rectList[i].width; + rrects[cls].height += rectList[i].height; + foundWeights[cls] = max(foundWeights[cls], weights[i]); + numInClass[cls]++; + } + + for( i = 0; i < nclasses; i++ ) + { + // find the average of all ROI in the cluster + cv::Rect_<double> r = rrects[i]; + float s = 1.f/numInClass[i]; + rrects[i] = cv::Rect_<double>(cv::saturate_cast<double>(r.x*s), + cv::saturate_cast<double>(r.y*s), + cv::saturate_cast<double>(r.width*s), + cv::saturate_cast<double>(r.height*s)); + } + + rectList.clear(); + weights.clear(); + + for( i = 0; i < nclasses; i++ ) + { + cv::Rect r1 = rrects[i]; + int n1 = numInClass[i]; + double w1 = foundWeights[i]; + if( n1 <= groupThreshold ) + continue; + // filter out small rectangles inside large rectangles + for( j = 0; j < nclasses; j++ ) + { + int n2 = numInClass[j]; + + if( j == i || n2 <= groupThreshold ) + continue; + + cv::Rect r2 = rrects[j]; + + int dx = cv::saturate_cast<int>( r2.width * eps ); + int dy = cv::saturate_cast<int>( r2.height * eps ); + + if( r1.x >= r2.x - dx && + r1.y >= r2.y - dy && + r1.x + r1.width <= r2.x + r2.width + dx && + r1.y + r1.height <= r2.y + r2.height + dy && + (n2 > std::max(3, n1) || n1 < 3) ) + break; + } + + if( j == nclasses ) + { + rectList.push_back(r1); + weights.push_back(w1); + } + } +} }