OpenCV:OpenCV目标检测Adaboost+haar源代码分析

转自https://www.cnblogs.com/wishchin/p/9199968.html
使用OpenCV作图像检测, Adaboost+haar决策过程,其中一部分源代码如下:

   函数调用堆栈的底层为:

1、使用有序决策桩进行预测

template
inline int predictOrderedStump( CascadeClassifier& cascade, Ptr &_featureEvaluator, double& sum )
{
int nodeOfs = 0, leafOfs = 0;
FEval& featureEvaluator = (FEval&)_featureEvaluator;
float
cascadeLeaves = &cascade.data.leaves[0];
CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0];
CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0];

//每一层进行计算,第一次训练为19层 nstages=19
//

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

    //每一层树的个数
    int ntrees = stage.ntrees;
    for( int i = 0; i < ntrees; i++, nodeOfs++, leafOfs+= 2 )
    {
        CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs];

    //收集累积和//没有显示否定的特性?
        double value = featureEvaluator(node.featureIdx);
        sum += cascadeLeaves[ value < node.threshold ? leafOfs : leafOfs + 1 ];
    }

    if( sum < stage.threshold )
        return -stageIdx;
}

return 1;

}

2.上层调用:在某个点之处进行计算

int CascadeClassifier::runAt( Ptr& evaluator, Point pt, double& weight )
{
CV_Assert( oldCascade.empty() );

assert( data.featureType == FeatureEvaluator::HAAR ||
        data.featureType == FeatureEvaluator::LBP ||
        data.featureType == FeatureEvaluator::HOG );

if( !evaluator->setWindow(pt) )
    return -1;
if( data.isStumpBased )
{
    //若使用haar特征,则进行haar检测过程 wishchin 
   if( data.featureType == FeatureEvaluator::HAAR )
        return predictOrderedStump<HaarEvaluator>( *this, evaluator, weight );
    else if( data.featureType == FeatureEvaluator::LBP )
        return predictCategoricalStump<LBPEvaluator>( *this, evaluator, weight );
    else if( data.featureType == FeatureEvaluator::HOG )
        return predictOrderedStump<HOGEvaluator>( *this, evaluator, weight );
    else
        return -2;
}
else
{
    if( data.featureType == FeatureEvaluator::HAAR )
        return predictOrdered<HaarEvaluator>( *this, evaluator, weight );
    else if( data.featureType == FeatureEvaluator::LBP )
        return predictCategorical<LBPEvaluator>( *this, evaluator, weight );
    else if( data.featureType == FeatureEvaluator::HOG )
        return predictOrdered<HOGEvaluator>( *this, evaluator, weight );
    else
        return -2;
}

}

  1. CascadeClassifierInvoker初始化时产生的 CascadeClassifier,

其中 每个inVoker继承于并行循环的body:例如 class CascadeClassifier : public ParallelLoopBody,完成并行计算过程

    其初始化过程,完成检测。

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

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

    int y1 = range.start * stripSize;
    int y2 = min(range.end * stripSize, processingRectSize.height);
    for( int y = y1; y < y2; y += yStep )
    {
        for( int x = 0; x < processingRectSize.width; x += yStep )
        {
            if ( (!mask.empty()) && (mask.at<uchar>(Point(x,y))==0)) {
                continue;
            }

            double gypWeight;

	//作为起始点检测图像是否为目标!!! wishchin 2017 03 20
            int result = classifier->runAt(evaluator, Point(x, y), gypWeight);

#if defined (LOG_CASCADE_STATISTIC)

            logger.setPoint(Point(x, y), result);

#endif
if( rejectLevels )
{
if( result == 1 )
result = -(int)classifier->data.stages.size();
if( classifier->data.stages.size() + result < 4 )
{
mtx->lock();
rectangles->push_back(Rect(cvRound(xscalingFactor), cvRound(yscalingFactor), winSize.width, winSize.height));
rejectLevels->push_back(-result);
levelWeights->push_back(gypWeight);
mtx->unlock();
}
}
else if( result > 0 )
{
mtx->lock();
rectangles->push_back(Rect(cvRound(xscalingFactor), cvRound(yscalingFactor),
winSize.width, winSize.height));
mtx->unlock();
}
if( result == 0 )
x += yStep;
}
}
}

CascadeClassifier* classifier;
vector<Rect>* rectangles;
Size processingRectSize;
int stripSize, yStep;
double scalingFactor;
vector<int> *rejectLevels;
vector<double> *levelWeights;
Mat mask;
Mutex* mtx;

};

4.使用多尺度计算过程,对每一层进行单层结果计算

bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize,
int stripSize, int yStep, double factor, vector & candidates,
vector& levels, vector& weights, bool outputRejectLevels )
{
if( !featureEvaluator->setImage( image, data.origWinSize ) )
return false;

#if defined (LOG_CASCADE_STATISTIC)
logger.setImage(image);
#endif

Mat currentMask;
if (!maskGenerator.empty()) {
    currentMask=maskGenerator->generateMask(image);
}

vector<Rect> candidatesVector;
vector<int>      rejectLevels;
vector<double>   levelWeights;
Mutex mtx;
if( outputRejectLevels )
{
    parallel_for_(Range(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor,
        candidatesVector, rejectLevels, levelWeights, true, currentMask, &mtx));
    levels.insert( levels.end(), rejectLevels.begin(), rejectLevels.end() );
    weights.insert( weights.end(), levelWeights.begin(), levelWeights.end() );
}
else
{
    //并行处理过程,对每一层初始化一个CascadeClassifierInvoker,完成计算
   parallel_for_(Range(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor,
        candidatesVector, rejectLevels, levelWeights, false, currentMask, &mtx));
}
candidates.insert( candidates.end(), candidatesVector.begin(), candidatesVector.end() );

#if defined (LOG_CASCADE_STATISTIC)
logger.write();
#endif

return true;

}

  1. 进行多尺度检测
    void CascadeClassifier::detectMultiScale( const Mat& image, vector & objects,
    vector& rejectLevels,
    vector& levelWeights,
    double scaleFactor, int minNeighbors,
    int flags, Size minObjectSize, Size maxObjectSize,
    bool outputRejectLevels )
    {
    const double GROUP_EPS = 0.2;

    CV_Assert( scaleFactor > 1 && image.depth() == CV_8U );

    if( empty() )
    return;

    if( isOldFormatCascade() )
    {
    MemStorage storage(cvCreateMemStorage(0));
    CvMat _image = image;
    CvSeq* _objects = cvHaarDetectObjectsForROC( &_image, oldCascade, storage, rejectLevels, levelWeights, scaleFactor,
    minNeighbors, flags, minObjectSize, maxObjectSize, outputRejectLevels );
    vector vecAvgComp;
    Seq(_objects).copyTo(vecAvgComp);
    objects.resize(vecAvgComp.size());
    std::transform(vecAvgComp.begin(), vecAvgComp.end(), objects.begin(), getRect());
    return;
    }

    objects.clear();

    if (!maskGenerator.empty()) {
    maskGenerator->initializeMask(image);
    }

    if( maxObjectSize.height == 0 || maxObjectSize.width == 0 )
    maxObjectSize = image.size();

    Mat grayImage = image;
    if( grayImage.channels() > 1 )
    {
    Mat temp;
    cvtColor(grayImage, temp, CV_BGR2GRAY);
    grayImage = temp;
    }

    Mat imageBuffer(image.rows + 1, image.cols + 1, CV_8U);
    vector candidates;

    for( double factor = 1; ; factor *= scaleFactor )
    {
    Size originalWindowSize = getOriginalWindowSize();

     Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );
     Size scaledImageSize( cvRound( grayImage.cols/factor ), cvRound( grayImage.rows/factor ) );
     Size processingRectSize( scaledImageSize.width - originalWindowSize.width, scaledImageSize.height - originalWindowSize.height );
    
     if( processingRectSize.width <= 0 || processingRectSize.height <= 0 )
         break;
     if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height )
         break;
     if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height )
         continue;
    
     Mat scaledImage( scaledImageSize, CV_8U, imageBuffer.data );
     resize( grayImage, scaledImage, scaledImageSize, 0, 0, CV_INTER_LINEAR );
    
     int yStep;
     if( getFeatureType() == cv::FeatureEvaluator::HOG )
     {
         yStep = 4;
     }
     else
     {
         yStep = factor > 2. ? 1 : 2;
     }
    
     int stripCount, stripSize;
    
     const int PTS_PER_THREAD = 1000;
     stripCount = ((processingRectSize.width/yStep)*(processingRectSize.height + yStep-1)/yStep + PTS_PER_THREAD/2)/PTS_PER_THREAD;
     stripCount = std::min(std::max(stripCount, 1), 100);
     stripSize = (((processingRectSize.height + stripCount - 1)/stripCount + yStep-1)/yStep)*yStep;
    
     //对每一个尺度进行目标检测 wishchin 2017 03 21 
     if( !detectSingleScale( scaledImage, stripCount, processingRectSize, stripSize, yStep, factor, candidates,
         rejectLevels, levelWeights, outputRejectLevels ) )
         break;
    

    }

    objects.resize(candidates.size());
    std::copy(candidates.begin(), candidates.end(), objects.begin());

    if( outputRejectLevels )
    {
    groupRectangles( objects, rejectLevels, levelWeights, minNeighbors, GROUP_EPS );
    }
    else
    {
    groupRectangles( objects, minNeighbors, GROUP_EPS );
    }
    }

以上为objectDetect过程的OpenCV的源代码,外层调用的使用函数接口可以为:
// 人眼检测
m_cascade.detectMultiScale(
smallImg,
eyes,
fAdaBoostScale, // originally 1.1, 4 is faster
2, //minNeighbors
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
CV_HAAR_DO_CANNY_PRUNING,
Size(48, 32)
);
//cout << “eyes size=:” << eyes.size() << endl;

总结:

    上述过程即是Haar+Adaboost检测计算大致的函数调用堆栈。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值