Reverted back to the previous method where a public method groupRectangles was added...
authorBahram Dahi <xivxix@gmail.com>
Fri, 24 May 2013 22:25:23 +0000 (18:25 -0400)
committerBahram Dahi <xivxix@gmail.com>
Fri, 24 May 2013 22:25:23 +0000 (18:25 -0400)
modules/objdetect/include/opencv2/objdetect/objdetect.hpp
modules/objdetect/src/cascadedetect.cpp
modules/objdetect/src/hog.cpp

index 8d7efb0..d5d6f0b 100644 (file)
@@ -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;
 };
 
 
index 46a232e..de46a68 100644 (file)
@@ -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() )
index 0ed9bbc..9e5fd1b 100644 (file)
@@ -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);
+        }
+    }
+}
 }