cascadedetect.cpp 54.2 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
10
//                           License Agreement
11 12
//                For Open Source Computer Vision Library
//
13
// Copyright (C) 2008-2013, Itseez Inc., all rights reserved.
14 15 16 17 18 19 20 21 22 23 24 25
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
26
//   * The name of Itseez Inc. may not be used to endorse or promote products
27 28 29 30 31
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
32
// In no event shall the copyright holders or contributors be liable for any direct,
33 34 35 36 37 38 39 40 41 42 43 44
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#include "precomp.hpp"
#include <cstdio>

45
#include "cascadedetect.hpp"
46
#include "opencv2/objdetect/objdetect_c.h"
V
Vadim Pisarevsky 已提交
47
#include "opencl_kernels.hpp"
48

49
#if defined (LOG_CASCADE_STATISTIC)
50 51
struct Logger
{
52
    enum { STADIES_NUM = 20 };
53

54 55 56 57
    int gid;
    cv::Mat mask;
    cv::Size sz0;
    int step;
58

59 60 61 62

    Logger() : gid (0), step(2) {}
    void setImage(const cv::Mat& image)
    {
63
     if (gid == 0)
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
         sz0 = image.size();

      mask.create(image.rows, image.cols * (STADIES_NUM + 1) + STADIES_NUM, CV_8UC1);
      mask = cv::Scalar(0);
      cv::Mat roi = mask(cv::Rect(cv::Point(0,0), image.size()));
      image.copyTo(roi);

      printf("%d) Size = (%d, %d)\n", gid, image.cols, image.rows);

      for(int i = 0; i < STADIES_NUM; ++i)
      {
          int x = image.cols + i * (image.cols + 1);
          cv::line(mask, cv::Point(x, 0), cv::Point(x, mask.rows-1), cv::Scalar(255));
      }

      if (sz0.width/image.cols > 2 && sz0.height/image.rows > 2)
          step = 1;
    }

    void setPoint(const cv::Point& p, int passed_stadies)
    {
        int cols = mask.cols / (STADIES_NUM + 1);

        passed_stadies = -passed_stadies;
        passed_stadies = (passed_stadies == -1) ? STADIES_NUM : passed_stadies;

        unsigned char* ptr = mask.ptr<unsigned char>(p.y) + cols + 1 + p.x;
        for(int i = 0; i < passed_stadies; ++i, ptr += cols + 1)
        {
            *ptr = 255;

            if (step == 2)
            {
                ptr[1] = 255;
                ptr[mask.step] = 255;
                ptr[mask.step + 1] = 255;
            }
        }
    };

    void write()
    {
        char buf[4096];
        sprintf(buf, "%04d.png", gid++);
        cv::imwrite(buf, mask);
    }
110 111

} logger;
112
#endif
113

114 115
namespace cv
{
116

117 118
template<typename _Tp> void copyVectorToUMat(const std::vector<_Tp>& v, UMat& um)
{
119 120 121
    if(v.empty())
        um.release();
    Mat(1, (int)(v.size()*sizeof(v[0])), CV_8U, (void*)&v[0]).copyTo(um);
122
}
A
Andrey Kamaev 已提交
123

124
void groupRectangles(std::vector<Rect>& rectList, int groupThreshold, double eps, std::vector<int>* weights, std::vector<double>* levelWeights)
125 126 127 128 129 130 131 132 133 134 135 136
{
    if( groupThreshold <= 0 || rectList.empty() )
    {
        if( weights )
        {
            size_t i, sz = rectList.size();
            weights->resize(sz);
            for( i = 0; i < sz; i++ )
                (*weights)[i] = 1;
        }
        return;
    }
A
Andrey Kamaev 已提交
137

138
    std::vector<int> labels;
139
    int nclasses = partition(rectList, labels, SimilarRects(eps));
A
Andrey Kamaev 已提交
140

141 142 143 144
    std::vector<Rect> rrects(nclasses);
    std::vector<int> rweights(nclasses, 0);
    std::vector<int> rejectLevels(nclasses, 0);
    std::vector<double> rejectWeights(nclasses, DBL_MIN);
145 146 147 148 149 150 151 152 153 154
    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;
        rweights[cls]++;
    }
155
    if ( levelWeights && weights && !weights->empty() && !levelWeights->empty() )
A
Andrey Kamaev 已提交
156 157 158 159
    {
        for( i = 0; i < nlabels; i++ )
        {
            int cls = labels[i];
160 161 162 163 164 165 166
            if( (*weights)[i] > rejectLevels[cls] )
            {
                rejectLevels[cls] = (*weights)[i];
                rejectWeights[cls] = (*levelWeights)[i];
            }
            else if( ( (*weights)[i] == rejectLevels[cls] ) && ( (*levelWeights)[i] > rejectWeights[cls] ) )
                rejectWeights[cls] = (*levelWeights)[i];
A
Andrey Kamaev 已提交
167 168 169
        }
    }

170 171 172 173 174 175 176 177 178
    for( i = 0; i < nclasses; i++ )
    {
        Rect r = rrects[i];
        float s = 1.f/rweights[i];
        rrects[i] = Rect(saturate_cast<int>(r.x*s),
             saturate_cast<int>(r.y*s),
             saturate_cast<int>(r.width*s),
             saturate_cast<int>(r.height*s));
    }
A
Andrey Kamaev 已提交
179

180 181 182
    rectList.clear();
    if( weights )
        weights->clear();
A
Andrey Kamaev 已提交
183 184 185
    if( levelWeights )
        levelWeights->clear();

186 187 188
    for( i = 0; i < nclasses; i++ )
    {
        Rect r1 = rrects[i];
189
        int n1 = rweights[i];
A
Andrey Kamaev 已提交
190
        double w1 = rejectWeights[i];
191
        int l1 = rejectLevels[i];
192

193
        // filter out rectangles which don't have enough similar rectangles
194 195 196 197 198 199
        if( n1 <= groupThreshold )
            continue;
        // filter out small face rectangles inside large rectangles
        for( j = 0; j < nclasses; j++ )
        {
            int n2 = rweights[j];
A
Andrey Kamaev 已提交
200

201 202 203
            if( j == i || n2 <= groupThreshold )
                continue;
            Rect r2 = rrects[j];
A
Andrey Kamaev 已提交
204

205 206
            int dx = saturate_cast<int>( r2.width * eps );
            int dy = saturate_cast<int>( r2.height * eps );
A
Andrey Kamaev 已提交
207

208 209 210 211 212 213 214 215
            if( i != j &&
                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;
        }
A
Andrey Kamaev 已提交
216

217 218 219 220
        if( j == nclasses )
        {
            rectList.push_back(r1);
            if( weights )
221
                weights->push_back(l1);
A
Andrey Kamaev 已提交
222 223
            if( levelWeights )
                levelWeights->push_back(w1);
224 225 226 227
        }
    }
}

228 229 230
class MeanshiftGrouping
{
public:
231 232
    MeanshiftGrouping(const Point3d& densKer, const std::vector<Point3d>& posV,
        const std::vector<double>& wV, double eps, int maxIter = 20)
233
    {
A
Andrey Kamaev 已提交
234
        densityKernel = densKer;
235 236
        weightsV = wV;
        positionsV = posV;
237
        positionsCount = (int)posV.size();
A
Andrey Kamaev 已提交
238
        meanshiftV.resize(positionsCount);
239
        distanceV.resize(positionsCount);
A
Andrey Kamaev 已提交
240
        iterMax = maxIter;
S
Siegfried Hochdorfer 已提交
241
        modeEps = eps;
A
Andrey Kamaev 已提交
242 243 244 245 246 247 248

        for (unsigned i = 0; i<positionsV.size(); i++)
        {
            meanshiftV[i] = getNewValue(positionsV[i]);
            distanceV[i] = moveToMode(meanshiftV[i]);
            meanshiftV[i] -= positionsV[i];
        }
249
    }
A
Andrey Kamaev 已提交
250

251
    void getModes(std::vector<Point3d>& modesV, std::vector<double>& resWeightsV, const double eps)
252
    {
A
Andrey Kamaev 已提交
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
        for (size_t i=0; i <distanceV.size(); i++)
        {
            bool is_found = false;
            for(size_t j=0; j<modesV.size(); j++)
            {
                if ( getDistance(distanceV[i], modesV[j]) < eps)
                {
                    is_found=true;
                    break;
                }
            }
            if (!is_found)
            {
                modesV.push_back(distanceV[i]);
            }
        }

        resWeightsV.resize(modesV.size());

        for (size_t i=0; i<modesV.size(); i++)
        {
            resWeightsV[i] = getResultWeight(modesV[i]);
        }
276 277 278
    }

protected:
279 280
    std::vector<Point3d> positionsV;
    std::vector<double> weightsV;
281

A
Andrey Kamaev 已提交
282 283
    Point3d densityKernel;
    int positionsCount;
284

285 286
    std::vector<Point3d> meanshiftV;
    std::vector<Point3d> distanceV;
A
Andrey Kamaev 已提交
287 288
    int iterMax;
    double modeEps;
289

A
Andrey Kamaev 已提交
290
    Point3d getNewValue(const Point3d& inPt) const
291
    {
A
Andrey Kamaev 已提交
292 293 294 295 296 297 298 299
        Point3d resPoint(.0);
        Point3d ratPoint(.0);
        for (size_t i=0; i<positionsV.size(); i++)
        {
            Point3d aPt= positionsV[i];
            Point3d bPt = inPt;
            Point3d sPt = densityKernel;

300 301
            sPt.x *= std::exp(aPt.z);
            sPt.y *= std::exp(aPt.z);
A
Andrey Kamaev 已提交
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322

            aPt.x /= sPt.x;
            aPt.y /= sPt.y;
            aPt.z /= sPt.z;

            bPt.x /= sPt.x;
            bPt.y /= sPt.y;
            bPt.z /= sPt.z;

            double w = (weightsV[i])*std::exp(-((aPt-bPt).dot(aPt-bPt))/2)/std::sqrt(sPt.dot(Point3d(1,1,1)));

            resPoint += w*aPt;

            ratPoint.x += w/sPt.x;
            ratPoint.y += w/sPt.y;
            ratPoint.z += w/sPt.z;
        }
        resPoint.x /= ratPoint.x;
        resPoint.y /= ratPoint.y;
        resPoint.z /= ratPoint.z;
        return resPoint;
323 324
    }

A
Andrey Kamaev 已提交
325
    double getResultWeight(const Point3d& inPt) const
326
    {
A
Andrey Kamaev 已提交
327 328 329 330 331 332
        double sumW=0;
        for (size_t i=0; i<positionsV.size(); i++)
        {
            Point3d aPt = positionsV[i];
            Point3d sPt = densityKernel;

333 334
            sPt.x *= std::exp(aPt.z);
            sPt.y *= std::exp(aPt.z);
A
Andrey Kamaev 已提交
335 336 337 338 339 340 341 342 343 344

            aPt -= inPt;

            aPt.x /= sPt.x;
            aPt.y /= sPt.y;
            aPt.z /= sPt.z;

            sumW+=(weightsV[i])*std::exp(-(aPt.dot(aPt))/2)/std::sqrt(sPt.dot(Point3d(1,1,1)));
        }
        return sumW;
345
    }
A
Andrey Kamaev 已提交
346 347

