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 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
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);
    
    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 805 806
    size_t fi, nfeatures = features->size();
    const std::vector<Feature>& ff = *features;
    optfeatures->resize(nfeatures);
    optfeaturesPtr = &(*optfeatures)[0];
    for( fi = 0; fi < nfeatures; fi++ )
        optfeaturesPtr[fi].setOffsets( ff[fi], sstep );    
    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 1101
        if (data.maxNodesPerTree > 1)
            return false;
        
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 1206
    
    Mat grayImage;
    UMat ugrayImage;
    _InputArray gray;
1207

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

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

1215 1216 1217 1218 1219 1220 1221
    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 已提交
1222

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

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

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

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

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

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

1268 1269
    // CPU code
    featureEvaluator->getMats();
1270
    {
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281
        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++ )
1282
        {
1283 1284
            szw = s[i].getWorkingSize(data.origWinSize);
            stripeSizes[i] = std::max((szw.height/s[i].ystep + nstripes-1)/nstripes, 1)*s[i].ystep;
1285
        }
1286 1287 1288 1289 1290

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

1294

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

1304 1305
    if( empty() )
        return;
1306

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

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

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

1369

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

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

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

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

1394 1395
    else
        return false;
1396

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

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

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

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

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

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

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

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

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

1451
            classifiers.push_back(tree);
1452

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

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

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

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

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

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

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

1504 1505 1506
    return true;
}

1507

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

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

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

R
Roman Donchenko 已提交
1528
template<> void DefaultDeleter<CvHaarClassifierCascade>::operator ()(CvHaarClassifierCascade* obj) const
A
Andrey Kamaev 已提交
1529
{ cvReleaseHaarClassifierCascade(&obj); }
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 1558

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

1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
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;
}

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

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

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

1644
} // namespace cv