cascadedetect.cpp 52.5 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 50
namespace cv
{
51

52 53
template<typename _Tp> void copyVectorToUMat(const std::vector<_Tp>& v, UMat& um)
{
54 55 56
    if(v.empty())
        um.release();
    Mat(1, (int)(v.size()*sizeof(v[0])), CV_8U, (void*)&v[0]).copyTo(um);
57
}
A
Andrey Kamaev 已提交
58

59 60
void groupRectangles(std::vector<Rect>& rectList, int groupThreshold, double eps,
                     std::vector<int>* weights, std::vector<double>* levelWeights)
61 62 63 64 65 66 67 68 69 70 71 72
{
    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 已提交
73

74
    std::vector<int> labels;
75
    int nclasses = partition(rectList, labels, SimilarRects(eps));
A
Andrey Kamaev 已提交
76

77 78 79 80
    std::vector<Rect> rrects(nclasses);
    std::vector<int> rweights(nclasses, 0);
    std::vector<int> rejectLevels(nclasses, 0);
    std::vector<double> rejectWeights(nclasses, DBL_MIN);
81 82 83 84 85 86 87 88 89 90
    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]++;
    }
91
    if ( levelWeights && weights && !weights->empty() && !levelWeights->empty() )
A
Andrey Kamaev 已提交
92 93 94 95
    {
        for( i = 0; i < nlabels; i++ )
        {
            int cls = labels[i];
96 97 98 99 100 101 102
            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 已提交
103 104 105
        }
    }

106 107 108 109 110 111 112 113 114
    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 已提交
115

116 117 118
    rectList.clear();
    if( weights )
        weights->clear();
A
Andrey Kamaev 已提交
119 120 121
    if( levelWeights )
        levelWeights->clear();

122 123 124
    for( i = 0; i < nclasses; i++ )
    {
        Rect r1 = rrects[i];
125
        int n1 = rweights[i];
A
Andrey Kamaev 已提交
126
        double w1 = rejectWeights[i];
127
        int l1 = rejectLevels[i];
128

129
        // filter out rectangles which don't have enough similar rectangles
130 131 132 133 134 135
        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 已提交
136

137 138 139
            if( j == i || n2 <= groupThreshold )
                continue;
            Rect r2 = rrects[j];
A
Andrey Kamaev 已提交
140

141 142
            int dx = saturate_cast<int>( r2.width * eps );
            int dy = saturate_cast<int>( r2.height * eps );
A
Andrey Kamaev 已提交
143

144 145 146 147 148 149 150 151
            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 已提交
152

153 154 155 156
        if( j == nclasses )
        {
            rectList.push_back(r1);
            if( weights )
157
                weights->push_back(l1);
A
Andrey Kamaev 已提交
158 159
            if( levelWeights )
                levelWeights->push_back(w1);
160 161 162 163
        }
    }
}

164 165 166
class MeanshiftGrouping
{
public:
167 168
    MeanshiftGrouping(const Point3d& densKer, const std::vector<Point3d>& posV,
        const std::vector<double>& wV, double eps, int maxIter = 20)
169
    {
A
Andrey Kamaev 已提交
170
        densityKernel = densKer;
171 172
        weightsV = wV;
        positionsV = posV;
173
        positionsCount = (int)posV.size();
A
Andrey Kamaev 已提交
174
        meanshiftV.resize(positionsCount);
175
        distanceV.resize(positionsCount);
A
Andrey Kamaev 已提交
176
        iterMax = maxIter;
S
Siegfried Hochdorfer 已提交
177
        modeEps = eps;
A
Andrey Kamaev 已提交
178 179 180 181 182 183 184

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

187
    void getModes(std::vector<Point3d>& modesV, std::vector<double>& resWeightsV, const double eps)
188
    {
A
Andrey Kamaev 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
        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]);
        }
212 213 214
    }

protected:
215 216
    std::vector<Point3d> positionsV;
    std::vector<double> weightsV;
217

A
Andrey Kamaev 已提交
218 219
    Point3d densityKernel;
    int positionsCount;
220

221 222
    std::vector<Point3d> meanshiftV;
    std::vector<Point3d> distanceV;
A
Andrey Kamaev 已提交
223 224
    int iterMax;
    double modeEps;
225

A
Andrey Kamaev 已提交
226
    Point3d getNewValue(const Point3d& inPt) const
227
    {
A
Andrey Kamaev 已提交
228 229 230 231 232 233 234 235
        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;

236 237
            sPt.x *= std::exp(aPt.z);
            sPt.y *= std::exp(aPt.z);
A
Andrey Kamaev 已提交
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

            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;
259 260
    }

A
Andrey Kamaev 已提交
261
    double getResultWeight(const Point3d& inPt) const
262
    {
A
Andrey Kamaev 已提交
263 264 265 266 267 268
        double sumW=0;
        for (size_t i=0; i<positionsV.size(); i++)
        {
            Point3d aPt = positionsV[i];
            Point3d sPt = densityKernel;

269 270
            sPt.x *= std::exp(aPt.z);
            sPt.y *= std::exp(aPt.z);
A
Andrey Kamaev 已提交
271 272 273 274 275 276 277 278 279 280

            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;
281
    }
A
Andrey Kamaev 已提交
282 283

    Point3d moveToMode(Point3d aPt) const
284
    {
A
Andrey Kamaev 已提交
285 286 287 288 289 290 291 292 293 294 295
        Point3d bPt;
        for (int i = 0; i<iterMax; i++)
        {
            bPt = aPt;
            aPt = getNewValue(bPt);
            if ( getDistance(aPt, bPt) <= modeEps )
            {
                break;
            }
        }
        return aPt;
296 297 298 299
    }

    double getDistance(Point3d p1, Point3d p2) const
    {
A
Andrey Kamaev 已提交
300
        Point3d ns = densityKernel;
301 302
        ns.x *= std::exp(p2.z);
        ns.y *= std::exp(p2.z);
A
Andrey Kamaev 已提交
303 304 305 306 307
        p2 -= p1;
        p2.x /= ns.x;
        p2.y /= ns.y;
        p2.z /= ns.z;
        return p2.dot(p2);
308 309
    }
};
310
//new grouping function with using meanshift
311 312
static void groupRectangles_meanshift(std::vector<Rect>& rectList, double detectThreshold, std::vector<double>* foundWeights,
                                      std::vector<double>& scales, Size winDetSize)