    Point3d moveToMode(Point3d aPt) const
348
    {
A
Andrey Kamaev 已提交
349 350 351 352 353 354 355 356 357 358 359
        Point3d bPt;
        for (int i = 0; i<iterMax; i++)
        {
            bPt = aPt;
            aPt = getNewValue(bPt);
            if ( getDistance(aPt, bPt) <= modeEps )
            {
                break;
            }
        }
        return aPt;
360 361 362 363
    }

    double getDistance(Point3d p1, Point3d p2) const
    {
A
Andrey Kamaev 已提交
364
        Point3d ns = densityKernel;
365 366
        ns.x *= std::exp(p2.z);
        ns.y *= std::exp(p2.z);
A
Andrey Kamaev 已提交
367 368 369 370 371
        p2 -= p1;
        p2.x /= ns.x;
        p2.y /= ns.y;
        p2.z /= ns.z;
        return p2.dot(p2);
372 373
    }
};
374
//new grouping function with using meanshift
375 376
static void groupRectangles_meanshift(std::vector<Rect>& rectList, double detectThreshold, std::vector<double>* foundWeights,
                                      std::vector<double>& scales, Size winDetSize)
377
{
378
    int detectionCount = (int)rectList.size();
379 380
    std::vector<Point3d> hits(detectionCount), resultHits;
    std::vector<double> hitWeights(detectionCount), resultWeights;
381 382
    Point2d hitCenter;

A
Andrey Kamaev 已提交
383
    for (int i=0; i < detectionCount; i++)
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
    {
        hitWeights[i] = (*foundWeights)[i];
        hitCenter = (rectList[i].tl() + rectList[i].br())*(0.5); //center of rectangles
        hits[i] = Point3d(hitCenter.x, hitCenter.y, std::log(scales[i]));
    }

    rectList.clear();
    if (foundWeights)
        foundWeights->clear();

    double logZ = std::log(1.3);
    Point3d smothing(8, 16, logZ);

    MeanshiftGrouping msGrouping(smothing, hits, hitWeights, 1e-5, 100);

    msGrouping.getModes(resultHits, resultWeights, 1);

A
Andrey Kamaev 已提交
401
    for (unsigned i=0; i < resultHits.size(); ++i)
402 403
    {

404
        double scale = std::exp(resultHits[i].z);
405 406 407
        hitCenter.x = resultHits[i].x;
        hitCenter.y = resultHits[i].y;
        Size s( int(winDetSize.width * scale), int(winDetSize.height * scale) );
A
Andrey Kamaev 已提交
408 409
        Rect resultRect( int(hitCenter.x-s.width/2), int(hitCenter.y-s.height/2),
            int(s.width), int(s.height) );
410

A
Andrey Kamaev 已提交
411
        if (resultWeights[i] > detectThreshold)
412 413 414 415 416 417
        {
            rectList.push_back(resultRect);
            foundWeights->push_back(resultWeights[i]);
        }
    }
}
418

419
void groupRectangles(std::vector<Rect>& rectList, int groupThreshold, double eps)
420
{
421
    groupRectangles(rectList, groupThreshold, eps, 0, 0);
422
}
423

424
void groupRectangles(std::vector<Rect>& rectList, std::vector<int>& weights, int groupThreshold, double eps)
425
{
426 427
    groupRectangles(rectList, groupThreshold, eps, &weights, 0);
}
428
//used for cascade detection algorithm for ROC-curve calculating
429
void groupRectangles(std::vector<Rect>& rectList, std::vector<int>& rejectLevels, std::vector<double>& levelWeights, int groupThreshold, double eps)
430
{
431
    groupRectangles(rectList, groupThreshold, eps, &rejectLevels, &levelWeights);
432
}
433
//can be used for HOG detection algorithm only
434 435
void groupRectangles_meanshift(std::vector<Rect>& rectList, std::vector<double>& foundWeights,
                               std::vector<double>& foundScales, double detectThreshold, Size winDetSize)
436
{
A
Andrey Kamaev 已提交
437
    groupRectangles_meanshift(rectList, detectThreshold, &foundWeights, foundScales, winDetSize);
438 439
}

A
Andrey Kamaev 已提交
440

441 442 443 444
FeatureEvaluator::~FeatureEvaluator() {}
bool FeatureEvaluator::read(const FileNode&) {return true;}
Ptr<FeatureEvaluator> FeatureEvaluator::clone() const { return Ptr<FeatureEvaluator>(); }
int FeatureEvaluator::getFeatureType() const {return -1;}
445
bool FeatureEvaluator::setImage(InputArray, Size, Size) {return true;}
446 447 448 449 450 451 452 453 454 455
bool FeatureEvaluator::setWindow(Point) { return true; }
double FeatureEvaluator::calcOrd(int) const { return 0.; }
int FeatureEvaluator::calcCat(int) const { return 0; }

//----------------------------------------------  HaarEvaluator ---------------------------------------

bool HaarEvaluator::Feature :: read( const FileNode& node )
{
    FileNode rnode = node[CC_RECTS];
    FileNodeIterator it = rnode.begin(), it_end = rnode.end();
A
Andrey Kamaev 已提交
456

457 458 459 460 461 462
    int ri;
    for( ri = 0; ri < RECT_NUM; ri++ )
    {
        rect[ri].r = Rect();
        rect[ri].weight = 0.f;
    }
A
Andrey Kamaev 已提交
463

464 465 466 467 468 469
    for(ri = 0; it != it_end; ++it, ri++)
    {
        FileNodeIterator it2 = (*it).begin();
        it2 >> rect[ri].r.x >> rect[ri].r.y >>
            rect[ri].r.width >> rect[ri].r.height >> rect[ri].weight;
    }
A
Andrey Kamaev 已提交
470

471 472 473 474 475 476
    tilted = (int)node[CC_TILTED] != 0;
    return true;
}

HaarEvaluator::HaarEvaluator()
{
477 478
    optfeaturesPtr = 0;
    pwin = 0;
479 480 481 482 483 484 485
}
HaarEvaluator::~HaarEvaluator()
{
}

bool HaarEvaluator::read(const FileNode& node)
{
486 487
    size_t i, n = node.size();
    CV_Assert(n > 0);
488 489 490 491
    if(features.empty())
        features = makePtr<std::vector<Feature> >();
    if(optfeatures.empty())
        optfeatures = makePtr<std::vector<OptFeature> >();
492
    features->resize(n);
493
    FileNodeIterator it = node.begin();
494
    hasTiltedFeatures = false;
V
Vadim Pisarevsky 已提交
495
    std::vector<Feature>& ff = *features;
496 497
    sumSize0 = Size();
    ufbuf.release();
A
Andrey Kamaev 已提交
498

499
    for(i = 0; i < n; i++, ++it)
500
    {
501
        if(!ff[i].read(*it))
502
            return false;
503
        if( ff[i].tilted )
504 505 506 507
            hasTiltedFeatures = true;
    }
    return true;
}
A
Andrey Kamaev 已提交
508

509 510
Ptr<FeatureEvaluator> HaarEvaluator::clone() const
{
R
Roman Donchenko 已提交
511
    Ptr<HaarEvaluator> ret = makePtr<HaarEvaluator>();
512 513
    ret->origWinSize = origWinSize;
    ret->features = features;
514 515
    ret->optfeatures = optfeatures;
    ret->optfeaturesPtr = optfeatures->empty() ? 0 : &(*(ret->optfeatures))[0];
516
    ret->hasTiltedFeatures = hasTiltedFeatures;
517
    ret->sum0 = sum0; ret->sqsum0 = sqsum0;
518 519
    ret->sum = sum; ret->sqsum = sqsum;
    ret->usum0 = usum0; ret->usqsum0 = usqsum0; ret->ufbuf = ufbuf;
520
    ret->normrect = normrect;
521
    memcpy( ret->nofs, nofs, 4*sizeof(nofs[0]) );
522
    ret->pwin = pwin;
A
Andrey Kamaev 已提交
523
    ret->varianceNormFactor = varianceNormFactor;
524 525 526
    return ret;
}

527
bool HaarEvaluator::setImage( InputArray _image, Size _origWinSize, Size _sumSize )
528
{
529
    Size imgsz = _image.size();
530
    int cols = imgsz.width, rows = imgsz.height;
531

532
    if (imgsz.width < origWinSize.width || imgsz.height < origWinSize.height)
533
        return false;
534

535 536
    origWinSize = _origWinSize;
    normrect = Rect(1, 1, origWinSize.width-2, origWinSize.height-2);
537

538 539 540
    int rn = _sumSize.height, cn = _sumSize.width, rn_scale = hasTiltedFeatures ? 2 : 1;
    int sumStep, tofs = 0;
    CV_Assert(rn >= rows+1 && cn >= cols+1);
541

542
    if( _image.isUMat() )
543
    {
544 545 546 547
        usum0.create(rn*rn_scale, cn, CV_32S);
        usqsum0.create(rn, cn, CV_32S);
        usum = UMat(usum0, Rect(0, 0, cols+1, rows+1));
        usqsum = UMat(usqsum0, Rect(0, 0, cols, rows));
548

549 550 551 552 553 554 555
        if( hasTiltedFeatures )
        {
            UMat utilted(usum0, Rect(0, _sumSize.height, cols+1, rows+1));
            integral(_image, usum, noArray(), utilted, CV_32S);
            tofs = (int)((utilted.offset - usum.offset)/sizeof(int));
        }
        else
V
Vadim Pisarevsky 已提交
556
        {
557
            integral(_image, usum, noArray(), noArray(), CV_32S);
V
Vadim Pisarevsky 已提交
558
        }
559

560 561 562
        sqrBoxFilter(_image, usqsum, CV_32S,
                     Size(normrect.width, normrect.height),
                     Point(0, 0), false);
V
Vadim Pisarevsky 已提交
563 564 565 566
        /*sqrBoxFilter(_image.getMat(), sqsum, CV_32S,
                     Size(normrect.width, normrect.height),
                     Point(0, 0), false);
        sqsum.copyTo(usqsum);*/
567
        sumStep = (int)(usum.step/usum.elemSize());
568
    }
569
    else
570
    {
571
        sum0.create(rn*rn_scale, cn, CV_32S);
V
Vadim Pisarevsky 已提交
572
        sqsum0.create(rn, cn, CV_32S);
573
        sum = sum0(Rect(0, 0, cols+1, rows+1));
V
Vadim Pisarevsky 已提交
574
        sqsum = sqsum0(Rect(0, 0, cols, rows));
575

576 577 578
        if( hasTiltedFeatures )
        {
            Mat tilted = sum0(Rect(0, _sumSize.height, cols+1, rows+1));
V
Vadim Pisarevsky 已提交
579
            integral(_image, sum, noArray(), tilted, CV_32S);
580 581 582
            tofs = (int)((tilted.data - sum.data)/sizeof(int));
        }
        else
V
Vadim Pisarevsky 已提交
583 584
            integral(_image, sum, noArray(), noArray(), CV_32S);
        sqrBoxFilter(_image, sqsum, CV_32S,
585
                     Size(normrect.width, normrect.height),
V
Vadim Pisarevsky 已提交
586
                     Point(0, 0), false);
587
        sumStep = (int)(sum.step/sum.elemSize());
588
    }
A
Andrey Kamaev 已提交
589

590
    CV_SUM_OFS( nofs[0], nofs[1], nofs[2], nofs[3], 0, normrect, sumStep );
A
Andrey Kamaev 已提交
591

592 593
    size_t fi, nfeatures = features->size();
    const std::vector<Feature>& ff = *features;
594

595 596 597 598 599 600 601 602
    if( sumSize0 != _sumSize )
    {
        optfeatures->resize(nfeatures);
        optfeaturesPtr = &(*optfeatures)[0];
        for( fi = 0; fi < nfeatures; fi++ )
            optfeaturesPtr[fi].setOffsets( ff[fi], sumStep, tofs );
    }
    if( _image.isUMat() && (sumSize0 != _sumSize || ufbuf.empty()) )
603
        copyVectorToUMat(*optfeatures, ufbuf);
604
    sumSize0 = _sumSize;
605

606 607 608
    return true;
}

609

610 611 612
bool  HaarEvaluator::setWindow( Point pt )
{
    if( pt.x < 0 || pt.y < 0 ||
613 614
        pt.x + origWinSize.width >= sum.cols ||
        pt.y + origWinSize.height >= sum.rows )
615 616
        return false;

617 618
    const int* p = &sum.at<int>(pt);
    int valsum = CALC_SUM_OFS(nofs, p);
V
Vadim Pisarevsky 已提交
619
    double valsqsum = sqsum.at<int>(pt.y + normrect.y, pt.x + normrect.x);
620 621 622

    double nf = (double)normrect.area() * valsqsum - (double)valsum * valsum;
    if( nf > 0. )
623
        nf = std::sqrt(nf);
624 625 626
    else
        nf = 1.;
    varianceNormFactor = 1./nf;
627
    pwin = p;
628

629 630
    return true;
}
631

632 633 634 635
Rect HaarEvaluator::getNormRect() const
{
    return normrect;
}
636

637 638 639 640 641 642 643
void HaarEvaluator::getUMats(std::vector<UMat>& bufs)
{
    bufs.clear();
    bufs.push_back(usum);
    bufs.push_back(usqsum);
    bufs.push_back(ufbuf);
}
644 645 646 647 648 649 650 651 652 653 654 655

//----------------------------------------------  LBPEvaluator -------------------------------------
bool LBPEvaluator::Feature :: read(const FileNode& node )
{
    FileNode rnode = node[CC_RECT];
    FileNodeIterator it = rnode.begin();
    it >> rect.x >> rect.y >> rect.width >> rect.height;
    return true;
}

LBPEvaluator::LBPEvaluator()
{
R
Roman Donchenko 已提交
656
    features = makePtr<std::vector<Feature> >();
657
    optfeatures = makePtr<std::vector<OptFeature> >();
658 659 660 661 662 663 664 665
}
LBPEvaluator::~LBPEvaluator()
{
}

bool LBPEvaluator::read( const FileNode& node )
{
    features->resize(node.size());
666
    optfeaturesPtr = &(*optfeatures)[0];
667
    FileNodeIterator it = node.begin(), it_end = node.end();
668
    std::vector<Feature>& ff = *features;
669 670
    for(int i = 0; it != it_end; ++it, i++)
    {
671
        if(!ff[i].read(*it))
672 673 674 675 676 677 678
            return false;
    }
    return true;
}

Ptr<FeatureEvaluator> LBPEvaluator::clone() const
{
R
Roman Donchenko 已提交
679
    Ptr<LBPEvaluator> ret = makePtr<LBPEvaluator>();
680 681
    ret->origWinSize = origWinSize;
    ret->features = features;
682 683
    ret->optfeatures = optfeatures;
    ret->optfeaturesPtr = ret->optfeatures.empty() ? 0 : &(*ret->optfeatures)[0];
684
    ret->sum0 = sum0, ret->sum = sum;
685
    ret->pwin = pwin;
686 687 688
    return ret;
}

689
bool LBPEvaluator::setImage( InputArray _image, Size _origWinSize, Size _sumSize )
690
{
691 692 693 694
    Size imgsz = _image.size();
    int cols = imgsz.width, rows = imgsz.height;
    
    if (imgsz.width < origWinSize.width || imgsz.height < origWinSize.height)
695
        return false;
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
    
    origWinSize = _origWinSize;
    
    int rn = _sumSize.height, cn = _sumSize.width;
    int sumStep;
    CV_Assert(rn >= rows+1 && cn >= cols+1);
    
    if( _image.isUMat() )
    {
        usum0.create(rn, cn, CV_32S);
        usum = UMat(usum0, Rect(0, 0, cols+1, rows+1));
        
        integral(_image, usum, noArray(), noArray(), CV_32S);
        sumStep = (int)(usum.step/usum.elemSize());
    }
    else
    {
713
        sum0.create(rn, cn, CV_32S);
714 715 716 717 718 719
        sum = sum0(Rect(0, 0, cols+1, rows+1));
        
        integral(_image, sum, noArray(), noArray(), CV_32S);
        sumStep = (int)(sum.step/sum.elemSize());
    }
    
720
    size_t fi, nfeatures = features->size();
721 722 723 724 725 726 727 728 729 730 731 732 733
    const std::vector<Feature>& ff = *features;
    
    if( sumSize0 != _sumSize )
    {
        optfeatures->resize(nfeatures);
        optfeaturesPtr = &(*optfeatures)[0];
        for( fi = 0; fi < nfeatures; fi++ )
            optfeaturesPtr[fi].setOffsets( ff[fi], sumStep );
    }
    if( _image.isUMat() && (sumSize0 != _sumSize || ufbuf.empty()) )
        copyVectorToUMat(*optfeatures, ufbuf);
    sumSize0 = _sumSize;
    
734 735
    return true;
}
A
Andrey Kamaev 已提交
736

737 738 739
bool LBPEvaluator::setWindow( Point pt )
{
    if( pt.x < 0 || pt.y < 0 ||
740 741
        pt.x + origWinSize.width >= sum.cols ||
        pt.y + origWinSize.height >= sum.rows )
742
        return false;
743
    pwin = &sum.at<int>(pt);
744
    return true;
A
Andrey Kamaev 已提交
745
}
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765

//----------------------------------------------  HOGEvaluator ---------------------------------------
bool HOGEvaluator::Feature :: read( const FileNode& node )
{
    FileNode rnode = node[CC_RECT];
    FileNodeIterator it = rnode.begin();
    it >> rect[0].x >> rect[0].y >> rect[0].width >> rect[0].height >> featComponent;
    rect[1].x = rect[0].x + rect[0].width;
    rect[1].y = rect[0].y;
    rect[2].x = rect[0].x;
    rect[2].y = rect[0].y + rect[0].height;
    rect[3].x = rect[0].x + rect[0].width;
    rect[3].y = rect[0].y + rect[0].height;
    rect[1].width = rect[2].width = rect[3].width = rect[0].width;
    rect[1].height = rect[2].height = rect[3].height = rect[0].height;
    return true;
}

HOGEvaluator::HOGEvaluator()
{
R
Roman Donchenko 已提交
766
    features = makePtr<std::vector<Feature> >();
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
}

HOGEvaluator::~HOGEvaluator()
{
}

bool HOGEvaluator::read( const FileNode& node )
{
    features->resize(node.size());
    featuresPtr = &(*features)[0];
    FileNodeIterator it = node.begin(), it_end = node.end();
    for(int i = 0; it != it_end; ++it, i++)
    {
        if(!featuresPtr[i].read(*it))
            return false;
    }
    return true;
}

Ptr<FeatureEvaluator> HOGEvaluator::clone() const
{
R
Roman Donchenko 已提交
788
    Ptr<HOGEvaluator> ret = makePtr<HOGEvaluator>();
789 790 791 792 793
    ret->origWinSize = origWinSize;
    ret->features = features;
    ret->featuresPtr = &(*ret->features)[0];
    ret->offset = offset;
    ret->hist = hist;
A
Andrey Kamaev 已提交
794
    ret->normSum = normSum;
795 796 797
    return ret;
}

798
bool HOGEvaluator::setImage( InputArray _image, Size winSize, Size )
799
{
800
    Mat image = _image.getMat();
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
    int rows = image.rows + 1;
    int cols = image.cols + 1;
    origWinSize = winSize;
    if( image.cols < origWinSize.width || image.rows < origWinSize.height )
        return false;
    hist.clear();
    for( int bin = 0; bin < Feature::BIN_NUM; bin++ )
    {
        hist.push_back( Mat(rows, cols, CV_32FC1) );
    }
    normSum.create( rows, cols, CV_32FC1 );

    integralHistogram( image, hist, normSum, Feature::BIN_NUM );

    size_t featIdx, featCount = features->size();

    for( featIdx = 0; featIdx < featCount; featIdx++ )
    {
        featuresPtr[featIdx].updatePtrs( hist, normSum );
    }
    return true;
822 823
}

824 825 826 827 828 829 830 831 832 833
bool HOGEvaluator::setWindow(Point pt)
{
    if( pt.x < 0 || pt.y < 0 ||
        pt.x + origWinSize.width >= hist[0].cols-2 ||
        pt.y + origWinSize.height >= hist[0].rows-2 )
        return false;
    offset = pt.y * ((int)hist[0].step/sizeof(float)) + pt.x;
    return true;
}

834
void HOGEvaluator::integralHistogram(const Mat &img, std::vector<Mat> &histogram, Mat &norm, int nbins) const
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
{
    CV_Assert( img.type() == CV_8U || img.type() == CV_8UC3 );
    int x, y, binIdx;

    Size gradSize(img.size());
    Size histSize(histogram[0].size());
    Mat grad(gradSize, CV_32F);
    Mat qangle(gradSize, CV_8U);

    AutoBuffer<int> mapbuf(gradSize.width + gradSize.height + 4);
    int* xmap = (int*)mapbuf + 1;
    int* ymap = xmap + gradSize.width + 2;

    const int borderType = (int)BORDER_REPLICATE;

    for( x = -1; x < gradSize.width + 1; x++ )
        xmap[x] = borderInterpolate(x, gradSize.width, borderType);
    for( y = -1; y < gradSize.height + 1; y++ )
        ymap[y] = borderInterpolate(y, gradSize.height, borderType);

    int width = gradSize.width;
    AutoBuffer<float> _dbuf(width*4);
    float* dbuf = _dbuf;
    Mat Dx(1, width, CV_32F, dbuf);
    Mat Dy(1, width, CV_32F, dbuf + width);
    Mat Mag(1, width, CV_32F, dbuf + width*2);
    Mat Angle(1, width, CV_32F, dbuf + width*3);

    float angleScale = (float)(nbins/CV_PI);

    for( y = 0; y < gradSize.height; y++ )
    {
        const uchar* currPtr = img.data + img.step*ymap[y];
        const uchar* prevPtr = img.data + img.step*ymap[y-1];
        const uchar* nextPtr = img.data + img.step*ymap[y+1];
        float* gradPtr = (float*)grad.ptr(y);
        uchar* qanglePtr = (uchar*)qangle.ptr(y);

        for( x = 0; x < width; x++ )
        {
            dbuf[x] = (float)(currPtr[xmap[x+1]] - currPtr[xmap[x-1]]);
            dbuf[width + x] = (float)(nextPtr[xmap[x]] - prevPtr[xmap[x]]);
        }
        cartToPolar( Dx, Dy, Mag, Angle, false );
        for( x = 0; x < width; x++ )
        {
            float mag = dbuf[x+width*2];
            float angle = dbuf[x+width*3];
            angle = angle*angleScale - 0.5f;
            int bidx = cvFloor(angle);
            angle -= bidx;
            if( bidx < 0 )
                bidx += nbins;
            else if( bidx >= nbins )
                bidx -= nbins;

            qanglePtr[x] = (uchar)bidx;
            gradPtr[x] = mag;
        }
    }
    integral(grad, norm, grad.depth());

    float* histBuf;
    const float* magBuf;
    const uchar* binsBuf;

    int binsStep = (int)( qangle.step / sizeof(uchar) );
    int histStep = (int)( histogram[0].step / sizeof(float) );
    int magStep = (int)( grad.step / sizeof(float) );
    for( binIdx = 0; binIdx < nbins; binIdx++ )
    {
        histBuf = (float*)histogram[binIdx].data;
        magBuf = (const float*)grad.data;
        binsBuf = (const uchar*)qangle.data;

        memset( histBuf, 0, histSize.width * sizeof(histBuf[0]) );
        histBuf += histStep + 1;
        for( y = 0; y < qangle.rows; y++ )
A
Andrey Kamaev 已提交
913
        {
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
            histBuf[-1] = 0.f;
            float strSum = 0.f;
            for( x = 0; x < qangle.cols; x++ )
            {
                if( binsBuf[x] == binIdx )
                    strSum += magBuf[x];
                histBuf[x] = histBuf[-histStep + x] + strSum;
            }
            histBuf += histStep;
            binsBuf += binsStep;
            magBuf += magStep;
        }
    }
}

Ptr<FeatureEvaluator> FeatureEvaluator::create( int featureType )
930 931
{
    return featureType == HAAR ? Ptr<FeatureEvaluator>(new HaarEvaluator) :
A
Andrey Kamaev 已提交
932
        featureType == LBP ? Ptr<FeatureEvaluator>(new LBPEvaluator) :
933 934
        featureType == HOG ? Ptr<FeatureEvaluator>(new HOGEvaluator) :
        Ptr<FeatureEvaluator>();
935
}
936

937 938
//---------------------------------------- Classifier Cascade --------------------------------------------

939
CascadeClassifierImpl::CascadeClassifierImpl()
940 941 942
{
}

943
CascadeClassifierImpl::~CascadeClassifierImpl()
A
Andrey Kamaev 已提交
944
{
945
}
946

947
bool CascadeClassifierImpl::empty() const
948
{
R
Roman Donchenko 已提交
949
    return !oldCascade && data.stages.empty();
950 951
}

952
bool CascadeClassifierImpl::load(const String& filename)
953 954
{
    oldCascade.release();
955 956
    data = Data();
    featureEvaluator.release();
A
Andrey Kamaev 已提交
957

958 959 960
    FileStorage fs(filename, FileStorage::READ);
    if( !fs.isOpened() )
        return false;
A
Andrey Kamaev 已提交
961

962
    if( read_(fs.getFirstTopLevelNode()) )
963
        return true;
A
Andrey Kamaev 已提交
964

965
    fs.release();
A
Andrey Kamaev 已提交
966

R
Roman Donchenko 已提交
967
    oldCascade.reset((CvHaarClassifierCascade*)cvLoad(filename.c_str(), 0, 0, 0));
968 969
    return !oldCascade.empty();
}
A
Andrey Kamaev 已提交
970

971 972 973 974 975 976
void CascadeClassifierImpl::read(const FileNode& node)
{
    read_(node);
}

int CascadeClassifierImpl::runAt( Ptr<FeatureEvaluator>& evaluator, Point pt, double& weight )
977
{
R
Roman Donchenko 已提交
978
    CV_Assert( !oldCascade );
A
Andrey Kamaev 已提交
979

980 981 982
    assert( data.featureType == FeatureEvaluator::HAAR ||
            data.featureType == FeatureEvaluator::LBP ||
            data.featureType == FeatureEvaluator::HOG );
983

A
Andrey Kamaev 已提交
984
    if( !evaluator->setWindow(pt) )
985
        return -1;
986
    if( data.isStumpBased() )
987 988
    {
        if( data.featureType == FeatureEvaluator::HAAR )
A
Andrey Kamaev 已提交
989
            return predictOrderedStump<HaarEvaluator>( *this, evaluator, weight );
990
        else if( data.featureType == FeatureEvaluator::LBP )
A
Andrey Kamaev 已提交
991
            return predictCategoricalStump<LBPEvaluator>( *this, evaluator, weight );
992
        else if( data.featureType == FeatureEvaluator::HOG )
A
Andrey Kamaev 已提交
993
            return predictOrderedStump<HOGEvaluator>( *this, evaluator, weight );
994 995 996 997 998 999
        else
            return -2;
    }
    else
    {
        if( data.featureType == FeatureEvaluator::HAAR )
A
Andrey Kamaev 已提交
1000
            return predictOrdered<HaarEvaluator>( *this, evaluator, weight );
1001
        else if( data.featureType == FeatureEvaluator::LBP )
A
Andrey Kamaev 已提交
1002
            return predictCategorical<LBPEvaluator>( *this, evaluator, weight );
1003
        else if( data.featureType == FeatureEvaluator::HOG )
A
Andrey Kamaev 已提交
1004
            return predictOrdered<HOGEvaluator>( *this, evaluator, weight );
1005 1006 1007
        else
            return -2;
    }
1008
}
A
Andrey Kamaev 已提交
1009

1010
void CascadeClassifierImpl::setMaskGenerator(const Ptr<MaskGenerator>& _maskGenerator)
1011 1012 1013
{
    maskGenerator=_maskGenerator;
}
1014
Ptr<CascadeClassifierImpl::MaskGenerator> CascadeClassifierImpl::getMaskGenerator()
1015 1016 1017 1018
{
    return maskGenerator;
}

1019
Ptr<BaseCascadeClassifier::MaskGenerator> createFaceDetectionMaskGenerator()
1020 1021
{
#ifdef HAVE_TEGRA_OPTIMIZATION
1022
    return tegra::getCascadeClassifierMaskGenerator(*this);
1023
#else
1024
    return Ptr<BaseCascadeClassifier::MaskGenerator>();
1025 1026 1027
#endif
}

1028
class CascadeClassifierInvoker : public ParallelLoopBody
1029
{
1030
public:
1031
    CascadeClassifierInvoker( CascadeClassifierImpl& _cc, Size _sz1, int _stripSize, int _yStep, double _factor,
1032
        std::vector<Rect>& _vec, std::vector<int>& _levels, std::vector<double>& _weights, bool outputLevels, const Mat& _mask, Mutex* _mtx)
1033
    {
1034
        classifier = &_cc;
1035
        processingRectSize = _sz1;
1036 1037
        stripSize = _stripSize;
        yStep = _yStep;
1038 1039
        scalingFactor = _factor;
        rectangles = &_vec;
1040 1041 1042 1043
        rejectLevels = outputLevels ? &_levels : 0;
        levelWeights = outputLevels ? &_weights : 0;
        mask = _mask;
        mtx = _mtx;
1044
    }
A
Andrey Kamaev 已提交
1045

1046
    void operator()(const Range& range) const
1047
    {
1048
        Ptr<FeatureEvaluator> evaluator = classifier->featureEvaluator->clone();
1049

1050 1051
        Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor),
                     cvRound(classifier->data.origWinSize.height * scalingFactor));
1052

1053
        int y1 = range.start * stripSize;
1054
        int y2 = std::min(range.end * stripSize, processingRectSize.height);
1055
        for( int y = y1; y < y2; y += yStep )
1056
        {
1057
            for( int x = 0; x < processingRectSize.width; x += yStep )
1058
            {
1059
                if ( (!mask.empty()) && (mask.at<uchar>(Point(x,y))==0)) {
1060 1061 1062
                    continue;
                }

1063 1064
                double gypWeight;
                int result = classifier->runAt(evaluator, Point(x, y), gypWeight);
1065

1066 1067 1068 1069
#if defined (LOG_CASCADE_STATISTIC)

                logger.setPoint(Point(x, y), result);
#endif
1070 1071 1072
                if( rejectLevels )
                {
                    if( result == 1 )
1073
                        result =  -(int)classifier->data.stages.size();
1074
                    if( classifier->data.stages.size() + result == 0 )
1075
                    {
1076
                        mtx->lock();
A
Andrey Kamaev 已提交
1077
                        rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), winSize.width, winSize.height));
1078
                        rejectLevels->push_back(-result);
1079
                        levelWeights->push_back(gypWeight);
1080
                        mtx->unlock();
1081
                    }
A
Andrey Kamaev 已提交
1082
                }
