train_cascade 源码阅读之LBP特征
2015-01-19 18:14
393 查看
本文以LBP特征为例,介绍了OpenCV中train_cascade数据初始化的过程。
1 在CvCascadeBoost中,创建了CvCascadeBoostTrainData对象。
2 在CvCascadeBoostTrainData中调用setData函数。
3 在setData函数中调用了预先计算特征,也就是参数中preCalcValBufSize, preClacIdxBufSize预留的内存初始化的地方。
4 在precalculate函数中,有初始化时计算一次特征的函数。
5 在该函数内,用函数指针调用了featureEvaluator的一个operator(),如果是LBP特征的话,则调用的是LBP子类的对应函数。
6 在CvLBPEvaluator中定义了operator()虚函数。并且它调用了calc函数,返回计算得到的LBP特征。
7 在CvLBPEvaluator初始化的时候,初始化了sum矩阵,它有样本和个数相同多的行。
8 创建积分图矩阵,将矩阵的数据指向刚才创建好的sum的对应样本行。
9 调用积分图,返回LBP特征,从函数中可以看到,作者使用的是原始的LBP特征,并没有归一化或者合并等等操作。
0 | 1 | 2 | 3
-------------------------------------
4 | 5 | 6 | 7
-------------------------------------
8 | 9 | 10 (cval) | 11
-------------------------------------
12 | 13 | 14 | 15
10 需要说明的是,上段代码中的p[?]保存的是图像像素在sum矩阵中的偏移量。这些地址是固定的,在CvFeatureEvaluator初始化的时候创建。
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 ) { …… // precalculate valCache and set indices in buf <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) | // 0 (psum[p[1]] - psum[p[2]] - psum[p[5]] + psum[p[6]] >= cval ? 64 : 0) | // 1 (psum[p[2]] - psum[p[3]] - psum[p[6]] + psum[p[7]] >= cval ? 32 : 0) | // 2 (psum[p[6]] - psum[p[7]] - psum[p[10]] + psum[p[11]] >= cval ? 16 : 0) | // 5 (psum[p[10]] - psum[p[11]] - psum[p[14]] + psum[p[15]] >= cval ? 8 : 0) | // 8 (psum[p[9]] - psum[p[10]] - psum[p[13]] + psum[p[14]] >= cval ? 4 : 0) | // 7 (psum[p[8]] - psum[p[9]] - psum[p[12]] + psum[p[13]] >= cval ? 2 : 0) | // 6 (psum[p[4]] - psum[p[5]] - psum[p[8]] + psum[p[9]] >= cval ? 1 : 0)); // 3 }
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特征
- train _cascade 源码阅读之HOG特征
- train_cascade 源码阅读之Haar特征
- train _cascade 源码阅读之HOG特征
- train_cascade 源码阅读之Haar特征
- train_cascade 源码阅读之级联训练
- train_cascade 源码阅读之级联训练
- 用opencv的traincascade.exe训练行人的HAAR、LBP和HOG特征的xml文件,并对分类器进行加载和检测
- train_cascade 源码阅读系列
- 用opencv自带的traincascade.exe训练给予haar特征和LBP特征的分类器
- 用opencv的traincascade.exe训练行人的HAAR、LBP和HOG特征的xml
- 为什么opencv train_cascade训练级联分类器时,lbp特征比haar_like特征快?
- Opencv中traincascade+LBP的训练过程及方法
- Opencv中traincascade+LBP的训练过程及方法
- PG2 BYPASS源码阅读 学习x64解密定时器、特征码定位
- 利用opencv训练基于Haar特征、LBP特征、Hog特征的分类器cascade.xml
- VLFeat库->LBP特征源码解析
- tomcat源码阅读(二) Digester方法详解
- [hadoop源码阅读][8]-datanode-DataXceiver
- diamond源码阅读-diamond-server