From b277fd20fe92fa7f3e128e5fbc3724a150aa2149 Mon Sep 17 00:00:00 2001 From: Jordan Cheney Date: Fri, 1 May 2015 17:03:30 -0400 Subject: [PATCH] Integrated representations into the backend and reformatted into a classifier --- openbr/core/boost.cpp | 22 ++++++++++++++++++++++ openbr/core/boost.h | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- openbr/core/cascade.cpp | 318 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ openbr/core/cascade.h | 72 ------------------------------------------------------------------------ openbr/core/features.cpp | 26 -------------------------- openbr/core/features.h | 75 --------------------------------------------------------------------------- openbr/openbr_plugin.h | 5 ----- openbr/plugins/classification/boostedforest.cpp | 1 - openbr/plugins/classification/cascade.cpp | 84 ++++++++++++++++++++++++++++++++++++------------------------------------------------ openbr/plugins/metadata/cascade.cpp | 111 +-------------------------------------------------------------------------------------------------------------- openbr/plugins/representation/mblbp.cpp | 13 ++++++++++--- 11 files changed, 131 insertions(+), 659 deletions(-) delete mode 100644 openbr/core/cascade.cpp delete mode 100644 openbr/core/cascade.h delete mode 100644 openbr/core/features.cpp delete mode 100644 openbr/core/features.h diff --git a/openbr/core/boost.cpp b/openbr/core/boost.cpp index bbc0997..f3699c1 100644 --- a/openbr/core/boost.cpp +++ b/openbr/core/boost.cpp @@ -137,6 +137,28 @@ static CvMat* cvPreprocessIndexArray( const CvMat* idx_arr, int data_arr_size, b return idx; } +//------------------------------------- FeatureEvaluator --------------------------------------- + +void FeatureEvaluator::init(Representation *_representation, int _maxSampleCount) +{ + representation = _representation; + data.create((int)_maxSampleCount, representation->postWindowSize().area(), CV_32SC1); + cls.create( (int)_maxSampleCount, 1, CV_32FC1 ); +} + +void FeatureEvaluator::setImage(const Mat &img, uchar clsLabel, int idx) +{ + cls.ptr(idx)[0] = clsLabel; + + Mat integralImg(representation->postWindowSize(), data.type(), data.ptr(idx)); + representation->preprocess(img, integralImg); +} + +void FeatureEvaluator::writeFeatures(FileStorage &fs, const Mat &featureMap) const +{ + representation->write(fs, featureMap); +} + //----------------------------- CascadeBoostParams ------------------------------------------------- CascadeBoostParams::CascadeBoostParams() : minHitRate( 0.995F), maxFalseAlarm( 0.5F ) diff --git a/openbr/core/boost.h b/openbr/core/boost.h index c7030c9..9710d26 100644 --- a/openbr/core/boost.h +++ b/openbr/core/boost.h @@ -1,12 +1,73 @@ #ifndef _BOOST_H_ #define _BOOST_H_ -#include "features.h" #include "ml.h" +#include + +#define CC_CASCADE_FILENAME "cascade.xml" +#define CC_PARAMS_FILENAME "params.xml" + +#define CC_CASCADE_PARAMS "cascadeParams" +#define CC_STAGE_TYPE "stageType" +#define CC_FEATURE_TYPE "featureType" +#define CC_HEIGHT "height" +#define CC_WIDTH "width" + +#define CC_STAGE_NUM "stageNum" +#define CC_STAGES "stages" +#define CC_STAGE_PARAMS "stageParams" + +#define CC_BOOST "BOOST" +#define CC_BOOST_TYPE "boostType" +#define CC_DISCRETE_BOOST "DAB" +#define CC_REAL_BOOST "RAB" +#define CC_LOGIT_BOOST "LB" +#define CC_GENTLE_BOOST "GAB" +#define CC_MINHITRATE "minHitRate" +#define CC_MAXFALSEALARM "maxFalseAlarm" +#define CC_TRIM_RATE "weightTrimRate" +#define CC_MAX_DEPTH "maxDeptrh" +#define CC_WEAK_COUNT "maxWeakCount" +#define CC_STAGE_THRESHOLD "stageThreshold" +#define CC_WEAK_CLASSIFIERS "weakClassifiers" +#define CC_INTERNAL_NODES "internalNodes" +#define CC_LEAF_VALUES "leafValues" + +#define CC_FEATURES "features" +#define CC_FEATURE_PARAMS "featureParams" +#define CC_MAX_CAT_COUNT "maxCatCount" +#define CC_FEATURE_SIZE "featSize" + +#define CC_LBP "LBP" +#define CC_RECT "rect" + +#ifdef _WIN32 +#define TIME( arg ) (((double) clock()) / CLOCKS_PER_SEC) +#else +#define TIME( arg ) (time( arg )) +#endif namespace br { +struct FeatureEvaluator +{ + ~FeatureEvaluator() {} + void init(Representation *_representation, int _maxSampleCount); + void setImage(const cv::Mat& img, uchar clsLabel, int idx); + void writeFeatures(cv::FileStorage &fs, const cv::Mat& featureMap) const; + float operator()(int featureIdx, int sampleIdx) const { return representation->evaluate(data.row(sampleIdx), featureIdx); } + + int getNumFeatures() const { return representation->numFeatures(); } + int getMaxCatCount() const { return representation->maxCatCount(); } + int getFeatureSize() const { return 1; } + const cv::Mat& getCls() const { return cls; } + float getCls(int si) const { return cls.at(si, 0); } + + cv::Mat data, cls; + Representation *representation; +}; + struct CascadeBoostParams : CvBoostParams { float minHitRate; diff --git a/openbr/core/cascade.cpp b/openbr/core/cascade.cpp deleted file mode 100644 index cc568b1..0000000 --- a/openbr/core/cascade.cpp +++ /dev/null @@ -1,318 +0,0 @@ -#include "cascade.h" -#include -#include -#include - -using namespace std; -using namespace br; -using namespace cv; - -bool CascadeImageReader::create(const QList &_posImages, const QList &_negImages, Size _winSize) -{ - posImages = _posImages; - negImages = _negImages; - winSize = _winSize; - - posIdx = negIdx = 0; - - src.create( 0, 0 , CV_8UC1 ); - img.create( 0, 0, CV_8UC1 ); - point = offset = Point( 0, 0 ); - scale = 1.0F; - scaleFactor = 1.4142135623730950488016887242097F; - stepFactor = 0.5F; - round = 0; - - return true; -} - -bool CascadeImageReader::nextNeg() -{ - Point _offset = Point(0,0); - size_t count = negImages.size(); - for (size_t i = 0; i < count; i++) { - src = negImages[negIdx++]; - if( src.empty() ) - continue; - round += negIdx / count; - round = round % (winSize.width * winSize.height); - negIdx %= count; - - _offset.x = std::min( (int)round % winSize.width, src.cols - winSize.width ); - _offset.y = std::min( (int)round / winSize.width, src.rows - winSize.height ); - if( !src.empty() && src.type() == CV_8UC1 && _offset.x >= 0 && _offset.y >= 0 ) - break; - } - - if( src.empty() ) - return false; // no appropriate image - point = offset = _offset; - scale = max( ((float)winSize.width + point.x) / ((float)src.cols), - ((float)winSize.height + point.y) / ((float)src.rows) ); - - Size sz( (int)(scale*src.cols + 0.5F), (int)(scale*src.rows + 0.5F) ); - resize( src, img, sz ); - return true; -} - -bool CascadeImageReader::getNeg( Mat& _img ) -{ - CV_Assert( !_img.empty() ); - CV_Assert( _img.type() == CV_8UC1 ); - CV_Assert( _img.cols == winSize.width ); - CV_Assert( _img.rows == winSize.height ); - - if( img.empty() ) - if ( !nextNeg() ) - return false; - - Mat mat( winSize.height, winSize.width, CV_8UC1, - (void*)(img.data + point.y * img.step + point.x * img.elemSize()), img.step ); - mat.copyTo(_img); - - if( (int)( point.x + (1.0F + stepFactor ) * winSize.width ) < img.cols ) - point.x += (int)(stepFactor * winSize.width); - else - { - point.x = offset.x; - if( (int)( point.y + (1.0F + stepFactor ) * winSize.height ) < img.rows ) - point.y += (int)(stepFactor * winSize.height); - else - { - point.y = offset.y; - scale *= scaleFactor; - if( scale <= 1.0F ) - resize( src, img, Size( (int)(scale*src.cols), (int)(scale*src.rows) ) ); - else - { - if ( !nextNeg() ) - return false; - } - } - } - return true; -} - - -bool CascadeImageReader::getPos(Mat &_img) -{ - posImages[posIdx++].copyTo(_img); - return true; -} - -//---------------------------- CascadeClassifier -------------------------------------- - -bool BrCascadeClassifier::train(const string _cascadeDirName, - const QList &_posImages, - const QList &_negImages, - int _numPos, int _numNeg, - int _precalcValBufSize, int _precalcIdxBufSize, - int _numStages, - Size _winSize, - const CascadeBoostParams& _stageParams) -{ - // Start recording clock ticks for training time output - const clock_t begin_time = clock(); - - if (_cascadeDirName.empty()) - CV_Error( CV_StsBadArg, "_cascadeDirName is NULL" ); - - string dirName; - if (_cascadeDirName.find_last_of("/\\") == (_cascadeDirName.length() - 1) ) - dirName = _cascadeDirName; - else - dirName = _cascadeDirName + '/'; - - winSize = _winSize; - - numPos = _numPos; - numNeg = _numNeg; - numStages = _numStages; - imgReader.create(_posImages, _negImages, winSize); - - Representation *representation = Representation::make("MBLBP(24,24)", NULL); - - stageParams = new CascadeBoostParams; - *stageParams = _stageParams; - featureEvaluator = new FeatureEvaluator; - featureEvaluator->init(representation, numPos + numNeg); - stageClassifiers.reserve( numStages ); - - double requiredLeafFARate = pow( (double) stageParams->maxFalseAlarm, (double) numStages ) / - (double)stageParams->max_depth; - double tempLeafFARate; - - for (int i = 0; i < numStages; i++) { - cout << endl << "===== TRAINING " << i << "-stage =====" << endl; - cout << "train( (FeatureEvaluator*)featureEvaluator, - curNumSamples, _precalcValBufSize, _precalcIdxBufSize, - *((CascadeBoostParams*)stageParams) ); - cout << "END>" << endl; - - if (!isStageTrained) - break; - - stageClassifiers.push_back(tempStage); - - // Output training time up till now - float seconds = float( clock () - begin_time ) / CLOCKS_PER_SEC; - int days = int(seconds) / 60 / 60 / 24; - int hours = (int(seconds) / 60 / 60) % 24; - int minutes = (int(seconds) / 60) % 60; - int seconds_left = int(seconds) % 60; - cout << "Training until now has taken " << days << " days " << hours << " hours " << minutes << " minutes " << seconds_left <<" seconds." << endl; - } - - if (stageClassifiers.size() == 0) { - cout << "Cascade classifier can't be trained. Check the used training parameters." << endl; - return false; - } - - save(dirName + CC_CASCADE_FILENAME); - - return true; -} - -int BrCascadeClassifier::predict( int sampleIdx ) -{ - CV_DbgAssert( sampleIdx < numPos + numNeg ); - for (vector< Ptr >::iterator it = stageClassifiers.begin(); - it != stageClassifiers.end(); it++ ) - { - if ( (*it)->predict( sampleIdx ) == 0.f ) - return 0; - } - return 1; -} - -bool BrCascadeClassifier::updateTrainingSet( double& acceptanceRatio) -{ - int64 posConsumed = 0, negConsumed = 0; - imgReader.restart(); - - int posCount = fillPassedSamples( 0, numPos, true, posConsumed ); - if( !posCount ) - return false; - cout << "POS count : consumed " << posCount << " : " << (int)posConsumed << endl; - - int proNumNeg = cvRound( ( ((double)numNeg) * ((double)posCount) ) / numPos ); // apply only a fraction of negative samples. double is required since overflow is possible - int negCount = fillPassedSamples( posCount, proNumNeg, false, negConsumed ); - if ( !negCount ) - return false; - - curNumSamples = posCount + negCount; - acceptanceRatio = negConsumed == 0 ? 0 : ( (double)negCount/(double)(int64)negConsumed ); - cout << "NEG count : acceptanceRatio " << negCount << " : " << acceptanceRatio << endl; - return true; -} - -int BrCascadeClassifier::fillPassedSamples( int first, int count, bool isPositive, int64& consumed ) -{ - int getcount = 0; - Mat img(winSize, CV_8UC1); - for( int i = first; i < first + count; i++ ) - { - for( ; ; ) - { - bool isGetImg = isPositive ? imgReader.getPos( img ) : - imgReader.getNeg( img ); - if( !isGetImg ) - return getcount; - consumed++; - - featureEvaluator->setImage( img, isPositive ? 1 : 0, i ); - if( predict( i ) == 1.0F ) - { - getcount++; - printf("%s current samples: %d\r", isPositive ? "POS":"NEG", getcount); - break; - } - } - } - return getcount; -} - -void BrCascadeClassifier::writeParams( FileStorage &fs ) const -{ - fs << CC_STAGE_TYPE << CC_BOOST; - fs << CC_FEATURE_TYPE << CC_LBP; - fs << CC_HEIGHT << winSize.height; - fs << CC_WIDTH << winSize.width; - - fs << CC_STAGE_PARAMS << "{"; stageParams->write( fs ); fs << "}"; - - fs << CC_FEATURE_PARAMS << "{"; - fs << CC_MAX_CAT_COUNT << featureEvaluator->getMaxCatCount(); - fs << CC_FEATURE_SIZE << featureEvaluator->getFeatureSize(); - fs << "}"; -} - -void BrCascadeClassifier::writeFeatures( FileStorage &fs, const Mat& featureMap ) const -{ - ((FeatureEvaluator*)((Ptr)featureEvaluator))->writeFeatures( fs, featureMap ); -} - -void BrCascadeClassifier::writeStages( FileStorage &fs, const Mat& featureMap ) const -{ - char cmnt[30]; - int i = 0; - fs << CC_STAGES << "["; - for( vector< Ptr >::const_iterator it = stageClassifiers.begin(); - it != stageClassifiers.end(); it++, i++ ) - { - sprintf( cmnt, "stage %d", i ); - cvWriteComment( fs.fs, cmnt, 0 ); - fs << "{"; - ((CascadeBoost*)((Ptr)*it))->write( fs, featureMap ); - fs << "}"; - } - fs << "]"; -} - -void BrCascadeClassifier::save(const string filename) -{ - FileStorage fs( filename, FileStorage::WRITE ); - - if ( !fs.isOpened() ) - return; - - fs << FileStorage::getDefaultObjectName(filename) << "{"; - - Mat featureMap; - getUsedFeaturesIdxMap( featureMap ); - writeParams( fs ); - fs << CC_STAGE_NUM << (int)stageClassifiers.size(); - writeStages( fs, featureMap ); - writeFeatures( fs, featureMap ); - - fs << "}"; -} - -void BrCascadeClassifier::getUsedFeaturesIdxMap( Mat& featureMap ) -{ - int varCount = featureEvaluator->getNumFeatures() * featureEvaluator->getFeatureSize(); - featureMap.create( 1, varCount, CV_32SC1 ); - featureMap.setTo(Scalar(-1)); - - for( vector< Ptr >::const_iterator it = stageClassifiers.begin(); - it != stageClassifiers.end(); it++ ) - ((CascadeBoost*)((Ptr)(*it)))->markUsedFeaturesInMap( featureMap ); - - for( int fi = 0, idx = 0; fi < varCount; fi++ ) - if ( featureMap.at(0, fi) >= 0 ) - featureMap.ptr(0)[fi] = idx++; -} - diff --git a/openbr/core/cascade.h b/openbr/core/cascade.h deleted file mode 100644 index 7708729..0000000 --- a/openbr/core/cascade.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef CASCADE_H -#define CASCADE_H - -#include -#include -#include "features.h" -#include "boost.h" - -namespace br -{ - -class CascadeImageReader -{ -public: - bool create( const QList &_posImages, const QList &_negImages, cv::Size _winSize ); - void restart() { posIdx = 0; } - bool getNeg(cv::Mat &_img); - bool getPos(cv::Mat &_img); - - QList posImages, negImages; - - int posIdx, negIdx; - - cv::Mat src, img; - cv::Point offset, point; - float scale; - float scaleFactor; - float stepFactor; - size_t round; - cv::Size winSize; - -private: - bool nextNeg(); -}; - - -class BrCascadeClassifier -{ -public: - bool train(const std::string _cascadeDirName, - const QList &_posImages, - const QList &_negImages, - int _numPos, int _numNeg, - int _precalcValBufSize, int _precalcIdxBufSize, - int _numStages, - cv::Size _winSize, - const CascadeBoostParams& _stageParams); -private: - int predict(int sampleIdx); - void save(const std::string cascadeDirName); - bool updateTrainingSet(double& acceptanceRatio); - int fillPassedSamples(int first, int count, bool isPositive, int64& consumed); - - void writeParams(cv::FileStorage &fs) const; - void writeStages(cv::FileStorage &fs, const cv::Mat& featureMap) const; - void writeFeatures(cv::FileStorage &fs, const cv::Mat& featureMap) const; - - void getUsedFeaturesIdxMap(cv::Mat& featureMap); - - cv::Ptr stageParams; - - cv::Ptr featureEvaluator; - std::vector< cv::Ptr > stageClassifiers; - CascadeImageReader imgReader; - int numStages, curNumSamples; - int numPos, numNeg; - cv::Size winSize; -}; - -} // namespace br - -#endif // CASCADE_H diff --git a/openbr/core/features.cpp b/openbr/core/features.cpp deleted file mode 100644 index fe77263..0000000 --- a/openbr/core/features.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "features.h" - -using namespace cv; -using namespace br; - -//------------------------------------- FeatureEvaluator --------------------------------------- - -void FeatureEvaluator::init(Representation *_representation, int _maxSampleCount) -{ - representation = _representation; - data.create((int)_maxSampleCount, representation->postWindowSize().area(), CV_32SC1); - cls.create( (int)_maxSampleCount, 1, CV_32FC1 ); -} - -void FeatureEvaluator::setImage(const Mat &img, uchar clsLabel, int idx) -{ - cls.ptr(idx)[0] = clsLabel; - - Mat integralImg(representation->postWindowSize(), data.type(), data.ptr(idx)); - representation->preprocess(img, integralImg); -} - -void FeatureEvaluator::writeFeatures(FileStorage &fs, const Mat &featureMap) const -{ - representation->write(fs, featureMap); -} diff --git a/openbr/core/features.h b/openbr/core/features.h deleted file mode 100644 index c21c80d..0000000 --- a/openbr/core/features.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef FEATURE_H -#define FEATURE_H - -#include -#include "opencv2/imgproc/imgproc.hpp" -#include - -#define CC_CASCADE_FILENAME "cascade.xml" -#define CC_PARAMS_FILENAME "params.xml" - -#define CC_CASCADE_PARAMS "cascadeParams" -#define CC_STAGE_TYPE "stageType" -#define CC_FEATURE_TYPE "featureType" -#define CC_HEIGHT "height" -#define CC_WIDTH "width" - -#define CC_STAGE_NUM "stageNum" -#define CC_STAGES "stages" -#define CC_STAGE_PARAMS "stageParams" - -#define CC_BOOST "BOOST" -#define CC_BOOST_TYPE "boostType" -#define CC_DISCRETE_BOOST "DAB" -#define CC_REAL_BOOST "RAB" -#define CC_LOGIT_BOOST "LB" -#define CC_GENTLE_BOOST "GAB" -#define CC_MINHITRATE "minHitRate" -#define CC_MAXFALSEALARM "maxFalseAlarm" -#define CC_TRIM_RATE "weightTrimRate" -#define CC_MAX_DEPTH "maxDeptrh" -#define CC_WEAK_COUNT "maxWeakCount" -#define CC_STAGE_THRESHOLD "stageThreshold" -#define CC_WEAK_CLASSIFIERS "weakClassifiers" -#define CC_INTERNAL_NODES "internalNodes" -#define CC_LEAF_VALUES "leafValues" - -#define CC_FEATURES "features" -#define CC_FEATURE_PARAMS "featureParams" -#define CC_MAX_CAT_COUNT "maxCatCount" -#define CC_FEATURE_SIZE "featSize" - -#define CC_LBP "LBP" -#define CC_RECT "rect" - -#ifdef _WIN32 -#define TIME( arg ) (((double) clock()) / CLOCKS_PER_SEC) -#else -#define TIME( arg ) (time( arg )) -#endif - -namespace br -{ - -class FeatureEvaluator -{ -public: - ~FeatureEvaluator() {} - void init(Representation *_representation, int _maxSampleCount); - void setImage(const cv::Mat& img, uchar clsLabel, int idx); - void writeFeatures(cv::FileStorage &fs, const cv::Mat& featureMap) const; - float operator()(int featureIdx, int sampleIdx) const { return representation->evaluate(data.row(sampleIdx), featureIdx); } - - int getNumFeatures() const { return representation->numFeatures(); } - int getMaxCatCount() const { return representation->maxCatCount(); } - int getFeatureSize() const { return 1; } - const cv::Mat& getCls() const { return cls; } - float getCls(int si) const { return cls.at(si, 0); } - - cv::Mat data, cls; - Representation *representation; -}; - -} // namespace br - -#endif // FEATURE_H diff --git a/openbr/openbr_plugin.h b/openbr/openbr_plugin.h index 438679c..f8ebf59 100644 --- a/openbr/openbr_plugin.h +++ b/openbr/openbr_plugin.h @@ -1395,11 +1395,6 @@ class BR_EXPORT Representation : public Object { Q_OBJECT - Q_PROPERTY(int winWidth READ get_winWidth WRITE set_winWidth RESET reset_winWidth STORED false) - Q_PROPERTY(int winHeight READ get_winHeight WRITE set_winHeight RESET reset_winHeight STORED false) - BR_PROPERTY(int, winWidth, 24) - BR_PROPERTY(int, winHeight, 24) - public: virtual ~Representation() {} diff --git a/openbr/plugins/classification/boostedforest.cpp b/openbr/plugins/classification/boostedforest.cpp index 8e0e0a0..3756536 100644 --- a/openbr/plugins/classification/boostedforest.cpp +++ b/openbr/plugins/classification/boostedforest.cpp @@ -1,6 +1,5 @@ #include #include -#include using namespace cv; diff --git a/openbr/plugins/classification/cascade.cpp b/openbr/plugins/classification/cascade.cpp index c4b6f3f..4dad1a3 100644 --- a/openbr/plugins/classification/cascade.cpp +++ b/openbr/plugins/classification/cascade.cpp @@ -1,5 +1,6 @@ +#include + #include -#include #include using namespace cv; @@ -9,7 +10,7 @@ namespace br struct ImageHandler { - bool create( const QList &_posImages, const QList &_negImages, cv::Size _winSize ) + bool create(const QList &_posImages, const QList &_negImages, Size _winSize) { posImages = _posImages; negImages = _negImages; @@ -30,72 +31,57 @@ struct ImageHandler void restart() { posIdx = 0; } - int numPos() const { return posImages.size(); } - int numNeg() const { return negImages.size(); } - - bool nextNeg() + void nextNeg() { - Point _offset = Point(0,0); - size_t count = negImages.size(); - for (size_t i = 0; i < count; i++) { + int count = negImages.size(); + for (int i = 0; i < count; i++) { src = negImages[negIdx++]; - if( src.empty() ) - continue; + round += negIdx / count; round = round % (winSize.width * winSize.height); negIdx %= count; - _offset.x = std::min( (int)round % winSize.width, src.cols - winSize.width ); - _offset.y = std::min( (int)round / winSize.width, src.rows - winSize.height ); - if( !src.empty() && src.type() == CV_8UC1 && _offset.x >= 0 && _offset.y >= 0 ) + offset.x = qMin( (int)round % winSize.width, src.cols - winSize.width ); + offset.y = qMin( (int)round / winSize.width, src.rows - winSize.height ); + if (!src.empty() && src.type() == CV_8UC1 && offset.x >= 0 && offset.y >= 0) break; } - if( src.empty() ) - return false; // no appropriate image - point = offset = _offset; - scale = max( ((float)winSize.width + point.x) / ((float)src.cols), - ((float)winSize.height + point.y) / ((float)src.rows) ); + point = offset; + scale = max(((float)winSize.width + point.x) / ((float)src.cols), + ((float)winSize.height + point.y) / ((float)src.rows)); - Size sz( (int)(scale*src.cols + 0.5F), (int)(scale*src.rows + 0.5F) ); - resize( src, img, sz ); - return true; + Size sz((int)(scale*src.cols + 0.5F), (int)(scale*src.rows + 0.5F)); + resize(src, img, sz); } - bool getNeg(cv::Mat &_img) + bool getNeg(Mat &_img) { - if( img.empty() ) - if ( !nextNeg() ) - return false; + if (img.empty()) + nextNeg(); - Mat mat( winSize.height, winSize.width, CV_8UC1, - (void*)(img.data + point.y * img.step + point.x * img.elemSize()), img.step ); - mat.copyTo(_img); + Mat m(winSize.height, winSize.width, CV_8UC1, (void*)(img.data + point.y * img.step + point.x * img.elemSize()), img.step); + m.copyTo(_img); - if( (int)( point.x + (1.0F + stepFactor ) * winSize.width ) < img.cols ) + if ((int)(point.x + (1.0F + stepFactor) * winSize.width) < img.cols) point.x += (int)(stepFactor * winSize.width); - else - { + else { point.x = offset.x; - if( (int)( point.y + (1.0F + stepFactor ) * winSize.height ) < img.rows ) + if ((int)( point.y + (1.0F + stepFactor ) * winSize.height ) < img.rows) point.y += (int)(stepFactor * winSize.height); - else - { + else { point.y = offset.y; scale *= scaleFactor; - if( scale <= 1.0F ) - resize( src, img, Size( (int)(scale*src.cols), (int)(scale*src.rows) ) ); + if (scale <= 1.0F) + resize(src, img, Size((int)(scale*src.cols), (int)(scale*src.rows))); else - { - if ( !nextNeg() ) - return false; - } + nextNeg(); } } return true; } - bool getPos(cv::Mat &_img) + bool getPos(Mat &_img) { if (posIdx >= posImages.size()) return false; @@ -104,20 +90,20 @@ struct ImageHandler return true; } - QList posImages, negImages; + QList posImages, negImages; int posIdx, negIdx; - cv::Mat src, img; - cv::Point offset, point; + Mat src, img; + Point offset, point; float scale; float scaleFactor; float stepFactor; size_t round; - cv::Size winSize; + Size winSize; }; -class _CascadeClassifier : public Classifier +class CascadeClassifier : public Classifier { Q_OBJECT @@ -242,6 +228,7 @@ private: qFatal("Cannot get another positive sample!"); if (classify(pos) == 1.0f) { + printf("POS current samples: %d\r", images.size()); images.append(pos); labels.append(1.0f); } @@ -257,6 +244,7 @@ private: qFatal("Cannot get another negative sample!"); if (classify(neg) == 1.0f) { + printf("NEG current samples: %d\r", images.size() - posCount); images.append(neg); labels.append(0.0f); } @@ -269,7 +257,7 @@ private: } }; -BR_REGISTER(Classifier, _CascadeClassifier) +BR_REGISTER(Classifier, CascadeClassifier) } // namespace br diff --git a/openbr/plugins/metadata/cascade.cpp b/openbr/plugins/metadata/cascade.cpp index 8787121..9dd61e9 100644 --- a/openbr/plugins/metadata/cascade.cpp +++ b/openbr/plugins/metadata/cascade.cpp @@ -22,7 +22,6 @@ #include #include #include -#include using namespace cv; @@ -65,34 +64,19 @@ private: * \author Josh Klontz \cite jklontz * \author David Crouse \cite dgcrouse */ -class CascadeTransform : public MetaTransform +class CascadeTransform : public UntrainableMetaTransform { Q_OBJECT Q_PROPERTY(QString model READ get_model WRITE set_model RESET reset_model STORED false) Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) Q_PROPERTY(int minNeighbors READ get_minNeighbors WRITE set_minNeighbors RESET reset_minNeighbors STORED false) Q_PROPERTY(bool ROCMode READ get_ROCMode WRITE set_ROCMode RESET reset_ROCMode STORED false) - - // Training parameters - Q_PROPERTY(QString vecFile READ get_vecFile WRITE set_vecFile RESET reset_vecFile STORED false) - Q_PROPERTY(QString negFile READ get_negFile WRITE set_negFile RESET reset_negFile STORED false) - Q_PROPERTY(int winWidth READ get_winWidth WRITE set_winWidth RESET reset_winWidth STORED false) - Q_PROPERTY(int winHeight READ get_winHeight WRITE set_winHeight RESET reset_winHeight STORED false) - Q_PROPERTY(int numPos READ get_numPos WRITE set_numPos RESET reset_numPos STORED false) - Q_PROPERTY(int numNeg READ get_numNeg WRITE set_numNeg RESET reset_numNeg STORED false) BR_PROPERTY(QString, model, "FrontalFace") BR_PROPERTY(int, minSize, 64) BR_PROPERTY(int, minNeighbors, 5) BR_PROPERTY(bool, ROCMode, false) - BR_PROPERTY(QString, vecFile, "data.vec") - BR_PROPERTY(QString, negFile, "neg.txt") - BR_PROPERTY(int, winWidth, 24) - BR_PROPERTY(int, winHeight, 24) - BR_PROPERTY(int, numPos, 1000) - BR_PROPERTY(int, numNeg, 1000) - Resource cascadeResource; void init() @@ -101,99 +85,6 @@ class CascadeTransform : public MetaTransform if (model == "Ear" || model == "Eye" || model == "FrontalFace" || model == "ProfileFace") this->trainable = false; } - - QList getPos() - { - FILE *file = fopen(vecFile.toStdString().c_str(), "rb"); - if ( !file ) - qFatal("Couldn't open the file"); - - short* vec = 0; - int count, vecSize, last, base; - - short tmp = 0; - if( fread( &count, sizeof( count ), 1, file ) != 1 || - fread( &vecSize, sizeof( vecSize ), 1, file ) != 1 || - fread( &tmp, sizeof( tmp ), 1, file ) != 1 || - fread( &tmp, sizeof( tmp ), 1, file ) != 1 ) - CV_Error_( CV_StsParseError, ("wrong file format for %s\n", qPrintable(vecFile)) ); - base = sizeof( count ) + sizeof( vecSize ) + 2*sizeof( tmp ); - - last = 0; - vec = (short*) cvAlloc( sizeof( *vec ) * vecSize ); - CV_Assert( vec ); - - QList posImages; - for (int i = 0; i < 35770; i++) { - Mat pos(winHeight, winWidth, CV_8UC1); - - CV_Assert( pos.rows * pos.cols == vecSize ); - uchar tmp = 0; - size_t elements_read = fread( &tmp, sizeof( tmp ), 1, file ); - if( elements_read != 1 ) - CV_Error( CV_StsBadArg, "Can not get new positive sample. The most possible reason is " - "insufficient count of samples in given vec-file.\n"); - elements_read = fread( vec, sizeof( vec[0] ), vecSize, file ); - if( elements_read != (size_t)(vecSize) ) - CV_Error( CV_StsBadArg, "Can not get new positive sample. Seems that vec-file has incorrect structure.\n"); - - if( feof( file ) || last++ >= count ) - CV_Error( CV_StsBadArg, "Can not get new positive sample. vec-file is over.\n"); - - for( int r = 0; r < pos.rows; r++ ) - for( int c = 0; c < pos.cols; c++ ) - pos.ptr(r)[c] = (uchar)vec[r * pos.cols + c]; - posImages.append(pos); - } - return posImages; - } - - QList getNeg() - { - QList negs; - - std::string dirname, str; - std::ifstream file(negFile.toStdString().c_str()); - - size_t pos = negFile.toStdString().rfind('\\'); - char dlmrt = '\\'; - if (pos == string::npos) - { - pos = negFile.toStdString().rfind('/'); - dlmrt = '/'; - } - dirname = pos == string::npos ? "" : negFile.toStdString().substr(0, pos) + dlmrt; - while( !file.eof() ) - { - std::getline(file, str); - if (str.empty()) break; - if (str.at(0) == '#' ) continue; - negs.append(imread(dirname + str, CV_LOAD_IMAGE_GRAYSCALE)); - } - file.close(); - - return negs; - } - - // Train transform - void train(const TemplateList& data) - { - (void)data; - - BrCascadeClassifier classifier; - - QList posImages = getPos(); - QList negImages = getNeg(); - - CascadeBoostParams stageParams(CvBoost::GENTLE, 0.999, 0.5, 0.95, 1, 200); - - QString cascadeDir = Globals->sdkPath + "/share/openbr/models/openbrcascades/" + model; - classifier.train(cascadeDir.toStdString(), - posImages, negImages, - numPos, numNeg, 1024, 1024, 12, - Size(winWidth, winHeight), - stageParams); - } void project(const Template &src, Template &dst) const { diff --git a/openbr/plugins/representation/mblbp.cpp b/openbr/plugins/representation/mblbp.cpp index 7934560..be74148 100644 --- a/openbr/plugins/representation/mblbp.cpp +++ b/openbr/plugins/representation/mblbp.cpp @@ -22,6 +22,11 @@ class MBLBPRepresentation : public Representation { Q_OBJECT + Q_PROPERTY(int winWidth READ get_winWidth WRITE set_winWidth RESET reset_winWidth STORED false) + Q_PROPERTY(int winHeight READ get_winHeight WRITE set_winHeight RESET reset_winHeight STORED false) + BR_PROPERTY(int, winWidth, 24) + BR_PROPERTY(int, winHeight, 24) + void init() { int offset = winWidth + 1; @@ -45,9 +50,11 @@ class MBLBPRepresentation : public Representation Mat evaluate(const Mat &image, const QList &indices) const { - Mat result(1, indices.size(), CV_32FC1); - for (int i = 0; i < indices.size(); i++) - result.at(i) = (float)features[indices[i]].calc(image); + int size = indices.empty() ? numFeatures() : indices.size(); + + Mat result(1, size, CV_32FC1); + for (int i = 0; i < size; i++) + result.at(i) = evaluate(image, indices.empty() ? i : indices[i]); return result; } -- libgit2 0.21.4