1083
                else if( result > 0 )
1084 1085
                {
                    mtx->lock();
1086
                    rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor),
1087
                                               winSize.width, winSize.height));
1088 1089
                    mtx->unlock();
                }
1090
                if( result == 0 )
1091 1092
                    x += yStep;
            }
1093
        }
1094
    }
A
Andrey Kamaev 已提交
1095

1096
    CascadeClassifierImpl* classifier;
1097
    std::vector<Rect>* rectangles;
1098
    Size processingRectSize;
1099
    int stripSize, yStep;
1100
    double scalingFactor;
1101 1102
    std::vector<int> *rejectLevels;
    std::vector<double> *levelWeights;
1103
    Mat mask;
1104
    Mutex* mtx;
1105
};
A
Andrey Kamaev 已提交
1106

1107
struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } };
1108
struct getNeighbors { int operator ()(const CvAvgComp& e) const { return e.neighbors; } };
1109

1110

1111 1112
bool CascadeClassifierImpl::detectSingleScale( InputArray _image, Size processingRectSize,
                                           int yStep, double factor, std::vector<Rect>& candidates,
1113 1114
                                           std::vector<int>& levels, std::vector<double>& weights,
                                           Size sumSize0, bool outputRejectLevels )
1115
{
1116
    if( !featureEvaluator->setImage(_image, data.origWinSize, sumSize0) )
1117 1118
        return false;

1119
#if defined (LOG_CASCADE_STATISTIC)
1120
    logger.setImage(image);
1121
#endif
1122

1123
    Mat currentMask;
R
Roman Donchenko 已提交
1124
    if (maskGenerator) {
1125
        Mat image = _image.getMat();
1126 1127 1128
        currentMask=maskGenerator->generateMask(image);
    }

1129 1130 1131
    std::vector<Rect> candidatesVector;
    std::vector<int> rejectLevels;
    std::vector<double> levelWeights;
1132

1133
    int stripCount, stripSize;
1134

1135 1136 1137 1138
    const int PTS_PER_THREAD = 1000;
    stripCount = ((processingRectSize.width/yStep)*(processingRectSize.height + yStep-1)/yStep + PTS_PER_THREAD/2)/PTS_PER_THREAD;
    stripCount = std::min(std::max(stripCount, 1), 100);
    stripSize = (((processingRectSize.height + stripCount - 1)/stripCount + yStep-1)/yStep)*yStep;
1139

1140 1141
    if( outputRejectLevels )
    {
1142 1143
        parallel_for_(Range(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor,
            candidatesVector, rejectLevels, levelWeights, true, currentMask, &mtx));
1144
        levels.insert( levels.end(), rejectLevels.begin(), rejectLevels.end() );
1145
        weights.insert( weights.end(), levelWeights.begin(), levelWeights.end() );
1146 1147 1148
    }
    else
    {
1149 1150
         parallel_for_(Range(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor,
            candidatesVector, rejectLevels, levelWeights, false, currentMask, &mtx));
1151
    }
1152
    candidates.insert( candidates.end(), candidatesVector.begin(), candidatesVector.end() );
1153

1154 1155 1156 1157 1158
#if defined (LOG_CASCADE_STATISTIC)
    logger.write();
#endif

    return true;
1159 1160
}

