Add OpenCV source code
[platform/upstream/opencv.git] / modules / objdetect / src / latentsvmdetector.cpp
1 #include "precomp.hpp"
2 #include "_lsvmparser.h"
3 #include "_lsvm_matching.h"
4
5 /*
6 // load trained detector from a file
7 //
8 // API
9 // CvLatentSvmDetector* cvLoadLatentSvmDetector(const char* filename);
10 // INPUT
11 // filename             - path to the file containing the parameters of
12 //                      - trained Latent SVM detector
13 // OUTPUT
14 // trained Latent SVM detector in internal representation
15 */
16 CvLatentSvmDetector* cvLoadLatentSvmDetector(const char* filename)
17 {
18     CvLatentSvmDetector* detector = 0;
19     CvLSVMFilterObject** filters = 0;
20     int kFilters = 0;
21     int kComponents = 0;
22     int* kPartFilters = 0;
23     float* b = 0;
24     float scoreThreshold = 0.f;
25     int err_code = 0;
26
27     err_code = loadModel(filename, &filters, &kFilters, &kComponents, &kPartFilters, &b, &scoreThreshold);
28     if (err_code != LATENT_SVM_OK) return 0;
29
30     detector = (CvLatentSvmDetector*)malloc(sizeof(CvLatentSvmDetector));
31     detector->filters = filters;
32     detector->b = b;
33     detector->num_components = kComponents;
34     detector->num_filters = kFilters;
35     detector->num_part_filters = kPartFilters;
36     detector->score_threshold = scoreThreshold;
37
38     return detector;
39 }
40
41 /*
42 // release memory allocated for CvLatentSvmDetector structure
43 //
44 // API
45 // void cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector);
46 // INPUT
47 // detector             - CvLatentSvmDetector structure to be released
48 // OUTPUT
49 */
50 void cvReleaseLatentSvmDetector(CvLatentSvmDetector** detector)
51 {
52     free((*detector)->b);
53     free((*detector)->num_part_filters);
54     for (int i = 0; i < (*detector)->num_filters; i++)
55     {
56         free((*detector)->filters[i]->H);
57         free((*detector)->filters[i]);
58     }
59     free((*detector)->filters);
60     free((*detector));
61     *detector = 0;
62 }
63
64 /*
65 // find rectangular regions in the given image that are likely
66 // to contain objects and corresponding confidence levels
67 //
68 // API
69 // CvSeq* cvLatentSvmDetectObjects(const IplImage* image,
70 //                                  CvLatentSvmDetector* detector,
71 //                                  CvMemStorage* storage,
72 //                                  float overlap_threshold = 0.5f,
73                                     int numThreads = -1);
74 // INPUT
75 // image                - image to detect objects in
76 // detector             - Latent SVM detector in internal representation
77 // storage              - memory storage to store the resultant sequence
78 //                          of the object candidate rectangles
79 // overlap_threshold    - threshold for the non-maximum suppression algorithm [here will be the reference to original paper]
80 // OUTPUT
81 // sequence of detected objects (bounding boxes and confidence levels stored in CvObjectDetection structures)
82 */
83 CvSeq* cvLatentSvmDetectObjects(IplImage* image,
84                                 CvLatentSvmDetector* detector,
85                                 CvMemStorage* storage,
86                                 float overlap_threshold, int numThreads)
87 {
88     CvLSVMFeaturePyramid *H = 0;
89     CvPoint *points = 0, *oppPoints = 0;
90     int kPoints = 0;
91     float *score = 0;
92     unsigned int maxXBorder = 0, maxYBorder = 0;
93     int numBoxesOut = 0;
94     CvPoint *pointsOut = 0;
95     CvPoint *oppPointsOut = 0;
96     float *scoreOut = 0;
97     CvSeq* result_seq = 0;
98     int error = 0;
99
100     if(image->nChannels == 3)
101         cvCvtColor(image, image, CV_BGR2RGB);
102
103     // Getting maximum filter dimensions
104     getMaxFilterDims((const CvLSVMFilterObject**)(detector->filters), detector->num_components,
105                      detector->num_part_filters, &maxXBorder, &maxYBorder);
106     // Create feature pyramid with nullable border
107     H = createFeaturePyramidWithBorder(image, maxXBorder, maxYBorder);
108     // Search object
109     error = searchObjectThresholdSomeComponents(H, (const CvLSVMFilterObject**)(detector->filters),
110         detector->num_components, detector->num_part_filters, detector->b, detector->score_threshold,
111         &points, &oppPoints, &score, &kPoints, numThreads);
112     if (error != LATENT_SVM_OK)
113     {
114         return NULL;
115     }
116     // Clipping boxes
117     clippingBoxes(image->width, image->height, points, kPoints);
118     clippingBoxes(image->width, image->height, oppPoints, kPoints);
119     // NMS procedure
120     nonMaximumSuppression(kPoints, points, oppPoints, score, overlap_threshold,
121                 &numBoxesOut, &pointsOut, &oppPointsOut, &scoreOut);
122
123     result_seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvObjectDetection), storage );
124
125     for (int i = 0; i < numBoxesOut; i++)
126     {
127         CvObjectDetection detection = {{0, 0, 0, 0}, 0};
128         detection.score = scoreOut[i];
129         CvRect bounding_box = {0, 0, 0, 0};
130         bounding_box.x = pointsOut[i].x;
131         bounding_box.y = pointsOut[i].y;
132         bounding_box.width = oppPointsOut[i].x - pointsOut[i].x;
133         bounding_box.height = oppPointsOut[i].y - pointsOut[i].y;
134         detection.rect = bounding_box;
135         cvSeqPush(result_seq, &detection);
136     }
137
138     if(image->nChannels == 3)
139         cvCvtColor(image, image, CV_RGB2BGR);
140
141     freeFeaturePyramidObject(&H);
142     free(points);
143     free(oppPoints);
144     free(score);
145     free(scoreOut);
146
147     return result_seq;
148 }
149
150 namespace cv
151 {
152 LatentSvmDetector::ObjectDetection::ObjectDetection() : score(0.f), classID(-1)
153 {}
154
155 LatentSvmDetector::ObjectDetection::ObjectDetection( const Rect& _rect, float _score, int _classID ) :
156     rect(_rect), score(_score), classID(_classID)
157 {}
158
159 LatentSvmDetector::LatentSvmDetector()
160 {}
161
162 LatentSvmDetector::LatentSvmDetector( const vector<string>& filenames, const vector<string>& _classNames )
163 {
164     load( filenames, _classNames );
165 }
166
167 LatentSvmDetector::~LatentSvmDetector()
168 {
169     clear();
170 }
171
172 void LatentSvmDetector::clear()
173 {
174     for( size_t i = 0; i < detectors.size(); i++ )
175         cvReleaseLatentSvmDetector( &detectors[i] );
176     detectors.clear();
177
178     classNames.clear();
179 }
180
181 bool LatentSvmDetector::empty() const
182 {
183     return detectors.empty();
184 }
185
186 const vector<string>& LatentSvmDetector::getClassNames() const
187 {
188     return classNames;
189 }
190
191 size_t LatentSvmDetector::getClassCount() const
192 {
193     return classNames.size();
194 }
195
196 static string extractModelName( const string& filename )
197 {
198     size_t startPos = filename.rfind('/');
199     if( startPos == string::npos )
200         startPos = filename.rfind('\\');
201
202     if( startPos == string::npos )
203         startPos = 0;
204     else
205         startPos++;
206
207     const int extentionSize = 4; //.xml
208
209     int substrLength = (int)(filename.size() - startPos - extentionSize);
210
211     return filename.substr(startPos, substrLength);
212 }
213
214 bool LatentSvmDetector::load( const vector<string>& filenames, const vector<string>& _classNames )
215 {
216     clear();
217
218     CV_Assert( _classNames.empty() || _classNames.size() == filenames.size() );
219
220     for( size_t i = 0; i < filenames.size(); i++ )
221     {
222         const string filename = filenames[i];
223         if( filename.length() < 5 || filename.substr(filename.length()-4, 4) != ".xml" )
224             continue;
225
226         CvLatentSvmDetector* detector = cvLoadLatentSvmDetector( filename.c_str() );
227         if( detector )
228         {
229             detectors.push_back( detector );
230             if( _classNames.empty() )
231             {
232                 classNames.push_back( extractModelName(filenames[i]) );
233             }
234             else
235                 classNames.push_back( _classNames[i] );
236         }
237     }
238
239     return !empty();
240 }
241
242 void LatentSvmDetector::detect( const Mat& image,
243                                 vector<ObjectDetection>& objectDetections,
244                                 float overlapThreshold,
245                                 int numThreads )
246 {
247     objectDetections.clear();
248     if( numThreads <= 0 )
249         numThreads = 1;
250
251     for( size_t classID = 0; classID < detectors.size(); classID++ )
252     {
253         IplImage image_ipl = image;
254         CvMemStorage* storage = cvCreateMemStorage(0);
255         CvSeq* detections = cvLatentSvmDetectObjects( &image_ipl, detectors[classID], storage, overlapThreshold, numThreads );
256
257         // convert results
258         objectDetections.reserve( objectDetections.size() + detections->total );
259         for( int detectionIdx = 0; detectionIdx < detections->total; detectionIdx++ )
260         {
261             CvObjectDetection detection = *(CvObjectDetection*)cvGetSeqElem( detections, detectionIdx );
262             objectDetections.push_back( ObjectDetection(Rect(detection.rect), detection.score, (int)classID) );
263         }
264
265         cvReleaseMemStorage( &storage );
266     }
267 }
268
269 } // namespace cv