313
{
314
    int detectionCount = (int)rectList.size();
315 316
    std::vector<Point3d> hits(detectionCount), resultHits;
    std::vector<double> hitWeights(detectionCount), resultWeights;
317 318
    Point2d hitCenter;

A
Andrey Kamaev 已提交
319
    for (int i=0; i < detectionCount; i++)
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
    {
        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 已提交
337
    for (unsigned i=0; i < resultHits.size(); ++i)
338 339
    {

340
        double scale = std::exp(resultHits[i].z);
341 342 343
        hitCenter.x = resultHits[i].x;
        hitCenter.y = resultHits[i].y;
        Size s( int(winDetSize.width * scale), int(winDetSize.height * scale) );
A
Andrey Kamaev 已提交
344 345
        Rect resultRect( int(hitCenter.x-s.width/2), int(hitCenter.y-s.height/2),
            int(s.width), int(s.height) );
346

A
Andrey Kamaev 已提交
347
        if (resultWeights[i] > detectThreshold)
348 349 350 351 352 353
        {
            rectList.push_back(resultRect);
            foundWeights->push_back(resultWeights[i]);
        }
    }
}
354

355
void groupRectangles(std::vector<Rect>& rectList, int groupThreshold, double eps)
356
{
357
    groupRectangles(rectList, groupThreshold, eps, 0, 0);
358
}
359

360
void groupRectangles(std::vector<Rect>& rectList, std::vector<int>& weights, int groupThreshold, double eps)
361
{
362 363
    groupRectangles(rectList, groupThreshold, eps, &weights, 0);
}
364
//used for cascade detection algorithm for ROC-curve calculating
365 366
void groupRectangles(std::vector<Rect>& rectList, std::vector<int>& rejectLevels,
                     std::vector<double>& levelWeights, int groupThreshold, double eps)
367
{
368
    groupRectangles(rectList, groupThreshold, eps, &rejectLevels, &levelWeights);
369
}
370
//can be used for HOG detection algorithm only
371 372
void groupRectangles_meanshift(std::vector<Rect>& rectList, std::vector<double>& foundWeights,
                               std::vector<double>& foundScales, double detectThreshold, Size winDetSize)
373
{
A
Andrey Kamaev 已提交
374
    groupRectangles_meanshift(rectList, detectThreshold, &foundWeights, foundScales, winDetSize);
375 376
}

A
Andrey Kamaev 已提交
377

378
FeatureEvaluator::~FeatureEvaluator() {}
379 380 381 382 383 384 385 386 387 388 389 390

bool FeatureEvaluator::read(const FileNode&, Size _origWinSize)
{
    origWinSize = _origWinSize;
    localSize = lbufSize = Size(0, 0);
    if (scaleData.empty())
        scaleData = makePtr<std::vector<ScaleData> >();
    else
        scaleData->clear();
    return true;
}

391 392
Ptr<FeatureEvaluator> FeatureEvaluator::clone() const { return Ptr<FeatureEvaluator>(); }
int FeatureEvaluator::getFeatureType() const {return -1;}
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
bool FeatureEvaluator::setWindow(Point, int) { return true; }
void FeatureEvaluator::getUMats(std::vector<UMat>& bufs)
{
    if (!(sbufFlag & USBUF_VALID))
    {
        sbuf.copyTo(usbuf);
        sbufFlag |= USBUF_VALID;
    }

    bufs.clear();
    bufs.push_back(uscaleData);
    bufs.push_back(usbuf);
    bufs.push_back(ufbuf);
}

void FeatureEvaluator::getMats()
{
    if (!(sbufFlag & SBUF_VALID))
    {
        usbuf.copyTo(sbuf);
        sbufFlag |= SBUF_VALID;
    }
}

float FeatureEvaluator::calcOrd(int) const { return 0.; }
418 419
int FeatureEvaluator::calcCat(int) const { return 0; }

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
bool FeatureEvaluator::updateScaleData( Size imgsz, const std::vector<float>& _scales )
{
    if( scaleData.empty() )
        scaleData = makePtr<std::vector<ScaleData> >();

    size_t i, nscales = _scales.size();
    bool recalcOptFeatures = nscales != scaleData->size();
    scaleData->resize(nscales);

    int layer_dy = 0;
    Point layer_ofs(0,0);
    Size prevBufSize = sbufSize;
    sbufSize.width = std::max(sbufSize.width, (int)alignSize(cvRound(imgsz.width/_scales[0]) + 31, 32));
    recalcOptFeatures = recalcOptFeatures || sbufSize.width != prevBufSize.width;

    for( i = 0; i < nscales; i++ )
    {
        FeatureEvaluator::ScaleData& s = scaleData->at(i);
        if( !recalcOptFeatures && fabs(s.scale - _scales[i]) > FLT_EPSILON*100*_scales[i] )
            recalcOptFeatures = true;
        float sc = _scales[i];
        Size sz;
        sz.width = cvRound(imgsz.width/sc);
        sz.height = cvRound(imgsz.height/sc);
        s.ystep = sc >= 2 ? 1 : 2;
        s.scale = sc;
        s.szi = Size(sz.width+1, sz.height+1);
        if( layer_ofs.x + s.szi.width > sbufSize.width )
        {
            layer_ofs = Point(0, layer_ofs.y + layer_dy);
            layer_dy = s.szi.height;
        }
        s.layer_ofs = layer_ofs.y*sbufSize.width + layer_ofs.x;
        layer_ofs.x += s.szi.width;
    }

    layer_ofs.y += layer_dy;
    sbufSize.height = std::max(sbufSize.height, layer_ofs.y);
    recalcOptFeatures = recalcOptFeatures || sbufSize.height != prevBufSize.height;
    return recalcOptFeatures;
}


bool FeatureEvaluator::setImage( InputArray _image, const std::vector<float>& _scales )
{
    Size imgsz = _image.size();
    bool recalcOptFeatures = updateScaleData(imgsz, _scales);
467

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
    size_t i, nscales = scaleData->size();
    Size sz0 = scaleData->at(0).szi;
    sz0 = Size(std::max(rbuf.cols, (int)alignSize(sz0.width, 16)), std::max(rbuf.rows, sz0.height));

    if (recalcOptFeatures)
    {
        computeOptFeatures();
        copyVectorToUMat(*scaleData, uscaleData);
    }

    if (_image.isUMat() && localSize.area() > 0)
    {
        usbuf.create(sbufSize.height*nchannels, sbufSize.width, CV_32S);
        urbuf.create(sz0, CV_8U);

        for (i = 0; i < nscales; i++)
        {
            const ScaleData& s = scaleData->at(i);
            UMat dst(urbuf, Rect(0, 0, s.szi.width - 1, s.szi.height - 1));
            resize(_image, dst, dst.size(), 1. / s.scale, 1. / s.scale, INTER_LINEAR);
            computeChannels((int)i, dst);
        }
        sbufFlag = USBUF_VALID;
    }
    else
    {
        Mat image = _image.getMat();
        sbuf.create(sbufSize.height*nchannels, sbufSize.width, CV_32S);
        rbuf.create(sz0, CV_8U);

        for (i = 0; i < nscales; i++)
        {
            const ScaleData& s = scaleData->at(i);
            Mat dst(s.szi.height - 1, s.szi.width - 1, CV_8U, rbuf.data);
            resize(image, dst, dst.size(), 1. / s.scale, 1. / s.scale, INTER_LINEAR);
            computeChannels((int)i, dst);
        }
        sbufFlag = SBUF_VALID;
    }

    return true;
}

511 512 513 514 515 516
//----------------------------------------------  HaarEvaluator ---------------------------------------

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

518 519 520 521 522 523
    int ri;
    for( ri = 0; ri < RECT_NUM; ri++ )
    {
        rect[ri].r = Rect();
        rect[ri].weight = 0.f;
    }
A
Andrey Kamaev 已提交
524

525 526 527 528 529 530
    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 已提交
531

532 533 534 535 536 537
    tilted = (int)node[CC_TILTED] != 0;
    return true;
}

