// 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;
// 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;
// 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
// API
// void cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector);
// INPUT
-// detector - CvLatentSvmDetector structure to be released
+// detector - CvLatentSvmDetector structure to be released
// OUTPUT
*/
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)
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 );
// 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;
};
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() )
}
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);
}
}
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);
+ }
+ }
+}
}