cascadedetect.hpp 16.1 KB
Newer Older
wester committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
#pragma once

namespace cv
{

#define CC_CASCADE_PARAMS "cascadeParams"
#define CC_STAGE_TYPE     "stageType"
#define CC_FEATURE_TYPE   "featureType"
#define CC_HEIGHT         "height"
#define CC_WIDTH          "width"

#define CC_STAGE_NUM    "stageNum"
#define CC_STAGES       "stages"
#define CC_STAGE_PARAMS "stageParams"

#define CC_BOOST            "BOOST"
#define CC_MAX_DEPTH        "maxDepth"
#define CC_WEAK_COUNT       "maxWeakCount"
#define CC_STAGE_THRESHOLD  "stageThreshold"
#define CC_WEAK_CLASSIFIERS "weakClassifiers"
#define CC_INTERNAL_NODES   "internalNodes"
#define CC_LEAF_VALUES      "leafValues"

#define CC_FEATURES       "features"
#define CC_FEATURE_PARAMS "featureParams"
#define CC_MAX_CAT_COUNT  "maxCatCount"

#define CC_HAAR   "HAAR"
#define CC_RECTS  "rects"
#define CC_TILTED "tilted"

#define CC_LBP  "LBP"
#define CC_RECT "rect"

#define CC_HOG  "HOG"

#define CV_SUM_PTRS( p0, p1, p2, p3, sum, rect, step )                    \
    /* (x, y) */                                                          \
    (p0) = sum + (rect).x + (step) * (rect).y,                            \
    /* (x + w, y) */                                                      \
    (p1) = sum + (rect).x + (rect).width + (step) * (rect).y,             \
    /* (x + w, y) */                                                      \
    (p2) = sum + (rect).x + (step) * ((rect).y + (rect).height),          \
    /* (x + w, y + h) */                                                  \
    (p3) = sum + (rect).x + (rect).width + (step) * ((rect).y + (rect).height)

#define CV_TILTED_PTRS( p0, p1, p2, p3, tilted, rect, step )                        \
    /* (x, y) */                                                                    \
    (p0) = tilted + (rect).x + (step) * (rect).y,                                   \
    /* (x - h, y + h) */                                                            \
    (p1) = tilted + (rect).x - (rect).height + (step) * ((rect).y + (rect).height), \
    /* (x + w, y + w) */                                                            \
    (p2) = tilted + (rect).x + (rect).width + (step) * ((rect).y + (rect).width),   \
    /* (x + w - h, y + w + h) */                                                    \
    (p3) = tilted + (rect).x + (rect).width - (rect).height                         \
           + (step) * ((rect).y + (rect).width + (rect).height)

#define CALC_SUM_(p0, p1, p2, p3, offset) \
    ((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset])

#define CALC_SUM(rect,offset) CALC_SUM_((rect)[0], (rect)[1], (rect)[2], (rect)[3], offset)


//----------------------------------------------  HaarEvaluator ---------------------------------------
class HaarEvaluator : public FeatureEvaluator
{
public:
    struct Feature
    {
        Feature();
wester committed
71 72 73

        float calc( int offset ) const;
        void updatePtrs( const Mat& sum );
wester committed
74 75 76 77 78
        bool read( const FileNode& node );

        bool tilted;

        enum { RECT_NUM = 3 };
wester committed
79

wester committed
80 81 82 83 84 85
        struct
        {
            Rect r;
            float weight;
        } rect[RECT_NUM];

wester committed
86
        const int* p[RECT_NUM][4];
wester committed
87 88 89 90 91
    };

    HaarEvaluator();
    virtual ~HaarEvaluator();

wester committed
92
    virtual bool read( const FileNode& node );
wester committed
93 94 95
    virtual Ptr<FeatureEvaluator> clone() const;
    virtual int getFeatureType() const { return FeatureEvaluator::HAAR; }

wester committed
96 97
    virtual bool setImage(const Mat&, Size origWinSize);
    virtual bool setWindow(Point pt);
wester committed
98

wester committed
99 100 101
    double operator()(int featureIdx) const
    { return featuresPtr[featureIdx].calc(offset) * varianceNormFactor; }
    virtual double calcOrd(int featureIdx) const
wester committed
102 103 104
    { return (*this)(featureIdx); }

protected:
wester committed
105 106 107
    Size origWinSize;
    Ptr<vector<Feature> > features;
    Feature* featuresPtr; // optimization
wester committed
108 109
    bool hasTiltedFeatures;

wester committed
110 111 112
    Mat sum0, sqsum0, tilted0;
    Mat sum, sqsum, tilted;

wester committed
113
    Rect normrect;
wester committed
114 115 116 117 118
    const int *p[4];
    const double *pq[4];