HaarEvaluator::HaarEvaluator()
{
538 539
    optfeaturesPtr = 0;
    pwin = 0;
540 541 542
    localSize = Size(4, 2);
    lbufSize = Size(0, 0);
    nchannels = 0;
543
}
544

545 546 547 548
HaarEvaluator::~HaarEvaluator()
{
}

549
bool HaarEvaluator::read(const FileNode& node, Size _origWinSize)
550
{
551 552
    if (!FeatureEvaluator::read(node, _origWinSize))
        return false;
553 554
    size_t i, n = node.size();
    CV_Assert(n > 0);
555 556 557 558
    if(features.empty())
        features = makePtr<std::vector<Feature> >();
    if(optfeatures.empty())
        optfeatures = makePtr<std::vector<OptFeature> >();
559 560
    if (optfeatures_lbuf.empty())
        optfeatures_lbuf = makePtr<std::vector<OptFeature> >();
561
    features->resize(n);
562
    FileNodeIterator it = node.begin();
563
    hasTiltedFeatures = false;
V
Vadim Pisarevsky 已提交
564
    std::vector<Feature>& ff = *features;
565
    sbufSize = Size();
566
    ufbuf.release();
A
Andrey Kamaev 已提交
567

568
    for(i = 0; i < n; i++, ++it)
569
    {
570
        if(!ff[i].read(*it))
571
            return false;
572
        if( ff[i].tilted )
573 574
            hasTiltedFeatures = true;
    }
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
    nchannels = hasTiltedFeatures ? 3 : 2;
    normrect = Rect(1, 1, origWinSize.width - 2, origWinSize.height - 2);

    if (ocl::haveOpenCL())
    {
        String vname = ocl::Device::getDefault().vendor();
        if (vname == "Advanced Micro Devices, Inc." ||
            vname == "AMD")
            localSize = Size(8, 8);
        lbufSize = Size(origWinSize.width + localSize.width,
                        origWinSize.height + localSize.height);
        if (lbufSize.area() > 1024)
            lbufSize = Size(0, 0);
    }

590 591
    return true;
}
A
Andrey Kamaev 已提交
592

593 594
Ptr<FeatureEvaluator> HaarEvaluator::clone() const
{
R
Roman Donchenko 已提交
595
    Ptr<HaarEvaluator> ret = makePtr<HaarEvaluator>();
596
    *ret = *this;
597 598 599
    return ret;
}

600

601 602 603 604 605
void HaarEvaluator::computeChannels(int scaleIdx, InputArray img)
{
    const ScaleData& s = scaleData->at(scaleIdx);
    tofs = (int)sbufSize.area();
    sqofs = hasTiltedFeatures ? tofs*2 : tofs;
606

607
    if (img.isUMat())
608
    {
609 610 611 612 613 614 615 616
        int sx = s.layer_ofs % sbufSize.width;
        int sy = s.layer_ofs / sbufSize.width;
        int sqy = sy + (sqofs / sbufSize.width);
        UMat sum(usbuf, Rect(sx, sy, s.szi.width, s.szi.height));
        UMat sqsum(usbuf, Rect(sx, sqy, s.szi.width, s.szi.height));
        sqsum.flags = (sqsum.flags & ~UMat::DEPTH_MASK) | CV_32F;

        if (hasTiltedFeatures)
617
        {
618 619 620
            int sty = sy + (tofs / sbufSize.width);
            UMat tilted(usbuf, Rect(sx, sty, s.szi.width, s.szi.height));
            integral(img, sum, sqsum, tilted, CV_32S, CV_32F);
621 622
        }
        else
V
Vadim Pisarevsky 已提交
623
        {
624 625 626
            UMatData* u = sqsum.u;
            integral(img, sum, sqsum, noArray(), CV_32S, CV_32F);
            CV_Assert(sqsum.u == u && sqsum.size() == s.szi && sqsum.type()==CV_32F);
V
Vadim Pisarevsky 已提交
627
        }
628
    }
629
    else
630
    {
631 632
        Mat sum(s.szi, CV_32S, sbuf.ptr<int>() + s.layer_ofs, sbuf.step);
        Mat sqsum(s.szi, CV_32F, sum.ptr<int>() + sqofs, sbuf.step);
633

634
        if (hasTiltedFeatures)
635
        {
636 637
            Mat tilted(s.szi, CV_32S, sum.ptr<int>() + tofs, sbuf.step);
            integral(img, sum, sqsum, tilted, CV_32S, CV_32F);
638 639
        }
        else
640
            integral(img, sum, sqsum, noArray(), CV_32S, CV_32F);
641
    }
642
}
A
Andrey Kamaev 已提交
643

644 645 646 647
void HaarEvaluator::computeOptFeatures()
{
    int sstep = sbufSize.width;
    CV_SUM_OFS( nofs[0], nofs[1], nofs[2], nofs[3], 0, normrect, sstep );
A
Andrey Kamaev 已提交
648

649 650
    size_t fi, nfeatures = features->size();
    const std::vector<Feature>& ff = *features;
651 652 653 654 655
    optfeatures->resize(nfeatures);
    optfeaturesPtr = &(*optfeatures)[0];
    for( fi = 0; fi < nfeatures; fi++ )
        optfeaturesPtr[fi].setOffsets( ff[fi], sstep, tofs );
    optfeatures_lbuf->resize(nfeatures);
656

657 658
    for( fi = 0; fi < nfeatures; fi++ )
        optfeatures_lbuf->at(fi).setOffsets(ff[fi], lbufSize.width > 0 ? lbufSize.width : sstep, tofs);
659

660
    copyVectorToUMat(*optfeatures_lbuf, ufbuf);
661 662
}

663

664
bool HaarEvaluator::setWindow( Point pt, int scaleIdx )
665
{
666 667
    const ScaleData& s = getScaleData(scaleIdx);

668
    if( pt.x < 0 || pt.y < 0 ||
669 670
        pt.x + origWinSize.width >= s.szi.width ||
        pt.y + origWinSize.height >= s.szi.height )
671 672
        return false;

673 674 675 676
    pwin = &sbuf.at<int>(pt) + s.layer_ofs;
    const float* pq = (const float*)(pwin + sqofs);
    int valsum = CALC_SUM_OFS(nofs, pwin);
    float valsqsum = CALC_SUM_OFS(nofs, pq);
677 678 679

    double nf = (double)normrect.area() * valsqsum - (double)valsum * valsum;
    if( nf > 0. )
680
        nf = std::sqrt(nf);
681 682
    else
        nf = 1.;
683
    varianceNormFactor = (float)(1./nf);
684

685 686
    return true;
}
687