1161

1162
bool CascadeClassifierImpl::ocl_detectSingleScale( InputArray _image, Size processingRectSize,
1163
                                                   int yStep, double factor, Size sumSize0 )
1164
{
1165
    const int VECTOR_SIZE = 1;
1166 1167 1168
    Ptr<HaarEvaluator> haar = featureEvaluator.dynamicCast<HaarEvaluator>();
    if( haar.empty() )
        return false;
1169

1170
    haar->setImage(_image, data.origWinSize, sumSize0);
1171

1172 1173
    if( cascadeKernel.empty() )
    {
1174
        cascadeKernel.create("runHaarClassifierStump", ocl::objdetect::cascadedetect_oclsrc,
1175
                             format("-D VECTOR_SIZE=%d", VECTOR_SIZE));
1176 1177 1178
        if( cascadeKernel.empty() )
            return false;
    }
1179

1180 1181
    if( ustages.empty() )
    {
1182 1183
        copyVectorToUMat(data.stages, ustages);
        copyVectorToUMat(data.stumps, ustumps);
1184
    }
1185

1186 1187
    std::vector<UMat> bufs;
    haar->getUMats(bufs);
1188
    CV_Assert(bufs.size() == 3);
1189

V
Vadim Pisarevsky 已提交
1190
    Rect normrect = haar->getNormRect();
1191

V
Vadim Pisarevsky 已提交
1192
    //processingRectSize = Size(yStep, yStep);
1193
    size_t globalsize[] = { (processingRectSize.width/yStep + VECTOR_SIZE-1)/VECTOR_SIZE, processingRectSize.height/yStep };
1194

V
Vadim Pisarevsky 已提交
1195 1196
    cascadeKernel.args(ocl::KernelArg::ReadOnlyNoSize(bufs[0]), // sum
                       ocl::KernelArg::ReadOnlyNoSize(bufs[1]), // sqsum
1197
                       ocl::KernelArg::PtrReadOnly(bufs[2]), // optfeatures
1198

1199
                       // cascade classifier
V
Vadim Pisarevsky 已提交
1200
                       (int)data.stages.size(),
1201
                       ocl::KernelArg::PtrReadOnly(ustages),
1202
                       ocl::KernelArg::PtrReadOnly(ustumps),
1203

V
Vadim Pisarevsky 已提交
1204 1205 1206
                       ocl::KernelArg::PtrWriteOnly(ufacepos), // positions
                       processingRectSize,
                       yStep, (float)factor,
1207
                       normrect, data.origWinSize, MAX_FACES);
V
Vadim Pisarevsky 已提交
1208 1209 1210
    bool ok = cascadeKernel.run(2, globalsize, 0, true);
    //CV_Assert(ok);
    return ok;
1211 1212
}