    int offset;
    double varianceNormFactor;
wester committed
119 120 121 122 123 124 125
};

inline HaarEvaluator::Feature :: Feature()
{
    tilted = false;
    rect[0].r = rect[1].r = rect[2].r = Rect();
    rect[0].weight = rect[1].weight = rect[2].weight = 0;
wester committed
126 127 128
    p[0][0] = p[0][1] = p[0][2] = p[0][3] =
        p[1][0] = p[1][1] = p[1][2] = p[1][3] =
        p[2][0] = p[2][1] = p[2][2] = p[2][3] = 0;
wester committed
129 130
}

wester committed
131
inline float HaarEvaluator::Feature :: calc( int _offset ) const
wester committed
132
{
wester committed
133
    float ret = rect[0].weight * CALC_SUM(p[0], _offset) + rect[1].weight * CALC_SUM(p[1], _offset);
wester committed
134

wester committed
135 136 137 138
    if( rect[2].weight != 0.0f )
        ret += rect[2].weight * CALC_SUM(p[2], _offset);

    return ret;
wester committed
139 140
}

wester committed
141
inline void HaarEvaluator::Feature :: updatePtrs( const Mat& _sum )
wester committed
142
{
wester committed
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
    const int* ptr = (const int*)_sum.data;
    size_t step = _sum.step/sizeof(ptr[0]);
    if (tilted)
    {
        CV_TILTED_PTRS( p[0][0], p[0][1], p[0][2], p[0][3], ptr, rect[0].r, step );
        CV_TILTED_PTRS( p[1][0], p[1][1], p[1][2], p[1][3], ptr, rect[1].r, step );
        if (rect[2].weight)
            CV_TILTED_PTRS( p[2][0], p[2][1], p[2][2], p[2][3], ptr, rect[2].r, step );
    }
    else
    {
        CV_SUM_PTRS( p[0][0], p[0][1], p[0][2], p[0][3], ptr, rect[0].r, step );
        CV_SUM_PTRS( p[1][0], p[1][1], p[1][2], p[1][3], ptr, rect[1].r, step );
        if (rect[2].weight)
            CV_SUM_PTRS( p[2][0], p[2][1], p[2][2], p[2][3], ptr, rect[2].r, step );
    }
wester committed
159 160
}

wester committed
161

wester committed
162 163 164 165 166 167 168 169 170
//----------------------------------------------  LBPEvaluator -------------------------------------

class LBPEvaluator : public FeatureEvaluator
{
public:
    struct Feature
    {
        Feature();
        Feature( int x, int y, int _block_w, int _block_h  ) :
wester committed
171
        rect(x, y, _block_w, _block_h) {}
wester committed
172

wester committed
173 174
        int calc( int offset ) const;
        void updatePtrs( const Mat& sum );
wester committed
175 176 177
        bool read(const FileNode& node );

        Rect rect; // weight and height for block
wester committed
178
        const int* p[16]; // fast
wester committed
179 180 181 182 183
    };

    LBPEvaluator();
    virtual ~LBPEvaluator();

wester committed
184
    virtual bool read( const FileNode& node );
wester committed
185 186 187
    virtual Ptr<FeatureEvaluator> clone() const;
    virtual int getFeatureType() const { return FeatureEvaluator::LBP; }

wester committed
188 189
    virtual bool setImage(const Mat& image, Size _origWinSize);
    virtual bool setWindow(Point pt);
wester committed
190 191