688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708

void HaarEvaluator::OptFeature::setOffsets( const Feature& _f, int step, int _tofs )
{
    weight[0] = _f.rect[0].weight;
    weight[1] = _f.rect[1].weight;
    weight[2] = _f.rect[2].weight;

    if( _f.tilted )
    {
        CV_TILTED_OFS( ofs[0][0], ofs[0][1], ofs[0][2], ofs[0][3], _tofs, _f.rect[0].r, step );
        CV_TILTED_OFS( ofs[1][0], ofs[1][1], ofs[1][2], ofs[1][3], _tofs, _f.rect[1].r, step );
        CV_TILTED_OFS( ofs[2][0], ofs[2][1], ofs[2][2], ofs[2][3], _tofs, _f.rect[2].r, step );
    }
    else
    {
        CV_SUM_OFS( ofs[0][0], ofs[0][1], ofs[0][2], ofs[0][3], 0, _f.rect[0].r, step );
        CV_SUM_OFS( ofs[1][0], ofs[1][1], ofs[1][2], ofs[1][3], 0, _f.rect[1].r, step );
        CV_SUM_OFS( ofs[2][0], ofs[2][1], ofs[2][2], ofs[2][3], 0, _f.rect[2].r, step );
    }
}

709 710 711 712
Rect HaarEvaluator::getNormRect() const
{
    return normrect;
}
713

714
int HaarEvaluator::getSquaresOffset() const
715
{
716
    return sqofs;
717
}
718 719 720 721 722 723 724 725 726 727 728 729

//----------------------------------------------  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 已提交
730
    features = makePtr<std::vector<Feature> >();
731
    optfeatures = makePtr<std::vector<OptFeature> >();
732
    scaleData = makePtr<std::vector<ScaleData> >();
733
}
734

735 736 737 738
LBPEvaluator::~LBPEvaluator()
{
}

739
bool LBPEvaluator::read( const FileNode& node, Size _origWinSize )
740
{
741 742 743 744 745 746 747 748 749
    if (!FeatureEvaluator::read(node, _origWinSize))
        return false;
    if(features.empty())
        features = makePtr<std::vector<Feature> >();
    if(optfeatures.empty())
        optfeatures = makePtr<std::vector<OptFeature> >();
    if (optfeatures_lbuf.empty())
        optfeatures_lbuf = makePtr<std::vector<OptFeature> >();

750
    features->resize(node.size());
751
    optfeaturesPtr = 0;
752
    FileNodeIterator it = node.begin(), it_end = node.end();
753
    std::vector<Feature>& ff = *features;
754 755
    for(int i = 0; it != it_end; ++it, i++)
    {
756
        if(!ff[i].read(*it))
757 758
            return false;
    }
759 760 761 762 763 764 765 766 767
    nchannels = 1;
    if (ocl::haveOpenCL())
    {
        const ocl::Device& device = ocl::Device::getDefault();
        String vname = device.vendor();
        if ((vname == "Advanced Micro Devices, Inc." ||
            vname == "AMD") && !device.hostUnifiedMemory())
            localSize = Size(8, 8);
    }
768 769 770 771 772
    return true;
}

Ptr<FeatureEvaluator> LBPEvaluator::clone() const
{
R
Roman Donchenko 已提交
773
    Ptr<LBPEvaluator> ret = makePtr<LBPEvaluator>();
774
    *ret = *this;
775 776 777
    return ret;
}

778
void LBPEvaluator::computeChannels(int scaleIdx, InputArray _img)
779
{
780
    const ScaleData& s = scaleData->at(scaleIdx);
781

782
    if (_img.isUMat())
783
    {
784 785 786 787
        int sx = s.layer_ofs % sbufSize.width;
        int sy = s.layer_ofs / sbufSize.width;
        UMat sum(usbuf, Rect(sx, sy, s.szi.width, s.szi.height));
        integral(_img, sum, noArray(), noArray(), CV_32S);
788 789 790
    }
    else
    {
791 792
        Mat sum(s.szi, CV_32S, sbuf.ptr<int>() + s.layer_ofs, sbuf.step);
        integral(_img, sum, noArray(), noArray(), CV_32S);
793
    }
794
}
795

796
void LBPEvaluator::computeOptFeatures()
797
{
798
    int sstep = sbufSize.width;
799

800 801 802 803 804
    size_t fi, nfeatures = features->size();
    const std::vector<Feature>& ff = *features;
    optfeatures->resize(nfeatures);
    optfeaturesPtr = &(*optfeatures)[0];
    for( fi = 0; fi < nfeatures; fi++ )
805
        optfeaturesPtr[fi].setOffsets( ff[fi], sstep );
806
    copyVectorToUMat(*optfeatures, ufbuf);
807 808 809
}


810
void LBPEvaluator::OptFeature::setOffsets( const Feature& _f, int step )
811
{
812 813 814 815 816 817 818 819 820 821 822
    Rect tr = _f.rect;
    int w0 = tr.width;
    int h0 = tr.height;

    CV_SUM_OFS( ofs[0], ofs[1], ofs[4], ofs[5], 0, tr, step );
    tr.x += 2*w0;
    CV_SUM_OFS( ofs[2], ofs[3], ofs[6], ofs[7], 0, tr, step );
    tr.y += 2*h0;
    CV_SUM_OFS( ofs[10], ofs[11], ofs[14], ofs[15], 0, tr, step );
    tr.x -= 2*w0;
    CV_SUM_OFS( ofs[8], ofs[9], ofs[12], ofs[13], 0, tr, step );
823 824 825
}


826
bool LBPEvaluator::setWindow( Point pt, int scaleIdx )
827
{
828 829
    CV_Assert(0 <= scaleIdx && scaleIdx < (int)scaleData->size());
    const ScaleData& s = scaleData->at(scaleIdx);
830 831

    if( pt.x < 0 || pt.y < 0 ||
832 833
        pt.x + origWinSize.width >= s.szi.width ||
        pt.y + origWinSize.height >= s.szi.height )
834
        return false;
835 836

    pwin = &sbuf.at<int>(pt) + s.layer_ofs;
837 838 839 840 841
    return true;
}


Ptr<FeatureEvaluator> FeatureEvaluator::create( int featureType )
842 843
{
    return featureType == HAAR ? Ptr<FeatureEvaluator>(new HaarEvaluator) :
A
Andrey Kamaev 已提交
844
        featureType == LBP ? Ptr<FeatureEvaluator>(new LBPEvaluator) :
845
        Ptr<FeatureEvaluator>();
846
}
847

848 849
//---------------------------------------- Classifier Cascade --------------------------------------------

850
CascadeClassifierImpl::CascadeClassifierImpl()
851 852 853
{
}

