Add OpenCV source code
[platform/upstream/opencv.git] / modules / objdetect / src / cascadedetect.hpp
1 #pragma once
2
3 namespace cv
4 {
5
6 #define CC_CASCADE_PARAMS "cascadeParams"
7 #define CC_STAGE_TYPE     "stageType"
8 #define CC_FEATURE_TYPE   "featureType"
9 #define CC_HEIGHT         "height"
10 #define CC_WIDTH          "width"
11
12 #define CC_STAGE_NUM    "stageNum"
13 #define CC_STAGES       "stages"
14 #define CC_STAGE_PARAMS "stageParams"
15
16 #define CC_BOOST            "BOOST"
17 #define CC_MAX_DEPTH        "maxDepth"
18 #define CC_WEAK_COUNT       "maxWeakCount"
19 #define CC_STAGE_THRESHOLD  "stageThreshold"
20 #define CC_WEAK_CLASSIFIERS "weakClassifiers"
21 #define CC_INTERNAL_NODES   "internalNodes"
22 #define CC_LEAF_VALUES      "leafValues"
23
24 #define CC_FEATURES       "features"
25 #define CC_FEATURE_PARAMS "featureParams"
26 #define CC_MAX_CAT_COUNT  "maxCatCount"
27
28 #define CC_HAAR   "HAAR"
29 #define CC_RECTS  "rects"
30 #define CC_TILTED "tilted"
31
32 #define CC_LBP  "LBP"
33 #define CC_RECT "rect"
34
35 #define CC_HOG  "HOG"
36
37 #define CV_SUM_PTRS( p0, p1, p2, p3, sum, rect, step )                    \
38     /* (x, y) */                                                          \
39     (p0) = sum + (rect).x + (step) * (rect).y,                            \
40     /* (x + w, y) */                                                      \
41     (p1) = sum + (rect).x + (rect).width + (step) * (rect).y,             \
42     /* (x + w, y) */                                                      \
43     (p2) = sum + (rect).x + (step) * ((rect).y + (rect).height),          \
44     /* (x + w, y + h) */                                                  \
45     (p3) = sum + (rect).x + (rect).width + (step) * ((rect).y + (rect).height)
46
47 #define CV_TILTED_PTRS( p0, p1, p2, p3, tilted, rect, step )                        \
48     /* (x, y) */                                                                    \
49     (p0) = tilted + (rect).x + (step) * (rect).y,                                   \
50     /* (x - h, y + h) */                                                            \
51     (p1) = tilted + (rect).x - (rect).height + (step) * ((rect).y + (rect).height), \
52     /* (x + w, y + w) */                                                            \
53     (p2) = tilted + (rect).x + (rect).width + (step) * ((rect).y + (rect).width),   \
54     /* (x + w - h, y + w + h) */                                                    \
55     (p3) = tilted + (rect).x + (rect).width - (rect).height                         \
56            + (step) * ((rect).y + (rect).width + (rect).height)
57
58 #define CALC_SUM_(p0, p1, p2, p3, offset) \
59     ((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset])
60
61 #define CALC_SUM(rect,offset) CALC_SUM_((rect)[0], (rect)[1], (rect)[2], (rect)[3], offset)
62
63
64 //----------------------------------------------  HaarEvaluator ---------------------------------------
65 class HaarEvaluator : public FeatureEvaluator
66 {
67 public:
68     struct Feature
69     {
70         Feature();
71
72         float calc( int offset ) const;
73         void updatePtrs( const Mat& sum );
74         bool read( const FileNode& node );
75
76         bool tilted;
77
78         enum { RECT_NUM = 3 };
79
80         struct
81         {
82             Rect r;
83             float weight;
84         } rect[RECT_NUM];
85
86         const int* p[RECT_NUM][4];
87     };
88
89     HaarEvaluator();
90     virtual ~HaarEvaluator();
91
92     virtual bool read( const FileNode& node );
93     virtual Ptr<FeatureEvaluator> clone() const;
94     virtual int getFeatureType() const { return FeatureEvaluator::HAAR; }
95
96     virtual bool setImage(const Mat&, Size origWinSize);
97     virtual bool setWindow(Point pt);
98
99     double operator()(int featureIdx) const
100     { return featuresPtr[featureIdx].calc(offset) * varianceNormFactor; }
101     virtual double calcOrd(int featureIdx) const
102     { return (*this)(featureIdx); }
103
104 protected:
105     Size origWinSize;
106     Ptr<vector<Feature> > features;
107     Feature* featuresPtr; // optimization
108     bool hasTiltedFeatures;
109
110     Mat sum0, sqsum0, tilted0;
111     Mat sum, sqsum, tilted;
112
113     Rect normrect;
114     const int *p[4];
115     const double *pq[4];
116
117     int offset;
118     double varianceNormFactor;
119 };
120
121 inline HaarEvaluator::Feature :: Feature()
122 {
123     tilted = false;
124     rect[0].r = rect[1].r = rect[2].r = Rect();
125     rect[0].weight = rect[1].weight = rect[2].weight = 0;
126     p[0][0] = p[0][1] = p[0][2] = p[0][3] =
127         p[1][0] = p[1][1] = p[1][2] = p[1][3] =
128         p[2][0] = p[2][1] = p[2][2] = p[2][3] = 0;
129 }
130
131 inline float HaarEvaluator::Feature :: calc( int _offset ) const
132 {
133     float ret = rect[0].weight * CALC_SUM(p[0], _offset) + rect[1].weight * CALC_SUM(p[1], _offset);
134
135     if( rect[2].weight != 0.0f )
136         ret += rect[2].weight * CALC_SUM(p[2], _offset);
137
138     return ret;
139 }
140
141 inline void HaarEvaluator::Feature :: updatePtrs( const Mat& _sum )
142 {
143     const int* ptr = (const int*)_sum.data;
144     size_t step = _sum.step/sizeof(ptr[0]);
145     if (tilted)
146     {
147         CV_TILTED_PTRS( p[0][0], p[0][1], p[0][2], p[0][3], ptr, rect[0].r, step );
148         CV_TILTED_PTRS( p[1][0], p[1][1], p[1][2], p[1][3], ptr, rect[1].r, step );
149         if (rect[2].weight)
150             CV_TILTED_PTRS( p[2][0], p[2][1], p[2][2], p[2][3], ptr, rect[2].r, step );
151     }
152     else
153     {
154         CV_SUM_PTRS( p[0][0], p[0][1], p[0][2], p[0][3], ptr, rect[0].r, step );
155         CV_SUM_PTRS( p[1][0], p[1][1], p[1][2], p[1][3], ptr, rect[1].r, step );
156         if (rect[2].weight)
157             CV_SUM_PTRS( p[2][0], p[2][1], p[2][2], p[2][3], ptr, rect[2].r, step );
158     }
159 }
160
161
162 //----------------------------------------------  LBPEvaluator -------------------------------------
163
164 class LBPEvaluator : public FeatureEvaluator
165 {
166 public:
167     struct Feature
168     {
169         Feature();
170         Feature( int x, int y, int _block_w, int _block_h  ) :
171         rect(x, y, _block_w, _block_h) {}
172
173         int calc( int offset ) const;
174         void updatePtrs( const Mat& sum );
175         bool read(const FileNode& node );
176
177         Rect rect; // weight and height for block
178         const int* p[16]; // fast
179     };
180
181     LBPEvaluator();
182     virtual ~LBPEvaluator();
183
184     virtual bool read( const FileNode& node );
185     virtual Ptr<FeatureEvaluator> clone() const;
186     virtual int getFeatureType() const { return FeatureEvaluator::LBP; }
187
188     virtual bool setImage(const Mat& image, Size _origWinSize);
189     virtual bool setWindow(Point pt);
190
191     int operator()(int featureIdx) const
192     { return featuresPtr[featureIdx].calc(offset); }
193     virtual int calcCat(int featureIdx) const
194     { return (*this)(featureIdx); }
195 protected:
196     Size origWinSize;
197     Ptr<vector<Feature> > features;
198     Feature* featuresPtr; // optimization
199     Mat sum0, sum;
200     Rect normrect;
201
202     int offset;
203 };
204
205
206 inline LBPEvaluator::Feature :: Feature()
207 {
208     rect = Rect();
209     for( int i = 0; i < 16; i++ )
210         p[i] = 0;
211 }
212
213 inline int LBPEvaluator::Feature :: calc( int _offset ) const
214 {
215     int cval = CALC_SUM_( p[5], p[6], p[9], p[10], _offset );
216
217     return (CALC_SUM_( p[0], p[1], p[4], p[5], _offset ) >= cval ? 128 : 0) |   // 0
218            (CALC_SUM_( p[1], p[2], p[5], p[6], _offset ) >= cval ? 64 : 0) |    // 1
219            (CALC_SUM_( p[2], p[3], p[6], p[7], _offset ) >= cval ? 32 : 0) |    // 2
220            (CALC_SUM_( p[6], p[7], p[10], p[11], _offset ) >= cval ? 16 : 0) |  // 5
221            (CALC_SUM_( p[10], p[11], p[14], p[15], _offset ) >= cval ? 8 : 0)|  // 8
222            (CALC_SUM_( p[9], p[10], p[13], p[14], _offset ) >= cval ? 4 : 0)|   // 7
223            (CALC_SUM_( p[8], p[9], p[12], p[13], _offset ) >= cval ? 2 : 0)|    // 6
224            (CALC_SUM_( p[4], p[5], p[8], p[9], _offset ) >= cval ? 1 : 0);
225 }
226
227 inline void LBPEvaluator::Feature :: updatePtrs( const Mat& _sum )
228 {
229     const int* ptr = (const int*)_sum.data;
230     size_t step = _sum.step/sizeof(ptr[0]);
231     Rect tr = rect;
232     CV_SUM_PTRS( p[0], p[1], p[4], p[5], ptr, tr, step );
233     tr.x += 2*rect.width;
234     CV_SUM_PTRS( p[2], p[3], p[6], p[7], ptr, tr, step );
235     tr.y += 2*rect.height;
236     CV_SUM_PTRS( p[10], p[11], p[14], p[15], ptr, tr, step );
237     tr.x -= 2*rect.width;
238     CV_SUM_PTRS( p[8], p[9], p[12], p[13], ptr, tr, step );
239 }
240
241 //---------------------------------------------- HOGEvaluator -------------------------------------------
242
243 class HOGEvaluator : public FeatureEvaluator
244 {
245 public:
246     struct Feature
247     {
248         Feature();
249         float calc( int offset ) const;
250         void updatePtrs( const vector<Mat>& _hist, const Mat &_normSum );
251         bool read( const FileNode& node );
252
253         enum { CELL_NUM = 4, BIN_NUM = 9 };
254
255         Rect rect[CELL_NUM];
256         int featComponent; //component index from 0 to 35
257         const float* pF[4]; //for feature calculation
258         const float* pN[4]; //for normalization calculation
259     };
260     HOGEvaluator();
261     virtual ~HOGEvaluator();
262     virtual bool read( const FileNode& node );
263     virtual Ptr<FeatureEvaluator> clone() const;
264     virtual int getFeatureType() const { return FeatureEvaluator::HOG; }
265     virtual bool setImage( const Mat& image, Size winSize );
266     virtual bool setWindow( Point pt );
267     double operator()(int featureIdx) const
268     {
269         return featuresPtr[featureIdx].calc(offset);
270     }
271     virtual double calcOrd( int featureIdx ) const
272     {
273         return (*this)(featureIdx);
274     }
275
276 private:
277     virtual void integralHistogram( const Mat& srcImage, vector<Mat> &histogram, Mat &norm, int nbins ) const;
278
279     Size origWinSize;
280     Ptr<vector<Feature> > features;
281     Feature* featuresPtr;
282     vector<Mat> hist;
283     Mat normSum;
284     int offset;
285 };
286
287 inline HOGEvaluator::Feature :: Feature()
288 {
289     rect[0] = rect[1] = rect[2] = rect[3] = Rect();
290     pF[0] = pF[1] = pF[2] = pF[3] = 0;
291     pN[0] = pN[1] = pN[2] = pN[3] = 0;
292     featComponent = 0;
293 }
294
295 inline float HOGEvaluator::Feature :: calc( int _offset ) const
296 {
297     float res = CALC_SUM(pF, _offset);
298     float normFactor = CALC_SUM(pN, _offset);
299     res = (res > 0.001f) ? (res / ( normFactor + 0.001f) ) : 0.f;
300     return res;
301 }
302
303 inline void HOGEvaluator::Feature :: updatePtrs( const vector<Mat> &_hist, const Mat &_normSum )
304 {
305     int binIdx = featComponent % BIN_NUM;
306     int cellIdx = featComponent / BIN_NUM;
307     Rect normRect = Rect( rect[0].x, rect[0].y, 2*rect[0].width, 2*rect[0].height );
308
309     const float* featBuf = (const float*)_hist[binIdx].data;
310     size_t featStep = _hist[0].step / sizeof(featBuf[0]);
311
312     const float* normBuf = (const float*)_normSum.data;
313     size_t normStep = _normSum.step / sizeof(normBuf[0]);
314
315     CV_SUM_PTRS( pF[0], pF[1], pF[2], pF[3], featBuf, rect[cellIdx], featStep );
316     CV_SUM_PTRS( pN[0], pN[1], pN[2], pN[3], normBuf, normRect, normStep );
317 }
318
319
320
321
322 //----------------------------------------------  predictor functions -------------------------------------
323
324 template<class FEval>
325 inline int predictOrdered( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
326 {
327     int nstages = (int)cascade.data.stages.size();
328     int nodeOfs = 0, leafOfs = 0;
329     FEval& featureEvaluator = (FEval&)*_featureEvaluator;
330     float* cascadeLeaves = &cascade.data.leaves[0];
331     CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
332     CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];
333     CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0];
334
335     for( int si = 0; si < nstages; si++ )
336     {
337         CascadeClassifier::Data::Stage& stage = cascadeStages[si];
338         int wi, ntrees = stage.ntrees;
339         sum = 0;
340
341         for( wi = 0; wi < ntrees; wi++ )
342         {
343             CascadeClassifier::Data::DTree& weak = cascadeWeaks[stage.first + wi];
344             int idx = 0, root = nodeOfs;
345
346             do
347             {
348                 CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx];
349                 double val = featureEvaluator(node.featureIdx);
350                 idx = val < node.threshold ? node.left : node.right;
351             }
352             while( idx > 0 );
353             sum += cascadeLeaves[leafOfs - idx];
354             nodeOfs += weak.nodeCount;
355             leafOfs += weak.nodeCount + 1;
356         }
357         if( sum < stage.threshold )
358             return -si;
359     }
360     return 1;
361 }
362
363 template<class FEval>
364 inline int predictCategorical( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
365 {
366     int nstages = (int)cascade.data.stages.size();
367     int nodeOfs = 0, leafOfs = 0;
368     FEval& featureEvaluator = (FEval&)*_featureEvaluator;
369     size_t subsetSize = (cascade.data.ncategories + 31)/32;
370     int* cascadeSubsets = &cascade.data.subsets[0];
371     float* cascadeLeaves = &cascade.data.leaves[0];
372     CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
373     CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];
374     CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0];
375
376     for(int si = 0; si < nstages; si++ )
377     {
378         CascadeClassifier::Data::Stage& stage = cascadeStages[si];
379         int wi, ntrees = stage.ntrees;
380         sum = 0;
381
382         for( wi = 0; wi < ntrees; wi++ )
383         {
384             CascadeClassifier::Data::DTree& weak = cascadeWeaks[stage.first + wi];
385             int idx = 0, root = nodeOfs;
386             do
387             {
388                 CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx];
389                 int c = featureEvaluator(node.featureIdx);
390                 const int* subset = &cascadeSubsets[(root + idx)*subsetSize];
391                 idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right;
392             }
393             while( idx > 0 );
394             sum += cascadeLeaves[leafOfs - idx];
395             nodeOfs += weak.nodeCount;
396             leafOfs += weak.nodeCount + 1;
397         }
398         if( sum < stage.threshold )
399             return -si;
400     }
401     return 1;
402 }
403
404 template<class FEval>
405 inline int predictOrderedStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
406 {
407     int nodeOfs = 0, leafOfs = 0;
408     FEval& featureEvaluator = (FEval&)*_featureEvaluator;
409     float* cascadeLeaves = &cascade.data.leaves[0];
410     CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
411     CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0];
412
413     int nstages = (int)cascade.data.stages.size();
414     for( int stageIdx = 0; stageIdx < nstages; stageIdx++ )
415     {
416         CascadeClassifier::Data::Stage& stage = cascadeStages[stageIdx];
417         sum = 0.0;
418
419         int ntrees = stage.ntrees;
420         for( int i = 0; i < ntrees; i++, nodeOfs++, leafOfs+= 2 )
421         {
422             CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs];
423             double value = featureEvaluator(node.featureIdx);
424             sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ];
425         }
426
427         if( sum < stage.threshold )
428             return -stageIdx;
429     }
430
431     return 1;
432 }
433
434 template<class FEval>
435 inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
436 {
437     int nstages = (int)cascade.data.stages.size();
438     int nodeOfs = 0, leafOfs = 0;
439     FEval& featureEvaluator = (FEval&)*_featureEvaluator;
440     size_t subsetSize = (cascade.data.ncategories + 31)/32;
441     int* cascadeSubsets = &cascade.data.subsets[0];
442     float* cascadeLeaves = &cascade.data.leaves[0];
443     CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
444     CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0];
445
446 #ifdef HAVE_TEGRA_OPTIMIZATION
447     float tmp = 0; // float accumulator -- float operations are quicker
448 #endif
449     for( int si = 0; si < nstages; si++ )
450     {
451         CascadeClassifier::Data::Stage& stage = cascadeStages[si];
452         int wi, ntrees = stage.ntrees;
453 #ifdef HAVE_TEGRA_OPTIMIZATION
454         tmp = 0;
455 #else
456         sum = 0;
457 #endif
458
459         for( wi = 0; wi < ntrees; wi++ )
460         {
461             CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs];
462             int c = featureEvaluator(node.featureIdx);
463             const int* subset = &cascadeSubsets[nodeOfs*subsetSize];
464 #ifdef HAVE_TEGRA_OPTIMIZATION
465             tmp += cascadeLeaves[ subset[c>>5] & (1 << (c & 31)) ? leafOfs : leafOfs+1];
466 #else
467             sum += cascadeLeaves[ subset[c>>5] & (1 << (c & 31)) ? leafOfs : leafOfs+1];
468 #endif
469             nodeOfs++;
470             leafOfs += 2;
471         }
472 #ifdef HAVE_TEGRA_OPTIMIZATION
473         if( tmp < stage.threshold ) {
474             sum = (double)tmp;
475             return -si;
476         }
477 #else
478         if( sum < stage.threshold )
479             return -si;
480 #endif
481     }
482
483 #ifdef HAVE_TEGRA_OPTIMIZATION
484     sum = (double)tmp;
485 #endif
486
487     return 1;
488 }
489 }