1213
bool CascadeClassifierImpl::isOldFormatCascade() const
1214 1215 1216 1217
{
    return !oldCascade.empty();
}

1218
int CascadeClassifierImpl::getFeatureType() const
1219 1220 1221 1222
{
    return featureEvaluator->getFeatureType();
}

1223
Size CascadeClassifierImpl::getOriginalWindowSize() const
1224 1225 1226 1227
{
    return data.origWinSize;
}

1228 1229 1230 1231 1232
void* CascadeClassifierImpl::getOldCascade()
{
    return oldCascade;
}

1233 1234 1235 1236 1237 1238 1239 1240
static void detectMultiScaleOldFormat( const Mat& image, Ptr<CvHaarClassifierCascade> oldCascade,
                                       std::vector<Rect>& objects,
                                       std::vector<int>& rejectLevels,
                                       std::vector<double>& levelWeights,
                                       std::vector<CvAvgComp>& vecAvgComp,
                                       double scaleFactor, int minNeighbors,
                                       int flags, Size minObjectSize, Size maxObjectSize,
                                       bool outputRejectLevels = false )
1241
{
1242 1243 1244 1245 1246 1247 1248 1249
    MemStorage storage(cvCreateMemStorage(0));
    CvMat _image = image;
    CvSeq* _objects = cvHaarDetectObjectsForROC( &_image, oldCascade, storage, rejectLevels, levelWeights, scaleFactor,
                                                 minNeighbors, flags, minObjectSize, maxObjectSize, outputRejectLevels );
    Seq<CvAvgComp>(_objects).copyTo(vecAvgComp);
    objects.resize(vecAvgComp.size());
    std::transform(vecAvgComp.begin(), vecAvgComp.end(), objects.begin(), getRect());
}
1250