854
CascadeClassifierImpl::~CascadeClassifierImpl()
A
Andrey Kamaev 已提交
855
{
856
}
857

858
bool CascadeClassifierImpl::empty() const
859
{
R
Roman Donchenko 已提交
860
    return !oldCascade && data.stages.empty();
861 862
}

863
bool CascadeClassifierImpl::load(const String& filename)
864 865
{
    oldCascade.release();
866 867
    data = Data();
    featureEvaluator.release();
A
Andrey Kamaev 已提交
868

869 870 871
    FileStorage fs(filename, FileStorage::READ);
    if( !fs.isOpened() )
        return false;
A
Andrey Kamaev 已提交
872

873
    if( read_(fs.getFirstTopLevelNode()) )
874
        return true;
A
Andrey Kamaev 已提交
875

876
    fs.release();
A
Andrey Kamaev 已提交
877

R
Roman Donchenko 已提交
878
    oldCascade.reset((CvHaarClassifierCascade*)cvLoad(filename.c_str(), 0, 0, 0));
879 880
    return !oldCascade.empty();
}
A
Andrey Kamaev 已提交
881

882 883 884 885 886
void CascadeClassifierImpl::read(const FileNode& node)
{
    read_(node);
}

887
int CascadeClassifierImpl::runAt( Ptr<FeatureEvaluator>& evaluator, Point pt, int scaleIdx, double& weight )
888
{
889 890
    assert( !oldCascade &&
           (data.featureType == FeatureEvaluator::HAAR ||
891
            data.featureType == FeatureEvaluator::LBP ||
892
            data.featureType == FeatureEvaluator::HOG) );
893

894
    if( !evaluator->setWindow(pt, scaleIdx) )
895
        return -1;
896
    if( data.maxNodesPerTree == 1 )
897 898
    {
        if( data.featureType == FeatureEvaluator::HAAR )
A
Andrey Kamaev 已提交
899
            return predictOrderedStump<HaarEvaluator>( *this, evaluator, weight );
900
        else if( data.featureType == FeatureEvaluator::LBP )
A
Andrey Kamaev 已提交
901
            return predictCategoricalStump<LBPEvaluator>( *this, evaluator, weight );
902 903 904 905 906 907
        else
            return -2;
    }
    else
    {
        if( data.featureType == FeatureEvaluator::HAAR )
A
Andrey Kamaev 已提交
908
            return predictOrdered<HaarEvaluator>( *this, evaluator, weight );
909
        else if( data.featureType == FeatureEvaluator::LBP )
A
Andrey Kamaev 已提交
910
            return predictCategorical<LBPEvaluator>( *this, evaluator, weight );
911 912 913
        else
            return -2;
    }
914
}
A
Andrey Kamaev 已提交
915

916
void CascadeClassifierImpl::setMaskGenerator(const Ptr<MaskGenerator>& _maskGenerator)
917 918 919
{
    maskGenerator=_maskGenerator;
}
920
Ptr<CascadeClassifierImpl::MaskGenerator> CascadeClassifierImpl::getMaskGenerator()
921 922 923 924
{
    return maskGenerator;
}

925
Ptr<BaseCascadeClassifier::MaskGenerator> createFaceDetectionMaskGenerator()
926 927
{
#ifdef HAVE_TEGRA_OPTIMIZATION
928
    return tegra::getCascadeClassifierMaskGenerator(*this);
929
#else
930
    return Ptr<BaseCascadeClassifier::MaskGenerator>();
931 932 933
#endif
}

934
class CascadeClassifierInvoker : public ParallelLoopBody
935
{
936
public:
937 938 939 940 941
    CascadeClassifierInvoker( CascadeClassifierImpl& _cc, int _nscales, int _nstripes,
                              const FeatureEvaluator::ScaleData* _scaleData,
                              const int* _stripeSizes, std::vector<Rect>& _vec,
                              std::vector<int>& _levels, std::vector<double>& _weights,
                              bool outputLevels, const Mat& _mask, Mutex* _mtx)
942
    {
943
        classifier = &_cc;
944 945 946 947
        nscales = _nscales;
        nstripes = _nstripes;
        scaleData = _scaleData;
        stripeSizes = _stripeSizes;
948
        rectangles = &_vec;
949 950 951 952
        rejectLevels = outputLevels ? &_levels : 0;
        levelWeights = outputLevels ? &_weights : 0;
        mask = _mask;
        mtx = _mtx;
953
    }
A
Andrey Kamaev 已提交
954

955
    void operator()(const Range& range) const
956
    {
957
        Ptr<FeatureEvaluator> evaluator = classifier->featureEvaluator->clone();
958 959
        double gypWeight = 0.;
        Size origWinSize = classifier->data.origWinSize;
960

961
        for( int scaleIdx = 0; scaleIdx < nscales; scaleIdx++ )
962
        {
963 964 965 966 967 968 969 970 971 972 973
            const FeatureEvaluator::ScaleData& s = scaleData[scaleIdx];
            float scalingFactor = s.scale;
            int yStep = s.ystep;
            int stripeSize = stripeSizes[scaleIdx];
            int y0 = range.start*stripeSize;
            Size szw = s.getWorkingSize(origWinSize);
            int y1 = std::min(range.end*stripeSize, szw.height);
            Size winSize(cvRound(origWinSize.width * scalingFactor),
                         cvRound(origWinSize.height * scalingFactor));

            for( int y = y0; y < y1; y += yStep )
974
            {
975
                for( int x = 0; x < szw.width; x += yStep )
976
                {
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
                    int result = classifier->runAt(evaluator, Point(x, y), scaleIdx, gypWeight);
                    if( rejectLevels )
                    {
                        if( result == 1 )
                            result = -(int)classifier->data.stages.size();
                        if( classifier->data.stages.size() + result == 0 )
                        {
                            mtx->lock();
                            rectangles->push_back(Rect(cvRound(x*scalingFactor),
                                                       cvRound(y*scalingFactor),
                                                       winSize.width, winSize.height));
                            rejectLevels->push_back(-result);
                            levelWeights->push_back(gypWeight);
                            mtx->unlock();
                        }
                    }
                    else if( result > 0 )
994
                    {
995
                        mtx->lock();
996 997 998
                        rectangles->push_back(Rect(cvRound(x*scalingFactor),
                                                   cvRound(y*scalingFactor),
                                                   winSize.width, winSize.height));
999
                        mtx->unlock();
1000
                    }
1001 1002
                    if( result == 0 )
                        x += yStep;
A
Andrey Kamaev 已提交
1003
                }
1004
            }
1005
        }
1006
    }
A
Andrey Kamaev 已提交
1007

1008
    CascadeClassifierImpl* classifier;
1009
    std::vector<Rect>* rectangles;
1010 1011 1012
    int nscales, nstripes;
    const FeatureEvaluator::ScaleData* scaleData;
    const int* stripeSizes;
1013 1014
    std::vector<int> *rejectLevels;
    std::vector<double> *levelWeights;
1015
    std::vector<float> scales;
1016
    Mat mask;
1017
    Mutex* mtx;
1018
};
A
Andrey Kamaev 已提交
1019

