本文主要是介绍train_cascade 源码阅读之LBP特征,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本文以LBP特征为例,介绍了OpenCV中train_cascade数据初始化的过程。
1 在CvCascadeBoost中,创建了CvCascadeBoostTrainData对象。
- bool CvCascadeBoost::
- train(
- const CvFeatureEvaluator* _featureEvaluator,
- int _numSamples,
- int _precalcValBufSize, int _precalcIdxBufSize,
- const CvCascadeBoostParams& _params )
- {
- bool isTrained = false;
- CV_Assert( !data );
- clear();
- data = new <strong>CvCascadeBoostTrainData</strong>(
- _featureEvaluator, _numSamples,
- _precalcValBufSize, _precalcIdxBufSize, _params )
- ……
- }
2 在CvCascadeBoostTrainData中调用setData函数。
- CvCascadeBoostTrainData::CvCascadeBoostTrainData( const CvFeatureEvaluator* _featureEvaluator,
- int _numSamples,
- int _precalcValBufSize, int _precalcIdxBufSize,
- const CvDTreeParams& _params )
- {
- <strong> setData</strong>( _featureEvaluator, _numSamples, _precalcValBufSize, _precalcIdxBufSize, _params );
- }
3 在setData函数中调用了预先计算特征,也就是参数中preCalcValBufSize, preClacIdxBufSize预留的内存初始化的地方。
- void CvCascadeBoostTrainData::setData( const CvFeatureEvaluator* _featureEvaluator,
- int _numSamples,
- int _precalcValBufSize, int _precalcIdxBufSize,
- const CvDTreeParams& _params )
- {
-
- ……
-
-
- <strong> precalculate();</strong>
- ……
-
- }
4 在precalculate函数中,有初始化时计算一次特征的函数。
- void CvCascadeBoostTrainData::precalculate()
- {
- int minNum = MIN( numPrecalcVal, numPrecalcIdx);
-
- double proctime = -TIME( 0 );
- parallel_for_( Range(numPrecalcVal, numPrecalcIdx),
- FeatureIdxOnlyPrecalc(featureEvaluator, buf, sample_count, is_buf_16u!=0) );
- parallel_for_( Range(0, minNum),
- FeatureValAndIdxPrecalc(featureEvaluator, buf, &valCache, sample_count, is_buf_16u!=0) );
- parallel_for_( Range(minNum, numPrecalcVal),
- <strong>FeatureValOnlyPrecalc(featureEvaluator, &valCache, sample_count) );</strong>
- cout << "Precalculation time: " << (proctime + TIME( 0 )) << endl;
- }
5 在该函数内,用函数指针调用了featureEvaluator的一个operator(),如果是LBP特征的话,则调用的是LBP子类的对应函数。
- struct FeatureValOnlyPrecalc : ParallelLoopBody
- {
- FeatureValOnlyPrecalc( const CvFeatureEvaluator* _featureEvaluator, Mat* _valCache, int _sample_count )
- {
- featureEvaluator = _featureEvaluator;
- valCache = _valCache;
- sample_count = _sample_count;
- }
- void operator()( const Range& range ) const
- {
- for ( int fi = range.start; fi < range.end; fi++)
- for( int si = 0; si < sample_count; si++ )
- <strong>valCache->at<float>(fi,si) = (*featureEvaluator)( fi, si );</strong>
- }
- const CvFeatureEvaluator* featureEvaluator;
- Mat* valCache;
- int sample_count;
- };
6 在CvLBPEvaluator中定义了operator()虚函数。并且它调用了calc函数,返回计算得到的LBP特征。
- class CvLBPEvaluator : public CvFeatureEvaluator
- {
- public:
- virtual ~CvLBPEvaluator() {}
- virtual void init(
- const CvFeatureParams *_featureParams,
- int _maxSampleCount,
- cv::Size _winSize );
- virtual void setImage(
- const cv::Mat & img,
- uchar clsLabel,
- int idx);
- <strong> virtual float operator()(
- int featureIdx,
- int sampleIdx) const
- { return (float)features[featureIdx].calc( sum, sampleIdx); }</strong>
- virtual void writeFeatures(
- cv::FileStorage &fs,
- const cv::Mat &featureMap ) const;
- protected:
- virtual void generateFeatures();
-
- class Feature
- {
- public:
- Feature();
- Feature(
- int offset,
- int x,
- int y,
- int _block_w,
- int _block_h );
- <strong>uchar calc(
- const cv::Mat& _sum,
- size_t y ) const;</strong>
- void write( cv::FileStorage &fs ) const;
-
- cv::Rect rect;
- <strong>int p[16];</strong>
- };
- <strong>std::vector<Feature> features;
-
- cv::Mat sum;</strong>
- };
7 在CvLBPEvaluator初始化的时候,初始化了sum矩阵,它有样本和个数相同多的行。
- void CvLBPEvaluator::init(
- const CvFeatureParams *_featureParams,
- int _maxSampleCount, Size _winSize)
- {
- CV_Assert( _maxSampleCount > 0);
- <strong>sum.create((int)_maxSampleCount,
- (_winSize.width + 1) * (_winSize.height + 1),
- CV_32SC1);</strong>
- CvFeatureEvaluator::init( _featureParams, _maxSampleCount, _winSize );
- }
8 创建积分图矩阵,将矩阵的数据指向刚才创建好的sum的对应样本行。
- void CvLBPEvaluator::setImage(const Mat &img, uchar clsLabel, int idx)
- {
- CV_DbgAssert( !sum.empty() );
- CvFeatureEvaluator::setImage( img, clsLabel, idx );
- Mat <strong>innSum</strong>(winSize.height + 1,
- winSize.width + 1,
- sum.type(),
- <strong>sum.ptr<int>((int)idx)</strong>);
- <strong>integral</strong>( img, innSum );
- }
9 调用积分图,返回LBP特征,从函数中可以看到,作者使用的是原始的LBP特征,并没有归一化或者合并等等操作。
0 | 1 | 2 | 3
-------------------------------------
4 | 5 | 6 | 7
-------------------------------------
8 | 9 | 10 (cval) | 11
-------------------------------------
12 | 13 | 14 | 15
- inline uchar CvLBPEvaluator::Feature::calc(const cv::Mat &_sum, size_t y) const
- {
- const int* psum = _sum.ptr<int>((int)y);
- int cval = psum[p[5]] - psum[p[6]] - psum[p[9]] + psum[p[10]];
-
- return (uchar)(
- (psum[p[0]] - psum[p[1]] - psum[p[4]] + psum[p[5]] >= cval ? 128 : 0) |
- (psum[p[1]] - psum[p[2]] - psum[p[5]] + psum[p[6]] >= cval ? 64 : 0) |
- (psum[p[2]] - psum[p[3]] - psum[p[6]] + psum[p[7]] >= cval ? 32 : 0) |
- (psum[p[6]] - psum[p[7]] - psum[p[10]] + psum[p[11]] >= cval ? 16 : 0) |
- (psum[p[10]] - psum[p[11]] - psum[p[14]] + psum[p[15]] >= cval ? 8 : 0) |
- (psum[p[9]] - psum[p[10]] - psum[p[13]] + psum[p[14]] >= cval ? 4 : 0) |
- (psum[p[8]] - psum[p[9]] - psum[p[12]] + psum[p[13]] >= cval ? 2 : 0) |
- (psum[p[4]] - psum[p[5]] - psum[p[8]] + psum[p[9]] >= cval ? 1 : 0));
- }
10 需要说明的是,上段代码中的p[?]保存的是图像像素在sum矩阵中的偏移量。这些地址是固定的,在CvFeatureEvaluator初始化的时候创建。
- void CvFeatureEvaluator::init(const CvFeatureParams *_featureParams,
- int _maxSampleCount, Size _winSize )
- {
- CV_Assert(_maxSampleCount > 0);
- featureParams = (CvFeatureParams *)_featureParams;
- winSize = _winSize;
- numFeatures = 0;
- cls.create( (int)_maxSampleCount, 1, CV_32FC1 );
- generateFeatures();
- }
- void CvLBPEvaluator::generateFeatures()
- {
- int offset = winSize.width + 1;
- for( int x = 0; x < winSize.width; x++ )
- for( int y = 0; y < winSize.height; y++ )
- for( int w = 1; w <= winSize.width / 3; w++ )
- for( int h = 1; h <= winSize.height / 3; h++ )
- if ( (x+3*w <= winSize.width) && (y+3*h <= winSize.height) )
- features.push_back( Feature(offset, x, y, w, h ) );
- numFeatures = (int)features.size();
- }
从这里看,其实现还是和原始的LBP有些不同的。
这篇关于train_cascade 源码阅读之LBP特征的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!