1251

1252
void CascadeClassifierImpl::detectMultiScaleNoGrouping( InputArray _image, std::vector<Rect>& candidates,
1253 1254 1255 1256
                                                    std::vector<int>& rejectLevels, std::vector<double>& levelWeights,
                                                    double scaleFactor, Size minObjectSize, Size maxObjectSize,
                                                    bool outputRejectLevels )
{
1257 1258
    Size imgsz = _image.size();
    int imgtype = _image.type();
1259

1260
    Mat grayImage, imageBuffer;
1261

1262
    candidates.clear();
1263 1264
    rejectLevels.clear();
    levelWeights.clear();
1265

1266
    if( maxObjectSize.height == 0 || maxObjectSize.width == 0 )
1267
        maxObjectSize = imgsz;
1268

V
Vadim Pisarevsky 已提交
1269
    bool use_ocl = ocl::useOpenCL() &&
1270 1271
        getFeatureType() == FeatureEvaluator::HAAR &&
        !isOldFormatCascade() &&
1272
        data.isStumpBased() &&
1273 1274
        maskGenerator.empty() &&
        !outputRejectLevels &&
V
Vadim Pisarevsky 已提交
1275
        tryOpenCL;
1276

1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
    if( !use_ocl )
    {
        Mat image = _image.getMat();
        if (maskGenerator)
            maskGenerator->initializeMask(image);

        grayImage = image;
        if( CV_MAT_CN(imgtype) > 1 )
        {
            Mat temp;
            cvtColor(grayImage, temp, COLOR_BGR2GRAY);
            grayImage = temp;
        }
A
Andrey Kamaev 已提交
1290

1291 1292 1293
        imageBuffer.create(imgsz.height + 1, imgsz.width + 1, CV_8U);
    }
    else
1294
    {
1295 1296 1297 1298 1299 1300
        UMat uimage = _image.getUMat();
        if( CV_MAT_CN(imgtype) > 1 )
            cvtColor(uimage, ugrayImage, COLOR_BGR2GRAY);
        else
            uimage.copyTo(ugrayImage);
        uimageBuffer.create(imgsz.height + 1, imgsz.width + 1, CV_8U);
1301
    }
1302

1303
    Size sumSize0((imgsz.width + SUM_ALIGN) & -SUM_ALIGN, imgsz.height+1);
1304

V
Vadim Pisarevsky 已提交
1305 1306 1307 1308 1309 1310
    if( use_ocl )
    {
        ufacepos.create(1, MAX_FACES*4 + 1, CV_32S);
        UMat ufacecount(ufacepos, Rect(0,0,1,1));
        ufacecount.setTo(Scalar::all(0));
    }
A
Andrey Kamaev 已提交
1311

1312 1313
    for( double factor = 1; ; factor *= scaleFactor )
    {
1314
        Size originalWindowSize = getOriginalWindowSize();
1315

1316
        Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );
V
Vadim Pisarevsky 已提交
1317
        Size scaledImageSize( cvRound( imgsz.width/factor ), cvRound( imgsz.height/factor ) );
1318 1319
        Size processingRectSize( scaledImageSize.width - originalWindowSize.width,
                                 scaledImageSize.height - originalWindowSize.height );
A
Andrey Kamaev 已提交
1320

1321
        if( processingRectSize.width <= 0 || processingRectSize.height <= 0 )
1322
            break;
1323
        if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height )