1020

1021
struct getRect { Rect operator ()(const CvAvgComp& e) const { return e.rect; } };
1022
struct getNeighbors { int operator ()(const CvAvgComp& e) const { return e.neighbors; } };
1023

1024

1025 1026
bool CascadeClassifierImpl::ocl_detectMultiScaleNoGrouping( const std::vector<float>& scales,
                                                            std::vector<Rect>& candidates )
1027
{
1028 1029
    int featureType = getFeatureType();
    std::vector<UMat> bufs;
1030 1031 1032 1033 1034 1035 1036 1037
    featureEvaluator->getUMats(bufs);
    Size localsz = featureEvaluator->getLocalSize();
    if( localsz.area() == 0 )
        return false;
    Size lbufSize = featureEvaluator->getLocalBufSize();
    size_t localsize[] = { localsz.width, localsz.height };
    const int grp_per_CU = 12;
    size_t globalsize[] = { grp_per_CU*ocl::Device::getDefault().maxComputeUnits()*localsize[0], localsize[1] };
1038
    bool ok = false;
1039

1040 1041 1042 1043
    ufacepos.create(1, MAX_FACES*3+1, CV_32S);
    UMat ufacepos_count(ufacepos, Rect(0, 0, 1, 1));
    ufacepos_count.setTo(Scalar::all(0));

1044 1045
    if( ustages.empty() )
    {
1046
        copyVectorToUMat(data.stages, ustages);
1047 1048 1049 1050 1051
        if (!data.stumps.empty())
            copyVectorToUMat(data.stumps, unodes);
        else
            copyVectorToUMat(data.nodes, unodes);
        copyVectorToUMat(data.leaves, uleaves);
1052 1053
        if( !data.subsets.empty() )
            copyVectorToUMat(data.subsets, usubsets);
1054
    }
1055

1056 1057
    int nstages = (int)data.stages.size();

1058 1059 1060 1061 1062
    if( featureType == FeatureEvaluator::HAAR )
    {
        Ptr<HaarEvaluator> haar = featureEvaluator.dynamicCast<HaarEvaluator>();
        if( haar.empty() )
            return false;
1063

1064 1065
        if( haarKernel.empty() )
        {
1066 1067 1068 1069 1070 1071 1072 1073
            String opts;
            if (lbufSize.area())
                opts = format("-D LOCAL_SIZE_X=%d -D LOCAL_SIZE_Y=%d -D SUM_BUF_SIZE=%d -D SUM_BUF_STEP=%d -D NODE_COUNT=%d",
                              localsz.width, localsz.height, lbufSize.area(), lbufSize.width, data.maxNodesPerTree);
            else
                opts = format("-D LOCAL_SIZE_X=%d -D LOCAL_SIZE_Y=%d -D NODE_COUNT=%d",
                              localsz.width, localsz.height, data.maxNodesPerTree);
            haarKernel.create("runHaarClassifier", ocl::objdetect::cascadedetect_oclsrc, opts);
1074 1075 1076
            if( haarKernel.empty() )
                return false;
        }
1077

1078
        Rect normrect = haar->getNormRect();
1079 1080
        int sqofs = haar->getSquaresOffset();
        int splitstage_ocl = 1;
1081

1082 1083 1084
        haarKernel.args((int)scales.size(),
                        ocl::KernelArg::PtrReadOnly(bufs[0]), // scaleData
                        ocl::KernelArg::ReadOnlyNoSize(bufs[1]), // sum
1085 1086 1087
                        ocl::KernelArg::PtrReadOnly(bufs[2]), // optfeatures

                        // cascade classifier
1088
                        splitstage_ocl, nstages,
1089
                        ocl::KernelArg::PtrReadOnly(ustages),
1090 1091
                        ocl::KernelArg::PtrReadOnly(unodes),
                        ocl::KernelArg::PtrReadOnly(uleaves),
1092 1093

                        ocl::KernelArg::PtrWriteOnly(ufacepos), // positions
1094 1095
                        normrect, sqofs, data.origWinSize, (int)MAX_FACES);
        ok = haarKernel.run(2, globalsize, localsize, true);
1096 1097 1098
    }
    else if( featureType == FeatureEvaluator::LBP )
    {
1099 1100
        if (data.maxNodesPerTree > 1)
            return false;
1101

1102 1103 1104
        Ptr<LBPEvaluator> lbp = featureEvaluator.dynamicCast<LBPEvaluator>();
        if( lbp.empty() )
            return false;
1105

1106 1107
        if( lbpKernel.empty() )
        {
1108 1109 1110 1111 1112 1113 1114
            String opts;
            if (lbufSize.area())
                opts = format("-D LOCAL_SIZE_X=%d -D LOCAL_SIZE_Y=%d -D SUM_BUF_SIZE=%d -D SUM_BUF_STEP=%d",
                              localsz.width, localsz.height, lbufSize.area(), lbufSize.width);
            else
                opts = format("-D LOCAL_SIZE_X=%d -D LOCAL_SIZE_Y=%d", localsz.width, localsz.height);
            lbpKernel.create("runLBPClassifierStumpSimple", ocl::objdetect::cascadedetect_oclsrc, opts);
1115 1116 1117
            if( lbpKernel.empty() )
                return false;
        }
1118

1119
        int splitstage_ocl = 1;
1120
        int subsetSize = (data.ncategories + 31)/32;
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
        lbpKernel.args((int)scales.size(),
                       ocl::KernelArg::PtrReadOnly(bufs[0]), // scaleData
                       ocl::KernelArg::ReadOnlyNoSize(bufs[1]), // sum
                       ocl::KernelArg::PtrReadOnly(bufs[2]), // optfeatures

                       // cascade classifier
                       splitstage_ocl, nstages,
                       ocl::KernelArg::PtrReadOnly(ustages),
                       ocl::KernelArg::PtrReadOnly(unodes),
                       ocl::KernelArg::PtrReadOnly(usubsets),
                       subsetSize,

                       ocl::KernelArg::PtrWriteOnly(ufacepos), // positions
                       data.origWinSize, (int)MAX_FACES);

        ok = lbpKernel.run(2, globalsize, localsize, true);
    }
1138

1139 1140 1141 1142 1143 1144
    if( ok )
    {
        Mat facepos = ufacepos.getMat(ACCESS_READ);
        const int* fptr = facepos.ptr<int>();
        int nfaces = fptr[0];
        nfaces = std::min(nfaces, (int)MAX_FACES);
1145

1146 1147 1148 1149 1150 1151 1152 1153
        for( int i = 0; i < nfaces; i++ )
        {
            const FeatureEvaluator::ScaleData& s = featureEvaluator->getScaleData(fptr[i*3 + 1]);
            candidates.push_back(Rect(cvRound(fptr[i*3 + 2]*s.scale),
                                      cvRound(fptr[i*3 + 3]*s.scale),
                                      cvRound(data.origWinSize.width*s.scale),
                                      cvRound(data.origWinSize.height*s.scale)));
        }
1154
    }
V
Vadim Pisarevsky 已提交
1155
    return ok;
1156 1157
}

