]> rtime.felk.cvut.cz Git - opencv.git/blob - opencv/src/cv/cvcascadedetect.cpp
bbffa16212edc21ceb844d414117358061bc83ca
[opencv.git] / opencv / src / cv / cvcascadedetect.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "_cv.h"
43 #include <cstdio>
44
45 namespace cv
46 {
47
48 // class for grouping object candidates, detected by Cascade Classifier, HOG etc.
49 // instance of the class is to be passed to cv::partition (see cxoperations.hpp)
50 class CV_EXPORTS SimilarRects
51 {
52 public:    
53     SimilarRects(double _eps) : eps(_eps) {}
54     inline bool operator()(const Rect& r1, const Rect& r2) const
55     {
56         double delta = eps*(std::min(r1.width, r2.width) + std::min(r1.height, r2.height))*0.5;
57         return std::abs(r1.x - r2.x) <= delta &&
58         std::abs(r1.y - r2.y) <= delta &&
59         std::abs(r1.x + r1.width - r2.x - r2.width) <= delta &&
60         std::abs(r1.y + r1.height - r2.y - r2.height) <= delta;
61     }
62     double eps;
63 };    
64     
65     
66 void groupRectangles(Vector<Rect>& rectList, int groupThreshold, double eps)
67 {
68     if( groupThreshold <= 0 )
69         return;
70     
71     Vector<int> labels;
72     int nclasses = partition(rectList, labels, SimilarRects(eps));
73     Vector<Rect> rrects(nclasses);
74     Vector<int> rweights(nclasses, 0);
75     int i, nlabels = (int)labels.size();
76     for( i = 0; i < nlabels; i++ )
77     {
78         int cls = labels[i];
79         rrects[cls].x += rectList[i].x;
80         rrects[cls].y += rectList[i].y;
81         rrects[cls].width += rectList[i].width;
82         rrects[cls].height += rectList[i].height;
83         rweights[cls]++;
84     }
85     rectList.clear();
86     for( i = 0; i < nclasses; i++ )
87     {
88         Rect r = rrects[i];
89         if( rweights[i] <= groupThreshold )
90             continue;
91         float s = 1.f/rweights[i];
92         rectList.push_back(Rect(saturate_cast<int>(r.x*s),
93                                 saturate_cast<int>(r.y*s),
94                                 saturate_cast<int>(r.width*s),
95                                 saturate_cast<int>(r.height*s)));
96     }
97 }
98     
99 //-----------------------------------------------------------------------------------------------------------------
100 #define CC_CASCADE_PARAMS "cascadeParams"
101 #define CC_STAGE_TYPE "stageType"
102 #define CC_FEATURE_TYPE "featureType"
103 #define CC_HEIGHT "height"
104 #define CC_WIDTH  "width"
105
106 #define CC_STAGE_NUM    "stageNum"
107 #define CC_STAGES       "stages"
108 #define CC_STAGE_PARAMS "stageParams"
109
110 #define CC_BOOST            "BOOST"
111 #define CC_MAX_DEPTH        "maxDepth"
112 #define CC_WEAK_COUNT       "maxWeakCount"
113 #define CC_STAGE_THRESHOLD  "stageThreshold"
114 #define CC_WEAK_CLASSIFIERS "weakClassifiers"
115 #define CC_INTERNAL_NODES   "internalNodes"
116 #define CC_LEAF_VALUES      "leafValues"
117
118 #define CC_FEATURES "features"
119 #define CC_FEATURE_PARAMS "featureParams"
120 #define CC_MAX_CAT_COUNT  "maxCatCount"
121
122 #define CC_HAAR         "HAAR"
123 #define CC_RECTS        "rects"
124 #define CC_TILTED       "tilted"
125
126 #define CC_LBP  "LBP"
127 #define CC_RECT "rect"
128
129 #define CV_SUM_PTRS( p0, p1, p2, p3, sum, rect, step )                    \
130     /* (x, y) */                                                          \
131     (p0) = sum + (rect).x + (step) * (rect).y,                            \
132     /* (x + w, y) */                                                      \
133     (p1) = sum + (rect).x + (rect).width + (step) * (rect).y,             \
134     /* (x + w, y) */                                                      \
135     (p2) = sum + (rect).x + (step) * ((rect).y + (rect).height),          \
136     /* (x + w, y + h) */                                                  \
137     (p3) = sum + (rect).x + (rect).width + (step) * ((rect).y + (rect).height)
138
139 #define CV_TILTED_PTRS( p0, p1, p2, p3, tilted, rect, step )                        \
140     /* (x, y) */                                                                    \
141     (p0) = tilted + (rect).x + (step) * (rect).y,                                   \
142     /* (x - h, y + h) */                                                            \
143     (p1) = tilted + (rect).x - (rect).height + (step) * ((rect).y + (rect).height), \
144     /* (x + w, y + w) */                                                            \
145     (p2) = tilted + (rect).x + (rect).width + (step) * ((rect).y + (rect).width),   \
146     /* (x + w - h, y + w + h) */                                                    \
147     (p3) = tilted + (rect).x + (rect).width - (rect).height                         \
148            + (step) * ((rect).y + (rect).width + (rect).height)
149
150 #define CALC_SUM_(p0, p1, p2, p3, offset) \
151     ((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset])   
152     
153 #define CALC_SUM(rect,offset) CALC_SUM_((rect)[0], (rect)[1], (rect)[2], (rect)[3], offset)
154
155
156 FeatureEvaluator::~FeatureEvaluator() {}
157 bool FeatureEvaluator::read(const FileNode&) {return true;}
158 int FeatureEvaluator::getFeatureType() const {return -1;}
159
160 bool FeatureEvaluator::setImage(const Mat&, Size) { return true; }
161 int FeatureEvaluator::setWindow(Point) { return true; }
162
163 double FeatureEvaluator::calcOrd(int, int) const { return 0.; }
164 int FeatureEvaluator::calcCat(int, int) const { return 0; }
165
166     
167 class HaarEvaluator : public FeatureEvaluator
168 {
169 public:
170     struct Feature
171     {
172         Feature();
173         
174         float calc( int offset ) const;
175         void updatePtrs( const Mat& sum );
176         bool read( const FileNode& node );
177         
178         bool tilted;
179         
180         enum { RECT_NUM = 3 };
181         
182         struct
183         {
184             Rect r;
185             float weight;
186         } rect[RECT_NUM];
187         
188         const int* p[RECT_NUM][4];
189     };
190     
191     HaarEvaluator();
192     virtual ~HaarEvaluator();
193
194     virtual bool read( const FileNode& node );
195     virtual bool setImage(const Mat& image, Size _origWinSize );
196     virtual int setWindow( Point pt );
197     virtual int getFeatureType() const { return FeatureEvaluator::HAAR; }
198
199     double operator()(int featureIdx, int pOffset) const
200     { return features[featureIdx].calc(pOffset) * varianceNormFactor; }
201     
202     virtual double calcOrd(int featureIdx, int pOffset) const
203     { return (*this)(featureIdx, pOffset); }
204
205 private:
206     Size origWinSize;
207     Vector<Feature> features;
208     bool hasTiltedFeatures;
209
210     Mat sum0, sqsum0, tilted0;
211     Mat sum, sqsum, tilted;
212     
213     Rect normrect;
214     const int *p[4];
215     const double *pq[4];
216     
217     double varianceNormFactor;    
218 };
219
220 //----------------------------------------------  Haar Features ------------------------------------------------
221 inline HaarEvaluator::Feature :: Feature()
222 {
223     tilted = false;
224     rect[0].r = rect[1].r = rect[2].r = Rect();
225     rect[0].weight = rect[1].weight = rect[2].weight = 0;
226     p[0][0] = p[0][1] = p[0][2] = p[0][3] = 
227     p[1][0] = p[1][1] = p[1][2] = p[1][3] = 
228     p[2][0] = p[2][1] = p[2][2] = p[2][3] = 0;
229 }
230
231 inline float HaarEvaluator::Feature :: calc( int offset ) const
232 {
233     float ret = rect[0].weight * CALC_SUM(p[0], offset) + rect[1].weight * CALC_SUM(p[1], offset);
234
235     if( rect[2].weight != 0.0f )
236         ret += rect[2].weight * CALC_SUM(p[2], offset);
237     
238     return ret;
239 }
240
241 inline void HaarEvaluator::Feature :: updatePtrs( const Mat& sum )
242 {
243     const int* ptr = (const int*)sum.data;
244     size_t step = sum.step/sizeof(ptr[0]);
245     if (tilted)
246     {
247         CV_TILTED_PTRS( p[0][0], p[0][1], p[0][2], p[0][3], ptr, rect[0].r, step );
248         CV_TILTED_PTRS( p[1][0], p[1][1], p[1][2], p[1][3], ptr, rect[1].r, step );
249         if (rect[2].weight)
250             CV_TILTED_PTRS( p[2][0], p[2][1], p[2][2], p[2][3], ptr, rect[2].r, step );
251     }
252     else
253     {
254         CV_SUM_PTRS( p[0][0], p[0][1], p[0][2], p[0][3], ptr, rect[0].r, step );
255         CV_SUM_PTRS( p[1][0], p[1][1], p[1][2], p[1][3], ptr, rect[1].r, step );
256         if (rect[2].weight)
257             CV_SUM_PTRS( p[2][0], p[2][1], p[2][2], p[2][3], ptr, rect[2].r, step );
258     }
259 }
260
261 bool HaarEvaluator::Feature :: read( const FileNode& node )
262 {
263     FileNode rnode = node[CC_RECTS];
264     FileNodeIterator it = rnode.begin(), it_end = rnode.end();
265     
266     int ri;
267     for( ri = 0; ri < RECT_NUM; ri++ )
268     {
269         rect[ri].r = Rect();
270         rect[ri].weight = 0.f;
271     }
272     
273     for(ri = 0; it != it_end; ++it, ri++)
274     {
275         FileNodeIterator it2 = (*it).begin();
276         it2 >> rect[ri].r.x >> rect[ri].r.y >>
277             rect[ri].r.width >> rect[ri].r.height >> rect[ri].weight;
278     }
279     
280     tilted = (int)node[CC_TILTED] != 0;
281     return true;
282 }
283
284
285 HaarEvaluator::HaarEvaluator()
286 {
287 }
288
289 HaarEvaluator::~HaarEvaluator()
290 {
291 }
292
293 bool HaarEvaluator::read(const FileNode& node)
294 {
295     features.resize(node.size());
296     FileNodeIterator it = node.begin(), it_end = node.end();
297     hasTiltedFeatures = false;
298     
299     for(int i = 0; it != it_end; ++it, i++)
300     {
301         if(!features[i].read(*it))
302             return false;
303         if( features[i].tilted )
304             hasTiltedFeatures = true;
305     }
306     return true;
307 }
308     
309 bool HaarEvaluator::setImage( const Mat& image, Size _origWinSize )
310 {
311     int rn = image.rows+1, cn = image.cols+1;
312     origWinSize = _origWinSize;
313     normrect = Rect(1, 1, origWinSize.width-2, origWinSize.height-2);
314     
315     if (image.cols < origWinSize.width || image.rows < origWinSize.height)
316         return false;
317     
318     if( sum0.rows < rn || sum0.cols < cn )
319     {
320         sum0.create(rn, cn, CV_32S);
321         sqsum0.create(rn, cn, CV_64F);
322         if (hasTiltedFeatures)
323             tilted0.create( rn, cn, CV_32S);
324     }
325     sum = Mat(rn, cn, CV_32S, sum0.data);
326     sqsum = Mat(rn, cn, CV_32S, sqsum0.data);
327     if( hasTiltedFeatures )
328     {
329         tilted = Mat(rn, cn, CV_32S, tilted0.data);
330         integral(image, sum, sqsum, tilted);
331     }
332     else
333         integral(image, sum, sqsum);
334
335     const int* sdata = (const int*)sum.data;
336     const double* sqdata = (const double*)sqsum.data;
337     size_t sumStep = sum.step/sizeof(sdata[0]);
338     size_t sqsumStep = sqsum.step/sizeof(sqdata[0]);
339     
340     CV_SUM_PTRS( p[0], p[1], p[2], p[3], sdata, normrect, sumStep );
341     CV_SUM_PTRS( pq[0], pq[1], pq[2], pq[3], sqdata, normrect, sqsumStep );
342     
343     size_t fi, nfeatures = features.size();
344
345     for( fi = 0; fi < nfeatures; fi++ )
346         features[fi].updatePtrs( !features[fi].tilted ? sum : tilted );
347
348     return true;
349 }
350
351
352 int HaarEvaluator::setWindow( Point pt )
353 {
354     if( pt.x < 0 || pt.y < 0 ||
355         pt.x + origWinSize.width >= sum.cols-2 ||
356         pt.y + origWinSize.height >= sum.rows-2 )
357         return false;
358
359     size_t pOffset = pt.y * (sum.step/sizeof(int)) + pt.x;
360     size_t pqOffset = pt.y * (sqsum.step/sizeof(double)) + pt.x;
361     int valsum = CALC_SUM(p,pOffset);
362     double valsqsum = CALC_SUM(pq,pqOffset);
363
364     varianceNormFactor = (double)normrect.area() * valsqsum - (double)valsum * valsum;
365     if( varianceNormFactor > 0. )
366         varianceNormFactor = sqrt(varianceNormFactor);
367     else
368         varianceNormFactor = 1.;
369     varianceNormFactor = 1./varianceNormFactor;
370     return (int)pOffset;
371 }
372
373 //----------------------------------------------  LBP Features ------------------------------------------------
374
375 class LBPEvaluator : public FeatureEvaluator
376 {
377 public:
378     struct Feature
379     {
380         Feature();
381         Feature( int x, int y, int _block_w, int _block_h  ) : 
382         rect(x, y, _block_w, _block_h) {}
383         
384         int calc( int offset ) const;
385         void updatePtrs( const Mat& sum );
386         bool read(const FileNode& node );
387         
388         enum { POINT_NUM = 16 };
389         
390         Rect rect; // weight and height for block
391         const int* p[POINT_NUM]; // fast
392     };
393     
394     LBPEvaluator();
395     virtual ~LBPEvaluator();
396     
397     virtual bool read( const FileNode& node );
398     virtual bool setImage(const Mat& image, Size _origWinSize);
399     virtual int setWindow( Point pt );
400     virtual int getFeatureType() const { return FeatureEvaluator::LBP; }
401     
402     int operator()(int featureIdx, int pOffset) const
403     { return features[featureIdx].calc(pOffset); }
404     
405     virtual int calcCat(int featureIdx, int pOffset) const
406     { return (*this)(featureIdx, pOffset); }
407     
408 private:
409     Size origWinSize;
410     Vector<LBPEvaluator::Feature> features;
411     
412     Mat sum0, sum;
413     Rect normrect;
414 };    
415     
416     
417 inline LBPEvaluator::Feature :: Feature()
418 {
419     rect = Rect();
420     for( int i = 0; i < POINT_NUM; i++ )
421         p[i] = 0;
422 }
423
424 inline int LBPEvaluator::Feature :: calc( int offset ) const
425 {
426     int cval = CALC_SUM_( p[5], p[6], p[9], p[10], offset );
427     
428     return (CALC_SUM_( p[0], p[1], p[4], p[5], offset ) >= cval ? 128 : 0) |   // 0
429            (CALC_SUM_( p[1], p[2], p[5], p[6], offset ) >= cval ? 64 : 0) |    // 1
430            (CALC_SUM_( p[2], p[3], p[6], p[7], offset ) >= cval ? 32 : 0) |    // 2
431            (CALC_SUM_( p[6], p[7], p[10], p[11], offset ) >= cval ? 16 : 0) |  // 5
432            (CALC_SUM_( p[10], p[11], p[14], p[15], offset ) >= cval ? 8 : 0)|  // 8
433            (CALC_SUM_( p[9], p[10], p[13], p[14], offset ) >= cval ? 4 : 0)|   // 7
434            (CALC_SUM_( p[8], p[9], p[12], p[13], offset ) >= cval ? 2 : 0)|    // 6
435            (CALC_SUM_( p[4], p[5], p[8], p[9], offset ) >= cval ? 1 : 0);
436 }
437
438 inline void LBPEvaluator::Feature :: updatePtrs( const Mat& sum )
439 {
440     const int* ptr = (const int*)sum.data;
441     size_t step = sum.step/sizeof(ptr[0]);
442     Rect tr = rect;
443     CV_SUM_PTRS( p[0], p[1], p[4], p[5], ptr, tr, step );
444     tr.x += 2*rect.width;
445     CV_SUM_PTRS( p[2], p[3], p[6], p[7], ptr, tr, step );
446     tr.y += 2*rect.height;
447     CV_SUM_PTRS( p[10], p[11], p[14], p[15], ptr, tr, step );
448     tr.x -= 2*rect.width;
449     CV_SUM_PTRS( p[8], p[9], p[12], p[13], ptr, tr, step );
450 }
451
452 bool LBPEvaluator::Feature :: read(const FileNode& node )
453 {
454     FileNode rnode = node[CC_RECT];
455     FileNodeIterator it = rnode.begin();
456     it >> rect.x >> rect.y >> rect.width >> rect.height;
457     return true;
458 }
459
460 //--------------------------------------- LBPEvaluator -------------------------------------------
461
462 LBPEvaluator::LBPEvaluator()
463 {
464 }
465
466 LBPEvaluator::~LBPEvaluator()
467 {
468 }
469 bool LBPEvaluator::read( const FileNode& node )
470 {
471     features.resize(node.size());
472     FileNodeIterator it = node.begin(), it_end = node.end();
473
474     for(int i = 0; it != it_end; ++it, i++)
475     {
476         if(!features[i].read(*it))
477             return false;
478     }
479     return true;
480 }
481
482 bool LBPEvaluator::setImage( const Mat& image, Size _origWinSize )
483 {
484     int rn = image.rows+1, cn = image.cols+1;
485     origWinSize = _origWinSize;
486
487     if( image.cols < origWinSize.width || image.rows < origWinSize.height )
488         return false;
489     
490     if( sum0.rows < rn || sum0.cols < cn )
491         sum0.create(rn, cn, CV_32S);
492     sum = Mat(rn, cn, CV_32S, sum0.data);
493     integral(image, sum);
494     
495     size_t fi, nfeatures = features.size();
496     
497     for( fi = 0; fi < nfeatures; fi++ )
498         features[fi].updatePtrs( sum );
499
500     return true;
501 }
502     
503 int LBPEvaluator::setWindow( Point pt )
504 {
505     if( pt.x < 0 || pt.y < 0 ||
506         pt.x + origWinSize.width >= sum.cols-2 ||
507         pt.y + origWinSize.height >= sum.rows-2 )
508         return -1;
509     return pt.y * ((int)sum.step/sizeof(int)) + pt.x;
510 }
511
512     
513 Ptr<FeatureEvaluator> FeatureEvaluator::create(int featureType)
514 {
515     return featureType == HAAR ? Ptr<FeatureEvaluator>(new HaarEvaluator) :
516         featureType == LBP ? Ptr<FeatureEvaluator>(new LBPEvaluator) : Ptr<FeatureEvaluator>();
517 }
518     
519 /////////////////////////////////// Classifier Cascade ////////////////////////////////////////////////
520
521 CascadeClassifier::CascadeClassifier()
522 {
523 }
524
525 CascadeClassifier::CascadeClassifier(const String& filename)
526 { load(filename); }
527
528 CascadeClassifier::~CascadeClassifier()
529 {
530 }    
531
532 bool CascadeClassifier::empty() const
533 {
534     return oldCascade.empty() && stages.empty();
535 }
536
537 bool CascadeClassifier::load(const String& filename)
538 {
539     oldCascade.release();
540     
541     FileStorage fs(filename, FileStorage::READ);
542     if( !fs.isOpened() )
543         return false;
544     
545     if( read(fs.getFirstTopLevelNode()) )
546         return true;
547     
548     fs.release();
549     
550     oldCascade = Ptr<CvHaarClassifierCascade>((CvHaarClassifierCascade*)cvLoad(filename.c_str(), 0, 0, 0));
551     return !oldCascade.empty();
552 }
553     
554
555 template<class FEval>
556 inline int predictOrdered( CascadeClassifier& cascade, int pOffset)
557 {
558     int si, nstages = (int)cascade.stages.size();
559     int nodeOfs = 0, leafOfs = 0;
560     FEval& feval = (FEval&)*cascade.feval;
561     
562     for( si = 0; si < nstages; si++ )
563     {
564         CascadeClassifier::Stage& stage = cascade.stages[si];
565         int wi, ntrees = stage.ntrees;
566         double sum = 0;
567         
568         for( wi = 0; wi < ntrees; wi++ )
569         {
570             CascadeClassifier::DTree& weak = cascade.classifiers[stage.first + wi];
571             int idx = 0, root = nodeOfs;
572             do
573             {
574                 CascadeClassifier::DTreeNode& node = cascade.nodes[root + idx];
575                 double val = feval(node.featureIdx, pOffset);
576                 idx = val < node.threshold ? node.left : node.right;
577             }
578             while( idx > 0 );
579             sum += cascade.leaves[leafOfs - idx];
580             nodeOfs += weak.nodeCount;
581             leafOfs += weak.nodeCount + 1;
582         }
583         if( sum < stage.threshold )
584             return -si;            
585     }
586     return 1;
587 }
588
589 template<class FEval>
590 inline int predictCategorical( CascadeClassifier& cascade, int pOffset)
591 {
592     int si, nstages = (int)cascade.stages.size();
593     int nodeOfs = 0, leafOfs = 0;
594     FEval& feval = (FEval&)*cascade.feval;
595     size_t subsetSize = (cascade.ncategories + 31)/32;
596     
597     for( si = 0; si < nstages; si++ )
598     {
599         CascadeClassifier::Stage& stage = cascade.stages[si];
600         int wi, ntrees = stage.ntrees;
601         double sum = 0;
602         
603         for( wi = 0; wi < ntrees; wi++ )
604         {
605             CascadeClassifier::DTree& weak = cascade.classifiers[stage.first + wi];
606             int idx = 0, root = nodeOfs;
607             do
608             {
609                 CascadeClassifier::DTreeNode& node = cascade.nodes[root + idx];
610                 int c = feval(node.featureIdx, pOffset);
611                 const int* subset = &cascade.subsets[(root + idx)*subsetSize];
612                 idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right;
613             }
614             while( idx > 0 );
615             sum += cascade.leaves[leafOfs - idx];
616             nodeOfs += weak.nodeCount;
617             leafOfs += weak.nodeCount + 1;
618         }
619         if( sum < stage.threshold )
620             return -si;            
621     }
622     return 1;
623 }
624     
625
626 int CascadeClassifier::runAt(Point pt)
627 {
628     CV_Assert( oldCascade.empty() );
629     /*if( !oldCascade.empty() )
630         return cvRunHaarClassifierCascade(oldCascade, pt, 0);*/
631         
632     assert(featureType == FeatureEvaluator::HAAR ||
633            featureType == FeatureEvaluator::LBP);
634     int offset = feval->setWindow(pt);
635     return offset < 0 ? -1 :
636         featureType == FeatureEvaluator::HAAR ?
637             predictOrdered<HaarEvaluator>(*this, offset) :
638             predictCategorical<LBPEvaluator>(*this, offset);
639 }
640
641     
642 bool CascadeClassifier::setImage(const Mat& image)
643 {
644     /*if( !oldCascade.empty() )
645     {
646         Mat sum(image.rows+1, image.cols+1, CV_32S);
647         Mat tilted(image.rows+1, image.cols+1, CV_32S);
648         Mat sqsum(image.rows+1, image.cols+1, CV_64F);
649         integral(image, sum, sqsum, tilted);
650         CvMat _sum = sum, _sqsum = sqsum, _tilted = tilted;
651         cvSetImagesForHaarClassifierCascade( oldCascade, &_sum, &_sqsum, &_tilted, 1. );
652         return true;
653     }*/
654     return empty() ? false : feval->setImage(image, origWinSize);
655 }
656     
657     
658 struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } };
659 void CascadeClassifier::detectMultiScale( const Mat& image, Vector<Rect>& objects,
660                                           double scaleFactor, int minNeighbors,
661                                           int flags, Size minSize )
662 {
663     CV_Assert( scaleFactor > 1 && image.depth() == CV_8U );
664     
665     if( empty() )
666         return;
667
668     if( !oldCascade.empty() )
669     {
670         MemStorage storage(cvCreateMemStorage(0));
671         CvMat _image = image;
672         CvSeq* _objects = cvHaarDetectObjects( &_image, oldCascade, storage, scaleFactor,
673                                               minNeighbors, flags, minSize );
674         Vector<CvAvgComp> vecAvgComp;
675         Seq<CvAvgComp>(_objects).copyTo(vecAvgComp);
676         objects.resize(vecAvgComp.size());
677         std::transform(vecAvgComp.begin(), vecAvgComp.end(), objects.begin(), getRect());
678         return;
679     }
680     
681     objects.clear();
682     
683     Mat img = image, imgbuf(image.rows+1, image.cols+1, CV_8U);
684     
685     if( img.channels() > 1 )
686     {
687         Mat temp;
688         cvtColor(img, temp, CV_BGR2GRAY);
689         img = temp;
690     }
691     
692     for( double factor = 1; ; factor *= scaleFactor )
693     {
694         
695         Size winSize( cvRound(origWinSize.width*factor), cvRound(origWinSize.height*factor) );
696         Size sz( cvRound( img.cols/factor ), cvRound( img.rows/factor ) );
697         Size sz1( sz.width - origWinSize.width, sz.height - origWinSize.height );
698         
699         if( sz1.width <= 0 || sz1.height <= 0 )
700             break;
701         if( winSize.width < minSize.width || winSize.height < minSize.height )
702             continue;
703         
704         Mat img1( sz, CV_8U, imgbuf.data );
705         
706         resize( img, img1, sz, 0, 0, CV_INTER_LINEAR );
707         if( !feval->setImage( img1, origWinSize ) )
708             break;
709         int yStep = factor > 2. ? 1 : 2;
710         
711         for( int y = 0; y < sz1.height; y += yStep )
712             for( int x = 0; x < sz1.width; x += yStep )
713             {
714                 int r = runAt(Point(x,y));
715                 if( r > 0 )
716                     objects.push_back(Rect(cvRound(x*factor), cvRound(y*factor),
717                                            winSize.width, winSize.height));
718                 else if( r == 0 )
719                     x += yStep;
720             }
721     }
722     
723     groupRectangles( objects, minNeighbors, 0.2 );
724 }    
725
726     
727 bool CascadeClassifier::read(const FileNode& root)
728 {
729     // load stage params
730     String stageTypeStr = (String)root[CC_STAGE_TYPE];
731     if( stageTypeStr == CC_BOOST )
732         stageType = BOOST;
733     else
734         return false;
735     
736     String featureTypeStr = (String)root[CC_FEATURE_TYPE];
737     if( featureTypeStr == CC_HAAR )
738         featureType = FeatureEvaluator::HAAR;
739     else if( featureTypeStr == CC_LBP )
740         featureType = FeatureEvaluator::LBP;
741     else
742         return false;
743     
744     origWinSize.width = (int)root[CC_WIDTH];
745     origWinSize.height = (int)root[CC_HEIGHT];
746     CV_Assert( origWinSize.height > 0 && origWinSize.width > 0 );
747     
748     // load feature params
749     FileNode fn = root[CC_FEATURE_PARAMS];
750     if( fn.empty() )
751         return false;
752     
753     ncategories = fn[CC_MAX_CAT_COUNT];
754     int subsetSize = (ncategories + 31)/32,
755         nodeStep = 3 + ( ncategories>0 ? subsetSize : 1 );
756     
757     // load stages
758     fn = root[CC_STAGES];
759     if( fn.empty() )
760         return false;
761     
762     stages.reserve(fn.size());
763     classifiers.clear();
764     nodes.clear();
765     
766     FileNodeIterator it = fn.begin(), it_end = fn.end();
767     
768     for( int si = 0; it != it_end; si++, ++it )
769     {
770         FileNode fns = *it;
771         Stage stage;
772         stage.threshold = fns[CC_STAGE_THRESHOLD];
773         fns = fns[CC_WEAK_CLASSIFIERS];
774         if(fns.empty())
775             return false;
776         stage.ntrees = (int)fns.size();
777         stage.first = (int)classifiers.size();
778         stages.push_back(stage);
779         classifiers.reserve(stages[si].first + stages[si].ntrees);
780         
781         FileNodeIterator it1 = fns.begin(), it1_end = fns.end();
782         for( ; it1 != it1_end; ++it1 ) // weak trees
783         {
784             FileNode fnw = *it1;
785             FileNode internalNodes = fnw[CC_INTERNAL_NODES];
786             FileNode leafValues = fnw[CC_LEAF_VALUES];
787             if( internalNodes.empty() || leafValues.empty() )
788                 return false;
789             DTree tree;
790             tree.nodeCount = (int)internalNodes.size()/nodeStep;
791             classifiers.push_back(tree);
792             
793             nodes.reserve(nodes.size() + tree.nodeCount);
794             leaves.reserve(leaves.size() + leafValues.size());
795             if( subsetSize > 0 )
796                 subsets.reserve(subsets.size() + tree.nodeCount*subsetSize);
797             
798             FileNodeIterator it2 = internalNodes.begin(), it2_end = internalNodes.end();
799             
800             for( ; it2 != it2_end; ) // nodes
801             {
802                 DTreeNode node;
803                 node.left = (int)*it2; ++it2;
804                 node.right = (int)*it2; ++it2;
805                 node.featureIdx = (int)*it2; ++it2;
806                 if( subsetSize > 0 )
807                     for( int j = 0; j < subsetSize; j++, ++it2 )
808                         subsets.push_back((int)*it2);
809                 else
810                 {
811                     node.threshold = (float)*it2; ++it2;
812                 }
813                 nodes.push_back(node);
814             }
815             
816             it2 = leafValues.begin(), it2_end = leafValues.end();
817             
818             for( ; it2 != it2_end; ++it2 ) // leaves
819                 leaves.push_back((float)*it2);
820         }
821     }
822
823     // load features
824     feval = FeatureEvaluator::create(featureType);
825     fn = root[CC_FEATURES];
826     if( fn.empty() )
827         return false;
828     
829     return feval->read(fn);
830 }
831
832 } // namespace cv
833
834 /* End of file. */