1324
            break;
1325
        if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height )
1326
            continue;
1327

1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
        int yStep;
        if( getFeatureType() == cv::FeatureEvaluator::HOG )
        {
            yStep = 4;
        }
        else
        {
            yStep = factor > 2. ? 1 : 2;
        }

1338 1339 1340 1341
        if( use_ocl )
        {
            UMat uscaledImage(uimageBuffer, Rect(0, 0, scaledImageSize.width, scaledImageSize.height));
            resize( ugrayImage, uscaledImage, scaledImageSize, 0, 0, INTER_LINEAR );
1342

1343
            if( ocl_detectSingleScale( uscaledImage, processingRectSize, yStep, factor, sumSize0 ) )
1344
                continue;
1345

1346
            /////// if the OpenCL branch has been executed but failed, fall back to CPU: /////
1347

1348
            tryOpenCL = false; // for this cascade do not try OpenCL anymore
1349

1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361
            // since we may already have some partial results from OpenCL code (unlikely, but still),
            // we just recursively call the function again, but with tryOpenCL==false it will
            // go with CPU route, so there is no infinite recursion
            detectMultiScaleNoGrouping( _image, candidates, rejectLevels, levelWeights,
                                       scaleFactor, minObjectSize, maxObjectSize,
                                       outputRejectLevels);
            return;
        }
        else
        {
            Mat scaledImage( scaledImageSize, CV_8U, imageBuffer.data );
            resize( grayImage, scaledImage, scaledImageSize, 0, 0, INTER_LINEAR );
1362

1363
            if( !detectSingleScale( scaledImage, processingRectSize, yStep, factor, candidates,
1364
                                    rejectLevels, levelWeights, sumSize0, outputRejectLevels ) )
1365 1366
                break;
        }
1367
    }
1368

1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
    if( use_ocl && tryOpenCL )
    {
        Mat facepos = ufacepos.getMat(ACCESS_READ);
        const int* fptr = facepos.ptr<int>();
        int i, nfaces = fptr[0];
        for( i = 0; i < nfaces; i++ )
        {
            candidates.push_back(Rect(fptr[i*4+1], fptr[i*4+2], fptr[i*4+3], fptr[i*4+4]));
        }
    }
1379
}
1380

1381
void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rect>& objects,
1382 1383 1384 1385 1386 1387
                                          std::vector<int>& rejectLevels,
                                          std::vector<double>& levelWeights,
                                          double scaleFactor, int minNeighbors,
                                          int flags, Size minObjectSize, Size maxObjectSize,
                                          bool outputRejectLevels )
{
1388
    CV_Assert( scaleFactor > 1 && _image.depth() == CV_8U );
A
Andrey Kamaev 已提交
1389

1390 1391
    if( empty() )
        return;
1392

1393
    if( isOldFormatCascade() )
1394
    {
1395
        Mat image = _image.getMat();
1396 1397 1398
        std::vector<CvAvgComp> fakeVecAvgComp;
        detectMultiScaleOldFormat( image, oldCascade, objects, rejectLevels, levelWeights, fakeVecAvgComp, scaleFactor,
                                   minNeighbors, flags, minObjectSize, maxObjectSize, outputRejectLevels );
1399 1400 1401
    }
    else
    {
1402
        detectMultiScaleNoGrouping( _image, objects, rejectLevels, levelWeights, scaleFactor, minObjectSize, maxObjectSize,
1403 1404 1405 1406 1407 1408 1409 1410 1411 1412
                                    outputRejectLevels );
        const double GROUP_EPS = 0.2;
        if( outputRejectLevels )
        {
            groupRectangles( objects, rejectLevels, levelWeights, minNeighbors, GROUP_EPS );
        }
        else
        {
            groupRectangles( objects, minNeighbors, GROUP_EPS );
        }
1413
    }
A
Alexey Kazakov 已提交
1414 1415
}

1416
void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rect>& objects,
A
Alexey Kazakov 已提交
1417 1418 1419
                                          double scaleFactor, int minNeighbors,
                                          int flags, Size minObjectSize, Size maxObjectSize)
{
1420
    Mat image = _image.getMat();
1421 1422
    std::vector<int> fakeLevels;
    std::vector<double> fakeWeights;
A
Andrey Kamaev 已提交
1423
    detectMultiScale( image, objects, fakeLevels, fakeWeights, scaleFactor,
1424 1425 1426
        minNeighbors, flags, minObjectSize, maxObjectSize );
}

1427
void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rect>& objects,
1428 1429 1430 1431
                                          std::vector<int>& numDetections, double scaleFactor,
                                          int minNeighbors, int flags, Size minObjectSize,
                                          Size maxObjectSize )
{
1432
    Mat image = _image.getMat();
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
    CV_Assert( scaleFactor > 1 && image.depth() == CV_8U );

    if( empty() )
        return;

    std::vector<int> fakeLevels;
    std::vector<double> fakeWeights;
    if( isOldFormatCascade() )
    {
        std::vector<CvAvgComp> vecAvgComp;
        detectMultiScaleOldFormat( image, oldCascade, objects, fakeLevels, fakeWeights, vecAvgComp, scaleFactor,
                                   minNeighbors, flags, minObjectSize, maxObjectSize );
        numDetections.resize(vecAvgComp.size());
        std::transform(vecAvgComp.begin(), vecAvgComp.end(), numDetections.begin(), getNeighbors());
    }
    else
    {
        detectMultiScaleNoGrouping( image, objects, fakeLevels, fakeWeights, scaleFactor, minObjectSize, maxObjectSize );
        const double GROUP_EPS = 0.2;
        groupRectangles( objects, numDetections, minNeighbors, GROUP_EPS );
    }
A
Andrey Kamaev 已提交
1454
}
1455

1456

1457 1458 1459 1460
CascadeClassifierImpl::Data::Data()
{
    stageType = featureType = ncategories = maxNodesPerTree = 0;
}
1461