1158
bool CascadeClassifierImpl::isOldFormatCascade() const
1159 1160 1161 1162
{
    return !oldCascade.empty();
}

1163
int CascadeClassifierImpl::getFeatureType() const
1164 1165 1166 1167
{
    return featureEvaluator->getFeatureType();
}

1168
Size CascadeClassifierImpl::getOriginalWindowSize() const
1169 1170 1171 1172
{
    return data.origWinSize;
}

1173 1174 1175 1176 1177
void* CascadeClassifierImpl::getOldCascade()
{
    return oldCascade;
}

1178 1179 1180 1181 1182 1183 1184 1185
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 )
1186
{
1187 1188 1189 1190 1191 1192 1193 1194
    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());
}
1195

1196

1197
void CascadeClassifierImpl::detectMultiScaleNoGrouping( InputArray _image, std::vector<Rect>& candidates,
1198 1199 1200 1201
                                                    std::vector<int>& rejectLevels, std::vector<double>& levelWeights,
                                                    double scaleFactor, Size minObjectSize, Size maxObjectSize,
                                                    bool outputRejectLevels )
{
1202
    Size imgsz = _image.size();
1203

1204 1205
    Mat grayImage;
    _InputArray gray;
1206

1207
    candidates.clear();
1208 1209
    rejectLevels.clear();
    levelWeights.clear();
1210

1211
    if( maxObjectSize.height == 0 || maxObjectSize.width == 0 )
1212
        maxObjectSize = imgsz;
1213

1214 1215 1216 1217 1218 1219 1220
    bool use_ocl = tryOpenCL && ocl::useOpenCL() &&
         featureEvaluator->getLocalSize().area() > 0 &&
         ocl::Device::getDefault().type() != ocl::Device::TYPE_CPU &&
         (data.minNodesPerTree == data.maxNodesPerTree) &&
         !isOldFormatCascade() &&
         maskGenerator.empty() &&
         !outputRejectLevels;
A
Andrey Kamaev 已提交
1221

1222
    /*if( use_ocl )
1223
    {
1224 1225 1226 1227
        if (_image.channels() > 1)
            cvtColor(_image, ugrayImage, COLOR_BGR2GRAY);
        else if (_image.isUMat())
            ugrayImage = _image.getUMat();
1228
        else
1229 1230
            _image.copyTo(ugrayImage);
        gray = ugrayImage;
1231
    }
1232
    else*/
V
Vadim Pisarevsky 已提交
1233
    {
1234 1235 1236 1237 1238 1239 1240
        if (_image.channels() > 1)
            cvtColor(_image, grayImage, COLOR_BGR2GRAY);
        else if (_image.isMat())
            grayImage = _image.getMat();
        else
            _image.copyTo(grayImage);
        gray = grayImage;
V
Vadim Pisarevsky 已提交
1241
    }
A
Andrey Kamaev 已提交
1242

1243 1244 1245
    std::vector<float> scales;
    scales.reserve(1024);

1246 1247
    for( double factor = 1; ; factor *= scaleFactor )
    {
1248
        Size originalWindowSize = getOriginalWindowSize();
1249

1250
        Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );
1251 1252
        if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height ||
            windowSize.width > imgsz.width || windowSize.height > imgsz.height )
1253
            break;
1254
        if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height )
1255
            continue;
1256 1257
        scales.push_back((float)factor);
    }
1258

1259 1260
    if( !featureEvaluator->setImage(gray, scales) )
        return;
1261

1262 1263 1264 1265
    // OpenCL code
    if( use_ocl && ocl_detectMultiScaleNoGrouping( scales, candidates ))
        return;
    tryOpenCL = false;
1266

1267 1268
    // CPU code
    featureEvaluator->getMats();
1269
    {
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
        Mat currentMask;
        if (maskGenerator)
            currentMask = maskGenerator->generateMask(gray.getMat());

        size_t i, nscales = scales.size();
        cv::AutoBuffer<int> stripeSizeBuf(nscales);
        int* stripeSizes = stripeSizeBuf;
        const FeatureEvaluator::ScaleData* s = &featureEvaluator->getScaleData(0);
        Size szw = s->getWorkingSize(data.origWinSize);
        int nstripes = cvCeil(szw.width/32.);
        for( i = 0; i < nscales; i++ )
1281
        {
1282 1283
            szw = s[i].getWorkingSize(data.origWinSize);
            stripeSizes[i] = std::max((szw.height/s[i].ystep + nstripes-1)/nstripes, 1)*s[i].ystep;
1284
        }
1285 1286 1287 1288 1289

        CascadeClassifierInvoker invoker(*this, (int)nscales, nstripes, s, stripeSizes,
                                         candidates, rejectLevels, levelWeights,
                                         outputRejectLevels, currentMask, &mtx);
        parallel_for_(Range(0, nstripes), invoker);
1290
    }
1291
}
1292

1293

1294
void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rect>& objects,
1295 1296 1297 1298 1299 1300
                                          std::vector<int>& rejectLevels,
                                          std::vector<double>& levelWeights,
                                          double scaleFactor, int minNeighbors,
                                          int flags, Size minObjectSize, Size maxObjectSize,
                                          bool outputRejectLevels )
{
1301
    CV_Assert( scaleFactor > 1 && _image.depth() == CV_8U );
A
Andrey Kamaev 已提交
1302

1303 1304
    if( empty() )
        return;
1305

1306
    if( isOldFormatCascade() )
1307
    {
1308
        Mat image = _image.getMat();
1309 1310 1311
        std::vector<CvAvgComp> fakeVecAvgComp;
        detectMultiScaleOldFormat( image, oldCascade, objects, rejectLevels, levelWeights, fakeVecAvgComp, scaleFactor,
                                   minNeighbors, flags, minObjectSize, maxObjectSize, outputRejectLevels );
1312 1313 1314
    }
    else
    {
1315
        detectMultiScaleNoGrouping( _image, objects, rejectLevels, levelWeights, scaleFactor, minObjectSize, maxObjectSize,
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
                                    outputRejectLevels );
        const double GROUP_EPS = 0.2;
        if( outputRejectLevels )
        {
            groupRectangles( objects, rejectLevels, levelWeights, minNeighbors, GROUP_EPS );
        }
        else
        {
            groupRectangles( objects, minNeighbors, GROUP_EPS );
        }
1326
    }
A
Alexey Kazakov 已提交
1327 1328
}