    int operator()(int featureIdx) const
wester committed
192
    { return featuresPtr[featureIdx].calc(offset); }
wester committed
193 194 195
    virtual int calcCat(int featureIdx) const
    { return (*this)(featureIdx); }
protected:
wester committed
196 197 198 199 200
    Size origWinSize;
    Ptr<vector<Feature> > features;
    Feature* featuresPtr; // optimization
    Mat sum0, sum;
    Rect normrect;
wester committed
201

wester committed
202
    int offset;
wester committed
203 204 205 206 207 208
};


inline LBPEvaluator::Feature :: Feature()
{
    rect = Rect();
wester committed
209 210
    for( int i = 0; i < 16; i++ )
        p[i] = 0;
wester committed
211 212
}

wester committed
213
inline int LBPEvaluator::Feature :: calc( int _offset ) const
wester committed
214
{
wester committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
    int cval = CALC_SUM_( p[5], p[6], p[9], p[10], _offset );

    return (CALC_SUM_( p[0], p[1], p[4], p[5], _offset ) >= cval ? 128 : 0) |   // 0
           (CALC_SUM_( p[1], p[2], p[5], p[6], _offset ) >= cval ? 64 : 0) |    // 1
           (CALC_SUM_( p[2], p[3], p[6], p[7], _offset ) >= cval ? 32 : 0) |    // 2
           (CALC_SUM_( p[6], p[7], p[10], p[11], _offset ) >= cval ? 16 : 0) |  // 5
           (CALC_SUM_( p[10], p[11], p[14], p[15], _offset ) >= cval ? 8 : 0)|  // 8
           (CALC_SUM_( p[9], p[10], p[13], p[14], _offset ) >= cval ? 4 : 0)|   // 7
           (CALC_SUM_( p[8], p[9], p[12], p[13], _offset ) >= cval ? 2 : 0)|    // 6
           (CALC_SUM_( p[4], p[5], p[8], p[9], _offset ) >= cval ? 1 : 0);
}

inline void LBPEvaluator::Feature :: updatePtrs( const Mat& _sum )
{
    const int* ptr = (const int*)_sum.data;
    size_t step = _sum.step/sizeof(ptr[0]);
    Rect tr = rect;
    CV_SUM_PTRS( p[0], p[1], p[4], p[5], ptr, tr, step );
    tr.x += 2*rect.width;
    CV_SUM_PTRS( p[2], p[3], p[6], p[7], ptr, tr, step );
    tr.y += 2*rect.height;
    CV_SUM_PTRS( p[10], p[11], p[14], p[15], ptr, tr, step );
    tr.x -= 2*rect.width;
    CV_SUM_PTRS( p[8], p[9], p[12], p[13], ptr, tr, step );
}

//---------------------------------------------- HOGEvaluator -------------------------------------------

class HOGEvaluator : public FeatureEvaluator
{
public:
    struct Feature
    {
        Feature();
        float calc( int offset ) const;
        void updatePtrs( const vector<Mat>& _hist, const Mat &_normSum );
        bool read( const FileNode& node );

        enum { CELL_NUM = 4, BIN_NUM = 9 };

        Rect rect[CELL_NUM];
        int featComponent; //component index from 0 to 35
        const float* pF[4]; //for feature calculation
        const float* pN[4]; //for normalization calculation
    };
    HOGEvaluator();
    virtual ~HOGEvaluator();
    virtual bool read( const FileNode& node );
    virtual Ptr<FeatureEvaluator> clone() const;
    virtual int getFeatureType() const { return FeatureEvaluator::HOG; }
    virtual bool setImage( const Mat& image, Size winSize );
    virtual bool setWindow( Point pt );
    double operator()(int featureIdx) const
    {
        return featuresPtr[featureIdx].calc(offset);
    }
    virtual double calcOrd( int featureIdx ) const
    {
        return (*this)(featureIdx);
    }

private:
    virtual void integralHistogram( const Mat& srcImage, vector<Mat> &histogram, Mat &norm, int nbins ) const;