1462
bool CascadeClassifierImpl::Data::read(const FileNode &root)
1463
{
1464
    static const float THRESHOLD_EPS = 1e-5f;
A
Andrey Kamaev 已提交
1465

1466
    // load stage params
1467
    String stageTypeStr = (String)root[CC_STAGE_TYPE];
1468 1469 1470 1471
    if( stageTypeStr == CC_BOOST )
        stageType = BOOST;
    else
        return false;
1472

1473
    String featureTypeStr = (String)root[CC_FEATURE_TYPE];
1474 1475 1476 1477
    if( featureTypeStr == CC_HAAR )
        featureType = FeatureEvaluator::HAAR;
    else if( featureTypeStr == CC_LBP )
        featureType = FeatureEvaluator::LBP;
1478 1479 1480
    else if( featureTypeStr == CC_HOG )
        featureType = FeatureEvaluator::HOG;

1481 1482
    else
        return false;
1483

1484 1485 1486
    origWinSize.width = (int)root[CC_WIDTH];
    origWinSize.height = (int)root[CC_HEIGHT];
    CV_Assert( origWinSize.height > 0 && origWinSize.width > 0 );
1487

1488 1489 1490 1491
    // load feature params
    FileNode fn = root[CC_FEATURE_PARAMS];
    if( fn.empty() )
        return false;
1492

1493 1494 1495
    ncategories = fn[CC_MAX_CAT_COUNT];
    int subsetSize = (ncategories + 31)/32,
        nodeStep = 3 + ( ncategories>0 ? subsetSize : 1 );
1496

1497 1498 1499 1500
    // load stages
    fn = root[CC_STAGES];
    if( fn.empty() )
        return false;
1501

1502 1503 1504
    stages.reserve(fn.size());
    classifiers.clear();
    nodes.clear();
1505
    stumps.clear();
1506

1507
    FileNodeIterator it = fn.begin(), it_end = fn.end();
1508
    maxNodesPerTree = 0;
1509

1510 1511 1512 1513
    for( int si = 0; it != it_end; si++, ++it )
    {
        FileNode fns = *it;
        Stage stage;
1514
        stage.threshold = (float)fns[CC_STAGE_THRESHOLD] - THRESHOLD_EPS;
1515 1516 1517 1518 1519 1520 1521
        fns = fns[CC_WEAK_CLASSIFIERS];
        if(fns.empty())
            return false;
        stage.ntrees = (int)fns.size();
        stage.first = (int)classifiers.size();
        stages.push_back(stage);
        classifiers.reserve(stages[si].first + stages[si].ntrees);
1522

1523 1524 1525 1526 1527 1528 1529 1530
        FileNodeIterator it1 = fns.begin(), it1_end = fns.end();
        for( ; it1 != it1_end; ++it1 ) // weak trees
        {
            FileNode fnw = *it1;
            FileNode internalNodes = fnw[CC_INTERNAL_NODES];
            FileNode leafValues = fnw[CC_LEAF_VALUES];
            if( internalNodes.empty() || leafValues.empty() )
                return false;
1531

1532 1533
            DTree tree;
            tree.nodeCount = (int)internalNodes.size()/nodeStep;
1534
            maxNodesPerTree = std::max(maxNodesPerTree, tree.nodeCount);
1535

1536
            classifiers.push_back(tree);
1537

1538 1539 1540 1541
            nodes.reserve(nodes.size() + tree.nodeCount);
            leaves.reserve(leaves.size() + leafValues.size());
            if( subsetSize > 0 )
                subsets.reserve(subsets.size() + tree.nodeCount*subsetSize);
1542 1543 1544 1545

            FileNodeIterator internalNodesIter = internalNodes.begin(), internalNodesEnd = internalNodes.end();

            for( ; internalNodesIter != internalNodesEnd; ) // nodes
1546 1547
            {
                DTreeNode node;
1548 1549 1550
                node.left = (int)*internalNodesIter; ++internalNodesIter;
                node.right = (int)*internalNodesIter; ++internalNodesIter;
                node.featureIdx = (int)*internalNodesIter; ++internalNodesIter;
1551 1552
                if( subsetSize > 0 )
                {
1553 1554
                    for( int j = 0; j < subsetSize; j++, ++internalNodesIter )
                        subsets.push_back((int)*internalNodesIter);
1555 1556 1557 1558
                    node.threshold = 0.f;
                }
                else
                {
1559
                    node.threshold = (float)*internalNodesIter; ++internalNodesIter;
1560 1561 1562
                }
                nodes.push_back(node);
            }
1563 1564 1565 1566 1567

            internalNodesIter = leafValues.begin(), internalNodesEnd = leafValues.end();

            for( ; internalNodesIter != internalNodesEnd; ++internalNodesIter ) // leaves
                leaves.push_back((float)*internalNodesIter);
1568 1569
        }
    }
1570

1571 1572 1573 1574 1575 1576 1577
    if( isStumpBased() )
    {
        int nodeOfs = 0, leafOfs = 0;
        size_t nstages = stages.size();
        for( size_t stageIdx = 0; stageIdx < nstages; stageIdx++ )
        {
            const Stage& stage = stages[stageIdx];
1578

1579 1580 1581 1582 1583 1584 1585 1586 1587
            int ntrees = stage.ntrees;
            for( int i = 0; i < ntrees; i++, nodeOfs++, leafOfs+= 2 )
            {
                const DTreeNode& node = nodes[nodeOfs];
                stumps.push_back(Stump(node.featureIdx, node.threshold,
                                       leaves[leafOfs], leaves[leafOfs+1]));
            }
        }
    }
1588

1589 1590 1591
    return true;
}

1592

1593
bool CascadeClassifierImpl::read_(const FileNode& root)
1594
{
1595 1596 1597
    tryOpenCL = true;
    cascadeKernel = ocl::Kernel();
    ustages.release();
1598
    ustumps.release();
1599 1600 1601
    if( !data.read(root) )
        return false;

1602
    // load features
1603 1604
    featureEvaluator = FeatureEvaluator::create(data.featureType);
    FileNode fn = root[CC_FEATURES];
1605 1606
    if( fn.empty() )
        return false;
A
Andrey Kamaev 已提交
1607

1608
    return featureEvaluator->read(fn);
1609
}
A
Andrey Kamaev 已提交
1610

R
Roman Donchenko 已提交
1611
template<> void DefaultDeleter<CvHaarClassifierCascade>::operator ()(CvHaarClassifierCascade* obj) const
A
Andrey Kamaev 已提交
1612
{ cvReleaseHaarClassifierCascade(&obj); }
1613

1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641

BaseCascadeClassifier::~BaseCascadeClassifier()
{
}

CascadeClassifier::CascadeClassifier() {}
CascadeClassifier::CascadeClassifier(const String& filename)
{
    load(filename);
}

CascadeClassifier::~CascadeClassifier()
{
}

bool CascadeClassifier::empty() const
{
    return cc.empty() || cc->empty();
}

bool CascadeClassifier::load( const String& filename )
{
    cc = makePtr<CascadeClassifierImpl>();
    if(!cc->load(filename))
        cc.release();
    return !empty();
}

1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
bool CascadeClassifier::read(const FileNode &root)
{
    Ptr<CascadeClassifierImpl> ccimpl;
    bool ok = ccimpl->read_(root);
    if( ok )
        cc = ccimpl.staticCast<BaseCascadeClassifier>();
    else
        cc.release();
    return ok;
}

1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714
void CascadeClassifier::detectMultiScale( InputArray image,
                      CV_OUT std::vector<Rect>& objects,
                      double scaleFactor,
                      int minNeighbors, int flags,
                      Size minSize,
                      Size maxSize )
{
    CV_Assert(!empty());
    cc->detectMultiScale(image, objects, scaleFactor, minNeighbors, flags, minSize, maxSize);
}

void CascadeClassifier::detectMultiScale( InputArray image,
                      CV_OUT std::vector<Rect>& objects,
                      CV_OUT std::vector<int>& numDetections,
                      double scaleFactor,
                      int minNeighbors, int flags,
                      Size minSize, Size maxSize )
{
    CV_Assert(!empty());
    cc->detectMultiScale(image, objects, numDetections,
                         scaleFactor, minNeighbors, flags, minSize, maxSize);
}

void CascadeClassifier::detectMultiScale( InputArray image,
                      CV_OUT std::vector<Rect>& objects,
                      CV_OUT std::vector<int>& rejectLevels,
                      CV_OUT std::vector<double>& levelWeights,
                      double scaleFactor,
                      int minNeighbors, int flags,
                      Size minSize, Size maxSize,
                      bool outputRejectLevels )
{
    CV_Assert(!empty());
    cc->detectMultiScale(image, objects, rejectLevels, levelWeights,
                         scaleFactor, minNeighbors, flags,
                         minSize, maxSize, outputRejectLevels);
}

bool CascadeClassifier::isOldFormatCascade() const
{
    CV_Assert(!empty());
    return cc->isOldFormatCascade();
}

Size CascadeClassifier::getOriginalWindowSize() const
{
    CV_Assert(!empty());
    return cc->getOriginalWindowSize();
}

int CascadeClassifier::getFeatureType() const
{
    CV_Assert(!empty());
    return cc->getFeatureType();
}

void* CascadeClassifier::getOldCascade()
{
    CV_Assert(!empty());
    return cc->getOldCascade();
}

1715
void CascadeClassifier::setMaskGenerator(const Ptr<BaseCascadeClassifier::MaskGenerator>& maskGenerator)
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726
{
    CV_Assert(!empty());
    cc->setMaskGenerator(maskGenerator);
}

Ptr<BaseCascadeClassifier::MaskGenerator> CascadeClassifier::getMaskGenerator()
{
    CV_Assert(!empty());
    return cc->getMaskGenerator();
}

1727
} // namespace cv