1329
void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rect>& objects,
A
Alexey Kazakov 已提交
1330 1331 1332
                                          double scaleFactor, int minNeighbors,
                                          int flags, Size minObjectSize, Size maxObjectSize)
{
1333 1334
    std::vector<int> fakeLevels;
    std::vector<double> fakeWeights;
1335
    detectMultiScale( _image, objects, fakeLevels, fakeWeights, scaleFactor,
1336 1337 1338
        minNeighbors, flags, minObjectSize, maxObjectSize );
}

1339
void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rect>& objects,
1340 1341 1342 1343
                                          std::vector<int>& numDetections, double scaleFactor,
                                          int minNeighbors, int flags, Size minObjectSize,
                                          Size maxObjectSize )
{
1344
    Mat image = _image.getMat();
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
    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 已提交
1366
}
1367

1368

1369 1370 1371 1372
CascadeClassifierImpl::Data::Data()
{
    stageType = featureType = ncategories = maxNodesPerTree = 0;
}
1373

1374
bool CascadeClassifierImpl::Data::read(const FileNode &root)
1375
{
1376
    static const float THRESHOLD_EPS = 1e-5f;
A
Andrey Kamaev 已提交
1377

1378
    // load stage params
1379
    String stageTypeStr = (String)root[CC_STAGE_TYPE];
1380 1381 1382 1383
    if( stageTypeStr == CC_BOOST )
        stageType = BOOST;
    else
        return false;
1384

1385
    String featureTypeStr = (String)root[CC_FEATURE_TYPE];
1386 1387 1388 1389
    if( featureTypeStr == CC_HAAR )
        featureType = FeatureEvaluator::HAAR;
    else if( featureTypeStr == CC_LBP )
        featureType = FeatureEvaluator::LBP;
1390 1391 1392
    else if( featureTypeStr == CC_HOG )
        featureType = FeatureEvaluator::HOG;

1393 1394
    else
        return false;
1395

1396 1397 1398
    origWinSize.width = (int)root[CC_WIDTH];
    origWinSize.height = (int)root[CC_HEIGHT];
    CV_Assert( origWinSize.height > 0 && origWinSize.width > 0 );
1399

1400 1401 1402 1403
    // load feature params
    FileNode fn = root[CC_FEATURE_PARAMS];
    if( fn.empty() )
        return false;
1404

1405 1406 1407
    ncategories = fn[CC_MAX_CAT_COUNT];
    int subsetSize = (ncategories + 31)/32,
        nodeStep = 3 + ( ncategories>0 ? subsetSize : 1 );
1408

1409 1410 1411 1412
    // load stages
    fn = root[CC_STAGES];
    if( fn.empty() )
        return false;
1413

1414 1415 1416
    stages.reserve(fn.size());
    classifiers.clear();
    nodes.clear();
1417
    stumps.clear();
1418

1419
    FileNodeIterator it = fn.begin(), it_end = fn.end();
1420
    minNodesPerTree = INT_MAX;
1421
    maxNodesPerTree = 0;
1422

1423 1424 1425 1426
    for( int si = 0; it != it_end; si++, ++it )
    {
        FileNode fns = *it;
        Stage stage;
1427
        stage.threshold = (float)fns[CC_STAGE_THRESHOLD] - THRESHOLD_EPS;
1428 1429 1430 1431 1432 1433 1434
        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);
1435

1436 1437 1438 1439 1440 1441 1442 1443
        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;
1444

1445 1446
            DTree tree;
            tree.nodeCount = (int)internalNodes.size()/nodeStep;
1447
            minNodesPerTree = std::min(minNodesPerTree, tree.nodeCount);
1448
            maxNodesPerTree = std::max(maxNodesPerTree, tree.nodeCount);
1449

1450
            classifiers.push_back(tree);
1451

1452 1453 1454 1455
            nodes.reserve(nodes.size() + tree.nodeCount);
            leaves.reserve(leaves.size() + leafValues.size());
            if( subsetSize > 0 )
                subsets.reserve(subsets.size() + tree.nodeCount*subsetSize);
1456 1457 1458 1459

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

            for( ; internalNodesIter != internalNodesEnd; ) // nodes
1460 1461
            {
                DTreeNode node;
1462 1463 1464
                node.left = (int)*internalNodesIter; ++internalNodesIter;
                node.right = (int)*internalNodesIter; ++internalNodesIter;
                node.featureIdx = (int)*internalNodesIter; ++internalNodesIter;
1465 1466
                if( subsetSize > 0 )
                {
1467 1468
                    for( int j = 0; j < subsetSize; j++, ++internalNodesIter )
                        subsets.push_back((int)*internalNodesIter);
1469 1470 1471 1472
                    node.threshold = 0.f;
                }
                else
                {
1473
                    node.threshold = (float)*internalNodesIter; ++internalNodesIter;
1474 1475 1476
                }
                nodes.push_back(node);
            }
1477 1478 1479 1480 1481

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

            for( ; internalNodesIter != internalNodesEnd; ++internalNodesIter ) // leaves
                leaves.push_back((float)*internalNodesIter);
1482 1483
        }
    }
1484

1485
    if( maxNodesPerTree == 1 )
1486 1487 1488 1489 1490 1491
    {
        int nodeOfs = 0, leafOfs = 0;
        size_t nstages = stages.size();
        for( size_t stageIdx = 0; stageIdx < nstages; stageIdx++ )
        {
            const Stage& stage = stages[stageIdx];
1492

1493 1494 1495 1496 1497 1498 1499 1500 1501
            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]));
            }
        }
    }
1502

1503 1504 1505
    return true;
}

1506

1507
bool CascadeClassifierImpl::read_(const FileNode& root)
1508
{
1509
    tryOpenCL = true;
1510 1511
    haarKernel = ocl::Kernel();
    lbpKernel = ocl::Kernel();
1512
    ustages.release();
1513 1514
    unodes.release();
    uleaves.release();
1515 1516 1517
    if( !data.read(root) )
        return false;

1518
    // load features
1519 1520
    featureEvaluator = FeatureEvaluator::create(data.featureType);
    FileNode fn = root[CC_FEATURES];
1521 1522
    if( fn.empty() )
        return false;
A
Andrey Kamaev 已提交
1523

1524
    return featureEvaluator->read(fn, data.origWinSize);
1525
}
A
Andrey Kamaev 已提交
1526

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

1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557

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();
}

1558 1559
bool CascadeClassifier::read(const FileNode &root)
{
1560
    Ptr<CascadeClassifierImpl> ccimpl = makePtr<CascadeClassifierImpl>();
1561 1562 1563 1564 1565 1566 1567 1568
    bool ok = ccimpl->read_(root);
    if( ok )
        cc = ccimpl.staticCast<BaseCascadeClassifier>();
    else
        cc.release();
    return ok;
}

1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630
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();
}

1631
void CascadeClassifier::setMaskGenerator(const Ptr<BaseCascadeClassifier::MaskGenerator>& maskGenerator)
1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
{
    CV_Assert(!empty());
    cc->setMaskGenerator(maskGenerator);
}

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

1643
} // namespace cv