    Size origWinSize;
    Ptr<vector<Feature> > features;
    Feature* featuresPtr;
    vector<Mat> hist;
    Mat normSum;
    int offset;
};

inline HOGEvaluator::Feature :: Feature()
{
    rect[0] = rect[1] = rect[2] = rect[3] = Rect();
    pF[0] = pF[1] = pF[2] = pF[3] = 0;
    pN[0] = pN[1] = pN[2] = pN[3] = 0;
    featComponent = 0;
}

inline float HOGEvaluator::Feature :: calc( int _offset ) const
{
    float res = CALC_SUM(pF, _offset);
    float normFactor = CALC_SUM(pN, _offset);
    res = (res > 0.001f) ? (res / ( normFactor + 0.001f) ) : 0.f;
    return res;
wester committed
301 302
}

wester committed
303
inline void HOGEvaluator::Feature :: updatePtrs( const vector<Mat> &_hist, const Mat &_normSum )
wester committed
304
{
wester committed
305 306 307 308 309 310 311 312 313 314 315 316
    int binIdx = featComponent % BIN_NUM;
    int cellIdx = featComponent / BIN_NUM;
    Rect normRect = Rect( rect[0].x, rect[0].y, 2*rect[0].width, 2*rect[0].height );

    const float* featBuf = (const float*)_hist[binIdx].data;
    size_t featStep = _hist[0].step / sizeof(featBuf[0]);

    const float* normBuf = (const float*)_normSum.data;
    size_t normStep = _normSum.step / sizeof(normBuf[0]);

    CV_SUM_PTRS( pF[0], pF[1], pF[2], pF[3], featBuf, rect[cellIdx], featStep );
    CV_SUM_PTRS( pN[0], pN[1], pN[2], pN[3], normBuf, normRect, normStep );
wester committed
317 318 319
}


wester committed
320 321


wester committed
322 323 324
//----------------------------------------------  predictor functions -------------------------------------

template<class FEval>
wester committed
325
inline int predictOrdered( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
wester committed
326 327 328 329 330
{
    int nstages = (int)cascade.data.stages.size();
    int nodeOfs = 0, leafOfs = 0;
    FEval& featureEvaluator = (FEval&)*_featureEvaluator;
    float* cascadeLeaves = &cascade.data.leaves[0];
wester committed
331 332 333
    CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
    CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];
    CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0];
wester committed
334 335 336

    for( int si = 0; si < nstages; si++ )
    {
wester committed
337
        CascadeClassifier::Data::Stage& stage = cascadeStages[si];
wester committed
338 339 340 341 342
        int wi, ntrees = stage.ntrees;
        sum = 0;

        for( wi = 0; wi < ntrees; wi++ )
        {
wester committed
343
            CascadeClassifier::Data::DTree& weak = cascadeWeaks[stage.first + wi];
wester committed
344 345 346 347
            int idx = 0, root = nodeOfs;

            do
            {
wester committed
348
                CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx];
wester committed
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
                double val = featureEvaluator(node.featureIdx);
                idx = val < node.threshold ? node.left : node.right;
            }
            while( idx > 0 );
            sum += cascadeLeaves[leafOfs - idx];
            nodeOfs += weak.nodeCount;
            leafOfs += weak.nodeCount + 1;
        }
        if( sum < stage.threshold )
            return -si;
    }
    return 1;
}

template<class FEval>
wester committed
364
inline int predictCategorical( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
wester committed
365 366 367 368 369 370 371
{
    int nstages = (int)cascade.data.stages.size();
    int nodeOfs = 0, leafOfs = 0;
    FEval& featureEvaluator = (FEval&)*_featureEvaluator;
    size_t subsetSize = (cascade.data.ncategories + 31)/32;
    int* cascadeSubsets = &cascade.data.subsets[0];
    float* cascadeLeaves = &cascade.data.leaves[0];
wester committed
372 373 374
    CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
    CascadeClassifier::Data::DTree* cascadeWeaks = &cascade.data.classifiers[0];
    CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0];
wester committed
375 376 377

    for(int si = 0; si < nstages; si++ )
    {
wester committed
378
        CascadeClassifier::Data::Stage& stage = cascadeStages[si];
wester committed
379 380 381 382 383
        int wi, ntrees = stage.ntrees;
        sum = 0;

        for( wi = 0; wi < ntrees; wi++ )
        {
wester committed
384
            CascadeClassifier::Data::DTree& weak = cascadeWeaks[stage.first + wi];
wester committed
385 386 387
            int idx = 0, root = nodeOfs;
            do
            {
wester committed
388
                CascadeClassifier::Data::DTreeNode& node = cascadeNodes[root + idx];
wester committed
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
                int c = featureEvaluator(node.featureIdx);
                const int* subset = &cascadeSubsets[(root + idx)*subsetSize];
                idx = (subset[c>>5] & (1 << (c & 31))) ? node.left : node.right;
            }
            while( idx > 0 );
            sum += cascadeLeaves[leafOfs - idx];
            nodeOfs += weak.nodeCount;
            leafOfs += weak.nodeCount + 1;
        }
        if( sum < stage.threshold )
            return -si;
    }
    return 1;
}

template<class FEval>
wester committed
405
inline int predictOrderedStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
wester committed
406
{
wester committed
407
    int nodeOfs = 0, leafOfs = 0;
wester committed
408
    FEval& featureEvaluator = (FEval&)*_featureEvaluator;
wester committed
409 410 411
    float* cascadeLeaves = &cascade.data.leaves[0];
    CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
    CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0];
wester committed
412 413 414 415

    int nstages = (int)cascade.data.stages.size();
    for( int stageIdx = 0; stageIdx < nstages; stageIdx++ )
    {
wester committed
416 417
        CascadeClassifier::Data::Stage& stage = cascadeStages[stageIdx];
        sum = 0.0;
wester committed
418 419

        int ntrees = stage.ntrees;
wester committed
420
        for( int i = 0; i < ntrees; i++, nodeOfs++, leafOfs+= 2 )
wester committed
421
        {
wester committed
422 423 424
            CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs];
            double value = featureEvaluator(node.featureIdx);
            sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ];
wester committed
425 426
        }

wester committed
427
        if( sum < stage.threshold )
wester committed
428 429 430 431 432 433 434
            return -stageIdx;
    }

    return 1;
}

template<class FEval>
wester committed
435
inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum )
wester committed
436 437
{
    int nstages = (int)cascade.data.stages.size();
wester committed
438
    int nodeOfs = 0, leafOfs = 0;
wester committed
439 440
    FEval& featureEvaluator = (FEval&)*_featureEvaluator;
    size_t subsetSize = (cascade.data.ncategories + 31)/32;
wester committed
441 442 443 444
    int* cascadeSubsets = &cascade.data.subsets[0];
    float* cascadeLeaves = &cascade.data.leaves[0];
    CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
    CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0];
wester committed
445

wester committed
446 447 448
#ifdef HAVE_TEGRA_OPTIMIZATION
    float tmp = 0; // float accumulator -- float operations are quicker
#endif
wester committed
449 450
    for( int si = 0; si < nstages; si++ )
    {
wester committed
451
        CascadeClassifier::Data::Stage& stage = cascadeStages[si];
wester committed
452
        int wi, ntrees = stage.ntrees;
wester committed
453
#ifdef HAVE_TEGRA_OPTIMIZATION
wester committed
454
        tmp = 0;
wester committed
455 456 457
#else
        sum = 0;
#endif
wester committed
458 459 460

        for( wi = 0; wi < ntrees; wi++ )
        {
wester committed
461 462 463 464 465 466 467 468 469 470
            CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs];
            int c = featureEvaluator(node.featureIdx);
            const int* subset = &cascadeSubsets[nodeOfs*subsetSize];
#ifdef HAVE_TEGRA_OPTIMIZATION
            tmp += cascadeLeaves[ subset[c>>5] & (1 << (c & 31)) ? leafOfs : leafOfs+1];
#else
            sum += cascadeLeaves[ subset[c>>5] & (1 << (c & 31)) ? leafOfs : leafOfs+1];
#endif
            nodeOfs++;
            leafOfs += 2;
wester committed
471
        }
wester committed
472 473 474
#ifdef HAVE_TEGRA_OPTIMIZATION
        if( tmp < stage.threshold ) {
            sum = (double)tmp;
wester committed
475 476
            return -si;
        }
wester committed
477 478 479 480
#else
        if( sum < stage.threshold )
            return -si;
#endif
wester committed
481 482
    }

wester committed
483
#ifdef HAVE_TEGRA_OPTIMIZATION
wester committed
484
    sum = (double)tmp;
wester committed
485 486
#endif

wester committed
487 488 489
    return 1;
}
}