Commit b277fd20fe92fa7f3e128e5fbc3724a150aa2149
1 parent
447ef443
Integrated representations into the backend and reformatted into a classifier
Showing
11 changed files
with
131 additions
and
659 deletions
openbr/core/boost.cpp
| @@ -137,6 +137,28 @@ static CvMat* cvPreprocessIndexArray( const CvMat* idx_arr, int data_arr_size, b | @@ -137,6 +137,28 @@ static CvMat* cvPreprocessIndexArray( const CvMat* idx_arr, int data_arr_size, b | ||
| 137 | return idx; | 137 | return idx; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | +//------------------------------------- FeatureEvaluator --------------------------------------- | ||
| 141 | + | ||
| 142 | +void FeatureEvaluator::init(Representation *_representation, int _maxSampleCount) | ||
| 143 | +{ | ||
| 144 | + representation = _representation; | ||
| 145 | + data.create((int)_maxSampleCount, representation->postWindowSize().area(), CV_32SC1); | ||
| 146 | + cls.create( (int)_maxSampleCount, 1, CV_32FC1 ); | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | +void FeatureEvaluator::setImage(const Mat &img, uchar clsLabel, int idx) | ||
| 150 | +{ | ||
| 151 | + cls.ptr<float>(idx)[0] = clsLabel; | ||
| 152 | + | ||
| 153 | + Mat integralImg(representation->postWindowSize(), data.type(), data.ptr<int>(idx)); | ||
| 154 | + representation->preprocess(img, integralImg); | ||
| 155 | +} | ||
| 156 | + | ||
| 157 | +void FeatureEvaluator::writeFeatures(FileStorage &fs, const Mat &featureMap) const | ||
| 158 | +{ | ||
| 159 | + representation->write(fs, featureMap); | ||
| 160 | +} | ||
| 161 | + | ||
| 140 | //----------------------------- CascadeBoostParams ------------------------------------------------- | 162 | //----------------------------- CascadeBoostParams ------------------------------------------------- |
| 141 | 163 | ||
| 142 | CascadeBoostParams::CascadeBoostParams() : minHitRate( 0.995F), maxFalseAlarm( 0.5F ) | 164 | CascadeBoostParams::CascadeBoostParams() : minHitRate( 0.995F), maxFalseAlarm( 0.5F ) |
openbr/core/boost.h
| 1 | #ifndef _BOOST_H_ | 1 | #ifndef _BOOST_H_ |
| 2 | #define _BOOST_H_ | 2 | #define _BOOST_H_ |
| 3 | 3 | ||
| 4 | -#include "features.h" | ||
| 5 | #include "ml.h" | 4 | #include "ml.h" |
| 5 | +#include <openbr/openbr_plugin.h> | ||
| 6 | + | ||
| 7 | +#define CC_CASCADE_FILENAME "cascade.xml" | ||
| 8 | +#define CC_PARAMS_FILENAME "params.xml" | ||
| 9 | + | ||
| 10 | +#define CC_CASCADE_PARAMS "cascadeParams" | ||
| 11 | +#define CC_STAGE_TYPE "stageType" | ||
| 12 | +#define CC_FEATURE_TYPE "featureType" | ||
| 13 | +#define CC_HEIGHT "height" | ||
| 14 | +#define CC_WIDTH "width" | ||
| 15 | + | ||
| 16 | +#define CC_STAGE_NUM "stageNum" | ||
| 17 | +#define CC_STAGES "stages" | ||
| 18 | +#define CC_STAGE_PARAMS "stageParams" | ||
| 19 | + | ||
| 20 | +#define CC_BOOST "BOOST" | ||
| 21 | +#define CC_BOOST_TYPE "boostType" | ||
| 22 | +#define CC_DISCRETE_BOOST "DAB" | ||
| 23 | +#define CC_REAL_BOOST "RAB" | ||
| 24 | +#define CC_LOGIT_BOOST "LB" | ||
| 25 | +#define CC_GENTLE_BOOST "GAB" | ||
| 26 | +#define CC_MINHITRATE "minHitRate" | ||
| 27 | +#define CC_MAXFALSEALARM "maxFalseAlarm" | ||
| 28 | +#define CC_TRIM_RATE "weightTrimRate" | ||
| 29 | +#define CC_MAX_DEPTH "maxDeptrh" | ||
| 30 | +#define CC_WEAK_COUNT "maxWeakCount" | ||
| 31 | +#define CC_STAGE_THRESHOLD "stageThreshold" | ||
| 32 | +#define CC_WEAK_CLASSIFIERS "weakClassifiers" | ||
| 33 | +#define CC_INTERNAL_NODES "internalNodes" | ||
| 34 | +#define CC_LEAF_VALUES "leafValues" | ||
| 35 | + | ||
| 36 | +#define CC_FEATURES "features" | ||
| 37 | +#define CC_FEATURE_PARAMS "featureParams" | ||
| 38 | +#define CC_MAX_CAT_COUNT "maxCatCount" | ||
| 39 | +#define CC_FEATURE_SIZE "featSize" | ||
| 40 | + | ||
| 41 | +#define CC_LBP "LBP" | ||
| 42 | +#define CC_RECT "rect" | ||
| 43 | + | ||
| 44 | +#ifdef _WIN32 | ||
| 45 | +#define TIME( arg ) (((double) clock()) / CLOCKS_PER_SEC) | ||
| 46 | +#else | ||
| 47 | +#define TIME( arg ) (time( arg )) | ||
| 48 | +#endif | ||
| 6 | 49 | ||
| 7 | namespace br | 50 | namespace br |
| 8 | { | 51 | { |
| 9 | 52 | ||
| 53 | +struct FeatureEvaluator | ||
| 54 | +{ | ||
| 55 | + ~FeatureEvaluator() {} | ||
| 56 | + void init(Representation *_representation, int _maxSampleCount); | ||
| 57 | + void setImage(const cv::Mat& img, uchar clsLabel, int idx); | ||
| 58 | + void writeFeatures(cv::FileStorage &fs, const cv::Mat& featureMap) const; | ||
| 59 | + float operator()(int featureIdx, int sampleIdx) const { return representation->evaluate(data.row(sampleIdx), featureIdx); } | ||
| 60 | + | ||
| 61 | + int getNumFeatures() const { return representation->numFeatures(); } | ||
| 62 | + int getMaxCatCount() const { return representation->maxCatCount(); } | ||
| 63 | + int getFeatureSize() const { return 1; } | ||
| 64 | + const cv::Mat& getCls() const { return cls; } | ||
| 65 | + float getCls(int si) const { return cls.at<float>(si, 0); } | ||
| 66 | + | ||
| 67 | + cv::Mat data, cls; | ||
| 68 | + Representation *representation; | ||
| 69 | +}; | ||
| 70 | + | ||
| 10 | struct CascadeBoostParams : CvBoostParams | 71 | struct CascadeBoostParams : CvBoostParams |
| 11 | { | 72 | { |
| 12 | float minHitRate; | 73 | float minHitRate; |
openbr/core/cascade.cpp deleted
| 1 | -#include "cascade.h" | ||
| 2 | -#include <stdio.h> | ||
| 3 | -#include <iostream> | ||
| 4 | -#include <fstream> | ||
| 5 | - | ||
| 6 | -using namespace std; | ||
| 7 | -using namespace br; | ||
| 8 | -using namespace cv; | ||
| 9 | - | ||
| 10 | -bool CascadeImageReader::create(const QList<Mat> &_posImages, const QList<Mat> &_negImages, Size _winSize) | ||
| 11 | -{ | ||
| 12 | - posImages = _posImages; | ||
| 13 | - negImages = _negImages; | ||
| 14 | - winSize = _winSize; | ||
| 15 | - | ||
| 16 | - posIdx = negIdx = 0; | ||
| 17 | - | ||
| 18 | - src.create( 0, 0 , CV_8UC1 ); | ||
| 19 | - img.create( 0, 0, CV_8UC1 ); | ||
| 20 | - point = offset = Point( 0, 0 ); | ||
| 21 | - scale = 1.0F; | ||
| 22 | - scaleFactor = 1.4142135623730950488016887242097F; | ||
| 23 | - stepFactor = 0.5F; | ||
| 24 | - round = 0; | ||
| 25 | - | ||
| 26 | - return true; | ||
| 27 | -} | ||
| 28 | - | ||
| 29 | -bool CascadeImageReader::nextNeg() | ||
| 30 | -{ | ||
| 31 | - Point _offset = Point(0,0); | ||
| 32 | - size_t count = negImages.size(); | ||
| 33 | - for (size_t i = 0; i < count; i++) { | ||
| 34 | - src = negImages[negIdx++]; | ||
| 35 | - if( src.empty() ) | ||
| 36 | - continue; | ||
| 37 | - round += negIdx / count; | ||
| 38 | - round = round % (winSize.width * winSize.height); | ||
| 39 | - negIdx %= count; | ||
| 40 | - | ||
| 41 | - _offset.x = std::min( (int)round % winSize.width, src.cols - winSize.width ); | ||
| 42 | - _offset.y = std::min( (int)round / winSize.width, src.rows - winSize.height ); | ||
| 43 | - if( !src.empty() && src.type() == CV_8UC1 && _offset.x >= 0 && _offset.y >= 0 ) | ||
| 44 | - break; | ||
| 45 | - } | ||
| 46 | - | ||
| 47 | - if( src.empty() ) | ||
| 48 | - return false; // no appropriate image | ||
| 49 | - point = offset = _offset; | ||
| 50 | - scale = max( ((float)winSize.width + point.x) / ((float)src.cols), | ||
| 51 | - ((float)winSize.height + point.y) / ((float)src.rows) ); | ||
| 52 | - | ||
| 53 | - Size sz( (int)(scale*src.cols + 0.5F), (int)(scale*src.rows + 0.5F) ); | ||
| 54 | - resize( src, img, sz ); | ||
| 55 | - return true; | ||
| 56 | -} | ||
| 57 | - | ||
| 58 | -bool CascadeImageReader::getNeg( Mat& _img ) | ||
| 59 | -{ | ||
| 60 | - CV_Assert( !_img.empty() ); | ||
| 61 | - CV_Assert( _img.type() == CV_8UC1 ); | ||
| 62 | - CV_Assert( _img.cols == winSize.width ); | ||
| 63 | - CV_Assert( _img.rows == winSize.height ); | ||
| 64 | - | ||
| 65 | - if( img.empty() ) | ||
| 66 | - if ( !nextNeg() ) | ||
| 67 | - return false; | ||
| 68 | - | ||
| 69 | - Mat mat( winSize.height, winSize.width, CV_8UC1, | ||
| 70 | - (void*)(img.data + point.y * img.step + point.x * img.elemSize()), img.step ); | ||
| 71 | - mat.copyTo(_img); | ||
| 72 | - | ||
| 73 | - if( (int)( point.x + (1.0F + stepFactor ) * winSize.width ) < img.cols ) | ||
| 74 | - point.x += (int)(stepFactor * winSize.width); | ||
| 75 | - else | ||
| 76 | - { | ||
| 77 | - point.x = offset.x; | ||
| 78 | - if( (int)( point.y + (1.0F + stepFactor ) * winSize.height ) < img.rows ) | ||
| 79 | - point.y += (int)(stepFactor * winSize.height); | ||
| 80 | - else | ||
| 81 | - { | ||
| 82 | - point.y = offset.y; | ||
| 83 | - scale *= scaleFactor; | ||
| 84 | - if( scale <= 1.0F ) | ||
| 85 | - resize( src, img, Size( (int)(scale*src.cols), (int)(scale*src.rows) ) ); | ||
| 86 | - else | ||
| 87 | - { | ||
| 88 | - if ( !nextNeg() ) | ||
| 89 | - return false; | ||
| 90 | - } | ||
| 91 | - } | ||
| 92 | - } | ||
| 93 | - return true; | ||
| 94 | -} | ||
| 95 | - | ||
| 96 | - | ||
| 97 | -bool CascadeImageReader::getPos(Mat &_img) | ||
| 98 | -{ | ||
| 99 | - posImages[posIdx++].copyTo(_img); | ||
| 100 | - return true; | ||
| 101 | -} | ||
| 102 | - | ||
| 103 | -//---------------------------- CascadeClassifier -------------------------------------- | ||
| 104 | - | ||
| 105 | -bool BrCascadeClassifier::train(const string _cascadeDirName, | ||
| 106 | - const QList<Mat> &_posImages, | ||
| 107 | - const QList<Mat> &_negImages, | ||
| 108 | - int _numPos, int _numNeg, | ||
| 109 | - int _precalcValBufSize, int _precalcIdxBufSize, | ||
| 110 | - int _numStages, | ||
| 111 | - Size _winSize, | ||
| 112 | - const CascadeBoostParams& _stageParams) | ||
| 113 | -{ | ||
| 114 | - // Start recording clock ticks for training time output | ||
| 115 | - const clock_t begin_time = clock(); | ||
| 116 | - | ||
| 117 | - if (_cascadeDirName.empty()) | ||
| 118 | - CV_Error( CV_StsBadArg, "_cascadeDirName is NULL" ); | ||
| 119 | - | ||
| 120 | - string dirName; | ||
| 121 | - if (_cascadeDirName.find_last_of("/\\") == (_cascadeDirName.length() - 1) ) | ||
| 122 | - dirName = _cascadeDirName; | ||
| 123 | - else | ||
| 124 | - dirName = _cascadeDirName + '/'; | ||
| 125 | - | ||
| 126 | - winSize = _winSize; | ||
| 127 | - | ||
| 128 | - numPos = _numPos; | ||
| 129 | - numNeg = _numNeg; | ||
| 130 | - numStages = _numStages; | ||
| 131 | - imgReader.create(_posImages, _negImages, winSize); | ||
| 132 | - | ||
| 133 | - Representation *representation = Representation::make("MBLBP(24,24)", NULL); | ||
| 134 | - | ||
| 135 | - stageParams = new CascadeBoostParams; | ||
| 136 | - *stageParams = _stageParams; | ||
| 137 | - featureEvaluator = new FeatureEvaluator; | ||
| 138 | - featureEvaluator->init(representation, numPos + numNeg); | ||
| 139 | - stageClassifiers.reserve( numStages ); | ||
| 140 | - | ||
| 141 | - double requiredLeafFARate = pow( (double) stageParams->maxFalseAlarm, (double) numStages ) / | ||
| 142 | - (double)stageParams->max_depth; | ||
| 143 | - double tempLeafFARate; | ||
| 144 | - | ||
| 145 | - for (int i = 0; i < numStages; i++) { | ||
| 146 | - cout << endl << "===== TRAINING " << i << "-stage =====" << endl; | ||
| 147 | - cout << "<BEGIN" << endl; | ||
| 148 | - if (!updateTrainingSet(tempLeafFARate)) { | ||
| 149 | - cout << "Train dataset for temp stage can not be filled. " | ||
| 150 | - "Branch training terminated." << endl; | ||
| 151 | - break; | ||
| 152 | - } | ||
| 153 | - if (tempLeafFARate <= requiredLeafFARate) { | ||
| 154 | - cout << "Required leaf false alarm rate achieved. " | ||
| 155 | - "Branch training terminated." << endl; | ||
| 156 | - break; | ||
| 157 | - } | ||
| 158 | - | ||
| 159 | - CascadeBoost* tempStage = new CascadeBoost; | ||
| 160 | - bool isStageTrained = tempStage->train( (FeatureEvaluator*)featureEvaluator, | ||
| 161 | - curNumSamples, _precalcValBufSize, _precalcIdxBufSize, | ||
| 162 | - *((CascadeBoostParams*)stageParams) ); | ||
| 163 | - cout << "END>" << endl; | ||
| 164 | - | ||
| 165 | - if (!isStageTrained) | ||
| 166 | - break; | ||
| 167 | - | ||
| 168 | - stageClassifiers.push_back(tempStage); | ||
| 169 | - | ||
| 170 | - // Output training time up till now | ||
| 171 | - float seconds = float( clock () - begin_time ) / CLOCKS_PER_SEC; | ||
| 172 | - int days = int(seconds) / 60 / 60 / 24; | ||
| 173 | - int hours = (int(seconds) / 60 / 60) % 24; | ||
| 174 | - int minutes = (int(seconds) / 60) % 60; | ||
| 175 | - int seconds_left = int(seconds) % 60; | ||
| 176 | - cout << "Training until now has taken " << days << " days " << hours << " hours " << minutes << " minutes " << seconds_left <<" seconds." << endl; | ||
| 177 | - } | ||
| 178 | - | ||
| 179 | - if (stageClassifiers.size() == 0) { | ||
| 180 | - cout << "Cascade classifier can't be trained. Check the used training parameters." << endl; | ||
| 181 | - return false; | ||
| 182 | - } | ||
| 183 | - | ||
| 184 | - save(dirName + CC_CASCADE_FILENAME); | ||
| 185 | - | ||
| 186 | - return true; | ||
| 187 | -} | ||
| 188 | - | ||
| 189 | -int BrCascadeClassifier::predict( int sampleIdx ) | ||
| 190 | -{ | ||
| 191 | - CV_DbgAssert( sampleIdx < numPos + numNeg ); | ||
| 192 | - for (vector< Ptr<CascadeBoost> >::iterator it = stageClassifiers.begin(); | ||
| 193 | - it != stageClassifiers.end(); it++ ) | ||
| 194 | - { | ||
| 195 | - if ( (*it)->predict( sampleIdx ) == 0.f ) | ||
| 196 | - return 0; | ||
| 197 | - } | ||
| 198 | - return 1; | ||
| 199 | -} | ||
| 200 | - | ||
| 201 | -bool BrCascadeClassifier::updateTrainingSet( double& acceptanceRatio) | ||
| 202 | -{ | ||
| 203 | - int64 posConsumed = 0, negConsumed = 0; | ||
| 204 | - imgReader.restart(); | ||
| 205 | - | ||
| 206 | - int posCount = fillPassedSamples( 0, numPos, true, posConsumed ); | ||
| 207 | - if( !posCount ) | ||
| 208 | - return false; | ||
| 209 | - cout << "POS count : consumed " << posCount << " : " << (int)posConsumed << endl; | ||
| 210 | - | ||
| 211 | - int proNumNeg = cvRound( ( ((double)numNeg) * ((double)posCount) ) / numPos ); // apply only a fraction of negative samples. double is required since overflow is possible | ||
| 212 | - int negCount = fillPassedSamples( posCount, proNumNeg, false, negConsumed ); | ||
| 213 | - if ( !negCount ) | ||
| 214 | - return false; | ||
| 215 | - | ||
| 216 | - curNumSamples = posCount + negCount; | ||
| 217 | - acceptanceRatio = negConsumed == 0 ? 0 : ( (double)negCount/(double)(int64)negConsumed ); | ||
| 218 | - cout << "NEG count : acceptanceRatio " << negCount << " : " << acceptanceRatio << endl; | ||
| 219 | - return true; | ||
| 220 | -} | ||
| 221 | - | ||
| 222 | -int BrCascadeClassifier::fillPassedSamples( int first, int count, bool isPositive, int64& consumed ) | ||
| 223 | -{ | ||
| 224 | - int getcount = 0; | ||
| 225 | - Mat img(winSize, CV_8UC1); | ||
| 226 | - for( int i = first; i < first + count; i++ ) | ||
| 227 | - { | ||
| 228 | - for( ; ; ) | ||
| 229 | - { | ||
| 230 | - bool isGetImg = isPositive ? imgReader.getPos( img ) : | ||
| 231 | - imgReader.getNeg( img ); | ||
| 232 | - if( !isGetImg ) | ||
| 233 | - return getcount; | ||
| 234 | - consumed++; | ||
| 235 | - | ||
| 236 | - featureEvaluator->setImage( img, isPositive ? 1 : 0, i ); | ||
| 237 | - if( predict( i ) == 1.0F ) | ||
| 238 | - { | ||
| 239 | - getcount++; | ||
| 240 | - printf("%s current samples: %d\r", isPositive ? "POS":"NEG", getcount); | ||
| 241 | - break; | ||
| 242 | - } | ||
| 243 | - } | ||
| 244 | - } | ||
| 245 | - return getcount; | ||
| 246 | -} | ||
| 247 | - | ||
| 248 | -void BrCascadeClassifier::writeParams( FileStorage &fs ) const | ||
| 249 | -{ | ||
| 250 | - fs << CC_STAGE_TYPE << CC_BOOST; | ||
| 251 | - fs << CC_FEATURE_TYPE << CC_LBP; | ||
| 252 | - fs << CC_HEIGHT << winSize.height; | ||
| 253 | - fs << CC_WIDTH << winSize.width; | ||
| 254 | - | ||
| 255 | - fs << CC_STAGE_PARAMS << "{"; stageParams->write( fs ); fs << "}"; | ||
| 256 | - | ||
| 257 | - fs << CC_FEATURE_PARAMS << "{"; | ||
| 258 | - fs << CC_MAX_CAT_COUNT << featureEvaluator->getMaxCatCount(); | ||
| 259 | - fs << CC_FEATURE_SIZE << featureEvaluator->getFeatureSize(); | ||
| 260 | - fs << "}"; | ||
| 261 | -} | ||
| 262 | - | ||
| 263 | -void BrCascadeClassifier::writeFeatures( FileStorage &fs, const Mat& featureMap ) const | ||
| 264 | -{ | ||
| 265 | - ((FeatureEvaluator*)((Ptr<FeatureEvaluator>)featureEvaluator))->writeFeatures( fs, featureMap ); | ||
| 266 | -} | ||
| 267 | - | ||
| 268 | -void BrCascadeClassifier::writeStages( FileStorage &fs, const Mat& featureMap ) const | ||
| 269 | -{ | ||
| 270 | - char cmnt[30]; | ||
| 271 | - int i = 0; | ||
| 272 | - fs << CC_STAGES << "["; | ||
| 273 | - for( vector< Ptr<CascadeBoost> >::const_iterator it = stageClassifiers.begin(); | ||
| 274 | - it != stageClassifiers.end(); it++, i++ ) | ||
| 275 | - { | ||
| 276 | - sprintf( cmnt, "stage %d", i ); | ||
| 277 | - cvWriteComment( fs.fs, cmnt, 0 ); | ||
| 278 | - fs << "{"; | ||
| 279 | - ((CascadeBoost*)((Ptr<CascadeBoost>)*it))->write( fs, featureMap ); | ||
| 280 | - fs << "}"; | ||
| 281 | - } | ||
| 282 | - fs << "]"; | ||
| 283 | -} | ||
| 284 | - | ||
| 285 | -void BrCascadeClassifier::save(const string filename) | ||
| 286 | -{ | ||
| 287 | - FileStorage fs( filename, FileStorage::WRITE ); | ||
| 288 | - | ||
| 289 | - if ( !fs.isOpened() ) | ||
| 290 | - return; | ||
| 291 | - | ||
| 292 | - fs << FileStorage::getDefaultObjectName(filename) << "{"; | ||
| 293 | - | ||
| 294 | - Mat featureMap; | ||
| 295 | - getUsedFeaturesIdxMap( featureMap ); | ||
| 296 | - writeParams( fs ); | ||
| 297 | - fs << CC_STAGE_NUM << (int)stageClassifiers.size(); | ||
| 298 | - writeStages( fs, featureMap ); | ||
| 299 | - writeFeatures( fs, featureMap ); | ||
| 300 | - | ||
| 301 | - fs << "}"; | ||
| 302 | -} | ||
| 303 | - | ||
| 304 | -void BrCascadeClassifier::getUsedFeaturesIdxMap( Mat& featureMap ) | ||
| 305 | -{ | ||
| 306 | - int varCount = featureEvaluator->getNumFeatures() * featureEvaluator->getFeatureSize(); | ||
| 307 | - featureMap.create( 1, varCount, CV_32SC1 ); | ||
| 308 | - featureMap.setTo(Scalar(-1)); | ||
| 309 | - | ||
| 310 | - for( vector< Ptr<CascadeBoost> >::const_iterator it = stageClassifiers.begin(); | ||
| 311 | - it != stageClassifiers.end(); it++ ) | ||
| 312 | - ((CascadeBoost*)((Ptr<CascadeBoost>)(*it)))->markUsedFeaturesInMap( featureMap ); | ||
| 313 | - | ||
| 314 | - for( int fi = 0, idx = 0; fi < varCount; fi++ ) | ||
| 315 | - if ( featureMap.at<int>(0, fi) >= 0 ) | ||
| 316 | - featureMap.ptr<int>(0)[fi] = idx++; | ||
| 317 | -} | ||
| 318 | - |
openbr/core/cascade.h deleted
| 1 | -#ifndef CASCADE_H | ||
| 2 | -#define CASCADE_H | ||
| 3 | - | ||
| 4 | -#include <openbr/openbr_plugin.h> | ||
| 5 | -#include <opencv2/highgui/highgui.hpp> | ||
| 6 | -#include "features.h" | ||
| 7 | -#include "boost.h" | ||
| 8 | - | ||
| 9 | -namespace br | ||
| 10 | -{ | ||
| 11 | - | ||
| 12 | -class CascadeImageReader | ||
| 13 | -{ | ||
| 14 | -public: | ||
| 15 | - bool create( const QList<cv::Mat> &_posImages, const QList<cv::Mat> &_negImages, cv::Size _winSize ); | ||
| 16 | - void restart() { posIdx = 0; } | ||
| 17 | - bool getNeg(cv::Mat &_img); | ||
| 18 | - bool getPos(cv::Mat &_img); | ||
| 19 | - | ||
| 20 | - QList<cv::Mat> posImages, negImages; | ||
| 21 | - | ||
| 22 | - int posIdx, negIdx; | ||
| 23 | - | ||
| 24 | - cv::Mat src, img; | ||
| 25 | - cv::Point offset, point; | ||
| 26 | - float scale; | ||
| 27 | - float scaleFactor; | ||
| 28 | - float stepFactor; | ||
| 29 | - size_t round; | ||
| 30 | - cv::Size winSize; | ||
| 31 | - | ||
| 32 | -private: | ||
| 33 | - bool nextNeg(); | ||
| 34 | -}; | ||
| 35 | - | ||
| 36 | - | ||
| 37 | -class BrCascadeClassifier | ||
| 38 | -{ | ||
| 39 | -public: | ||
| 40 | - bool train(const std::string _cascadeDirName, | ||
| 41 | - const QList<cv::Mat> &_posImages, | ||
| 42 | - const QList<cv::Mat> &_negImages, | ||
| 43 | - int _numPos, int _numNeg, | ||
| 44 | - int _precalcValBufSize, int _precalcIdxBufSize, | ||
| 45 | - int _numStages, | ||
| 46 | - cv::Size _winSize, | ||
| 47 | - const CascadeBoostParams& _stageParams); | ||
| 48 | -private: | ||
| 49 | - int predict(int sampleIdx); | ||
| 50 | - void save(const std::string cascadeDirName); | ||
| 51 | - bool updateTrainingSet(double& acceptanceRatio); | ||
| 52 | - int fillPassedSamples(int first, int count, bool isPositive, int64& consumed); | ||
| 53 | - | ||
| 54 | - void writeParams(cv::FileStorage &fs) const; | ||
| 55 | - void writeStages(cv::FileStorage &fs, const cv::Mat& featureMap) const; | ||
| 56 | - void writeFeatures(cv::FileStorage &fs, const cv::Mat& featureMap) const; | ||
| 57 | - | ||
| 58 | - void getUsedFeaturesIdxMap(cv::Mat& featureMap); | ||
| 59 | - | ||
| 60 | - cv::Ptr<CascadeBoostParams> stageParams; | ||
| 61 | - | ||
| 62 | - cv::Ptr<FeatureEvaluator> featureEvaluator; | ||
| 63 | - std::vector< cv::Ptr<CascadeBoost> > stageClassifiers; | ||
| 64 | - CascadeImageReader imgReader; | ||
| 65 | - int numStages, curNumSamples; | ||
| 66 | - int numPos, numNeg; | ||
| 67 | - cv::Size winSize; | ||
| 68 | -}; | ||
| 69 | - | ||
| 70 | -} // namespace br | ||
| 71 | - | ||
| 72 | -#endif // CASCADE_H |
openbr/core/features.cpp deleted
| 1 | -#include "features.h" | ||
| 2 | - | ||
| 3 | -using namespace cv; | ||
| 4 | -using namespace br; | ||
| 5 | - | ||
| 6 | -//------------------------------------- FeatureEvaluator --------------------------------------- | ||
| 7 | - | ||
| 8 | -void FeatureEvaluator::init(Representation *_representation, int _maxSampleCount) | ||
| 9 | -{ | ||
| 10 | - representation = _representation; | ||
| 11 | - data.create((int)_maxSampleCount, representation->postWindowSize().area(), CV_32SC1); | ||
| 12 | - cls.create( (int)_maxSampleCount, 1, CV_32FC1 ); | ||
| 13 | -} | ||
| 14 | - | ||
| 15 | -void FeatureEvaluator::setImage(const Mat &img, uchar clsLabel, int idx) | ||
| 16 | -{ | ||
| 17 | - cls.ptr<float>(idx)[0] = clsLabel; | ||
| 18 | - | ||
| 19 | - Mat integralImg(representation->postWindowSize(), data.type(), data.ptr<int>(idx)); | ||
| 20 | - representation->preprocess(img, integralImg); | ||
| 21 | -} | ||
| 22 | - | ||
| 23 | -void FeatureEvaluator::writeFeatures(FileStorage &fs, const Mat &featureMap) const | ||
| 24 | -{ | ||
| 25 | - representation->write(fs, featureMap); | ||
| 26 | -} |
openbr/core/features.h deleted
| 1 | -#ifndef FEATURE_H | ||
| 2 | -#define FEATURE_H | ||
| 3 | - | ||
| 4 | -#include <openbr/openbr_plugin.h> | ||
| 5 | -#include "opencv2/imgproc/imgproc.hpp" | ||
| 6 | -#include <iostream> | ||
| 7 | - | ||
| 8 | -#define CC_CASCADE_FILENAME "cascade.xml" | ||
| 9 | -#define CC_PARAMS_FILENAME "params.xml" | ||
| 10 | - | ||
| 11 | -#define CC_CASCADE_PARAMS "cascadeParams" | ||
| 12 | -#define CC_STAGE_TYPE "stageType" | ||
| 13 | -#define CC_FEATURE_TYPE "featureType" | ||
| 14 | -#define CC_HEIGHT "height" | ||
| 15 | -#define CC_WIDTH "width" | ||
| 16 | - | ||
| 17 | -#define CC_STAGE_NUM "stageNum" | ||
| 18 | -#define CC_STAGES "stages" | ||
| 19 | -#define CC_STAGE_PARAMS "stageParams" | ||
| 20 | - | ||
| 21 | -#define CC_BOOST "BOOST" | ||
| 22 | -#define CC_BOOST_TYPE "boostType" | ||
| 23 | -#define CC_DISCRETE_BOOST "DAB" | ||
| 24 | -#define CC_REAL_BOOST "RAB" | ||
| 25 | -#define CC_LOGIT_BOOST "LB" | ||
| 26 | -#define CC_GENTLE_BOOST "GAB" | ||
| 27 | -#define CC_MINHITRATE "minHitRate" | ||
| 28 | -#define CC_MAXFALSEALARM "maxFalseAlarm" | ||
| 29 | -#define CC_TRIM_RATE "weightTrimRate" | ||
| 30 | -#define CC_MAX_DEPTH "maxDeptrh" | ||
| 31 | -#define CC_WEAK_COUNT "maxWeakCount" | ||
| 32 | -#define CC_STAGE_THRESHOLD "stageThreshold" | ||
| 33 | -#define CC_WEAK_CLASSIFIERS "weakClassifiers" | ||
| 34 | -#define CC_INTERNAL_NODES "internalNodes" | ||
| 35 | -#define CC_LEAF_VALUES "leafValues" | ||
| 36 | - | ||
| 37 | -#define CC_FEATURES "features" | ||
| 38 | -#define CC_FEATURE_PARAMS "featureParams" | ||
| 39 | -#define CC_MAX_CAT_COUNT "maxCatCount" | ||
| 40 | -#define CC_FEATURE_SIZE "featSize" | ||
| 41 | - | ||
| 42 | -#define CC_LBP "LBP" | ||
| 43 | -#define CC_RECT "rect" | ||
| 44 | - | ||
| 45 | -#ifdef _WIN32 | ||
| 46 | -#define TIME( arg ) (((double) clock()) / CLOCKS_PER_SEC) | ||
| 47 | -#else | ||
| 48 | -#define TIME( arg ) (time( arg )) | ||
| 49 | -#endif | ||
| 50 | - | ||
| 51 | -namespace br | ||
| 52 | -{ | ||
| 53 | - | ||
| 54 | -class FeatureEvaluator | ||
| 55 | -{ | ||
| 56 | -public: | ||
| 57 | - ~FeatureEvaluator() {} | ||
| 58 | - void init(Representation *_representation, int _maxSampleCount); | ||
| 59 | - void setImage(const cv::Mat& img, uchar clsLabel, int idx); | ||
| 60 | - void writeFeatures(cv::FileStorage &fs, const cv::Mat& featureMap) const; | ||
| 61 | - float operator()(int featureIdx, int sampleIdx) const { return representation->evaluate(data.row(sampleIdx), featureIdx); } | ||
| 62 | - | ||
| 63 | - int getNumFeatures() const { return representation->numFeatures(); } | ||
| 64 | - int getMaxCatCount() const { return representation->maxCatCount(); } | ||
| 65 | - int getFeatureSize() const { return 1; } | ||
| 66 | - const cv::Mat& getCls() const { return cls; } | ||
| 67 | - float getCls(int si) const { return cls.at<float>(si, 0); } | ||
| 68 | - | ||
| 69 | - cv::Mat data, cls; | ||
| 70 | - Representation *representation; | ||
| 71 | -}; | ||
| 72 | - | ||
| 73 | -} // namespace br | ||
| 74 | - | ||
| 75 | -#endif // FEATURE_H |
openbr/openbr_plugin.h
| @@ -1395,11 +1395,6 @@ class BR_EXPORT Representation : public Object | @@ -1395,11 +1395,6 @@ class BR_EXPORT Representation : public Object | ||
| 1395 | { | 1395 | { |
| 1396 | Q_OBJECT | 1396 | Q_OBJECT |
| 1397 | 1397 | ||
| 1398 | - Q_PROPERTY(int winWidth READ get_winWidth WRITE set_winWidth RESET reset_winWidth STORED false) | ||
| 1399 | - Q_PROPERTY(int winHeight READ get_winHeight WRITE set_winHeight RESET reset_winHeight STORED false) | ||
| 1400 | - BR_PROPERTY(int, winWidth, 24) | ||
| 1401 | - BR_PROPERTY(int, winHeight, 24) | ||
| 1402 | - | ||
| 1403 | public: | 1398 | public: |
| 1404 | virtual ~Representation() {} | 1399 | virtual ~Representation() {} |
| 1405 | 1400 |
openbr/plugins/classification/boostedforest.cpp
openbr/plugins/classification/cascade.cpp
| 1 | +#include <opencv2/imgproc/imgproc.hpp> | ||
| 2 | + | ||
| 1 | #include <openbr/plugins/openbr_internal.h> | 3 | #include <openbr/plugins/openbr_internal.h> |
| 2 | -#include <openbr/core/features.h> | ||
| 3 | #include <openbr/core/boost.h> | 4 | #include <openbr/core/boost.h> |
| 4 | 5 | ||
| 5 | using namespace cv; | 6 | using namespace cv; |
| @@ -9,7 +10,7 @@ namespace br | @@ -9,7 +10,7 @@ namespace br | ||
| 9 | 10 | ||
| 10 | struct ImageHandler | 11 | struct ImageHandler |
| 11 | { | 12 | { |
| 12 | - bool create( const QList<cv::Mat> &_posImages, const QList<cv::Mat> &_negImages, cv::Size _winSize ) | 13 | + bool create(const QList<Mat> &_posImages, const QList<Mat> &_negImages, Size _winSize) |
| 13 | { | 14 | { |
| 14 | posImages = _posImages; | 15 | posImages = _posImages; |
| 15 | negImages = _negImages; | 16 | negImages = _negImages; |
| @@ -30,72 +31,57 @@ struct ImageHandler | @@ -30,72 +31,57 @@ struct ImageHandler | ||
| 30 | 31 | ||
| 31 | void restart() { posIdx = 0; } | 32 | void restart() { posIdx = 0; } |
| 32 | 33 | ||
| 33 | - int numPos() const { return posImages.size(); } | ||
| 34 | - int numNeg() const { return negImages.size(); } | ||
| 35 | - | ||
| 36 | - bool nextNeg() | 34 | + void nextNeg() |
| 37 | { | 35 | { |
| 38 | - Point _offset = Point(0,0); | ||
| 39 | - size_t count = negImages.size(); | ||
| 40 | - for (size_t i = 0; i < count; i++) { | 36 | + int count = negImages.size(); |
| 37 | + for (int i = 0; i < count; i++) { | ||
| 41 | src = negImages[negIdx++]; | 38 | src = negImages[negIdx++]; |
| 42 | - if( src.empty() ) | ||
| 43 | - continue; | 39 | + |
| 44 | round += negIdx / count; | 40 | round += negIdx / count; |
| 45 | round = round % (winSize.width * winSize.height); | 41 | round = round % (winSize.width * winSize.height); |
| 46 | negIdx %= count; | 42 | negIdx %= count; |
| 47 | 43 | ||
| 48 | - _offset.x = std::min( (int)round % winSize.width, src.cols - winSize.width ); | ||
| 49 | - _offset.y = std::min( (int)round / winSize.width, src.rows - winSize.height ); | ||
| 50 | - if( !src.empty() && src.type() == CV_8UC1 && _offset.x >= 0 && _offset.y >= 0 ) | 44 | + offset.x = qMin( (int)round % winSize.width, src.cols - winSize.width ); |
| 45 | + offset.y = qMin( (int)round / winSize.width, src.rows - winSize.height ); | ||
| 46 | + if (!src.empty() && src.type() == CV_8UC1 && offset.x >= 0 && offset.y >= 0) | ||
| 51 | break; | 47 | break; |
| 52 | } | 48 | } |
| 53 | 49 | ||
| 54 | - if( src.empty() ) | ||
| 55 | - return false; // no appropriate image | ||
| 56 | - point = offset = _offset; | ||
| 57 | - scale = max( ((float)winSize.width + point.x) / ((float)src.cols), | ||
| 58 | - ((float)winSize.height + point.y) / ((float)src.rows) ); | 50 | + point = offset; |
| 51 | + scale = max(((float)winSize.width + point.x) / ((float)src.cols), | ||
| 52 | + ((float)winSize.height + point.y) / ((float)src.rows)); | ||
| 59 | 53 | ||
| 60 | - Size sz( (int)(scale*src.cols + 0.5F), (int)(scale*src.rows + 0.5F) ); | ||
| 61 | - resize( src, img, sz ); | ||
| 62 | - return true; | 54 | + Size sz((int)(scale*src.cols + 0.5F), (int)(scale*src.rows + 0.5F)); |
| 55 | + resize(src, img, sz); | ||
| 63 | } | 56 | } |
| 64 | 57 | ||
| 65 | - bool getNeg(cv::Mat &_img) | 58 | + bool getNeg(Mat &_img) |
| 66 | { | 59 | { |
| 67 | - if( img.empty() ) | ||
| 68 | - if ( !nextNeg() ) | ||
| 69 | - return false; | 60 | + if (img.empty()) |
| 61 | + nextNeg(); | ||
| 70 | 62 | ||
| 71 | - Mat mat( winSize.height, winSize.width, CV_8UC1, | ||
| 72 | - (void*)(img.data + point.y * img.step + point.x * img.elemSize()), img.step ); | ||
| 73 | - mat.copyTo(_img); | 63 | + Mat m(winSize.height, winSize.width, CV_8UC1, (void*)(img.data + point.y * img.step + point.x * img.elemSize()), img.step); |
| 64 | + m.copyTo(_img); | ||
| 74 | 65 | ||
| 75 | - if( (int)( point.x + (1.0F + stepFactor ) * winSize.width ) < img.cols ) | 66 | + if ((int)(point.x + (1.0F + stepFactor) * winSize.width) < img.cols) |
| 76 | point.x += (int)(stepFactor * winSize.width); | 67 | point.x += (int)(stepFactor * winSize.width); |
| 77 | - else | ||
| 78 | - { | 68 | + else { |
| 79 | point.x = offset.x; | 69 | point.x = offset.x; |
| 80 | - if( (int)( point.y + (1.0F + stepFactor ) * winSize.height ) < img.rows ) | 70 | + if ((int)( point.y + (1.0F + stepFactor ) * winSize.height ) < img.rows) |
| 81 | point.y += (int)(stepFactor * winSize.height); | 71 | point.y += (int)(stepFactor * winSize.height); |
| 82 | - else | ||
| 83 | - { | 72 | + else { |
| 84 | point.y = offset.y; | 73 | point.y = offset.y; |
| 85 | scale *= scaleFactor; | 74 | scale *= scaleFactor; |
| 86 | - if( scale <= 1.0F ) | ||
| 87 | - resize( src, img, Size( (int)(scale*src.cols), (int)(scale*src.rows) ) ); | 75 | + if (scale <= 1.0F) |
| 76 | + resize(src, img, Size((int)(scale*src.cols), (int)(scale*src.rows))); | ||
| 88 | else | 77 | else |
| 89 | - { | ||
| 90 | - if ( !nextNeg() ) | ||
| 91 | - return false; | ||
| 92 | - } | 78 | + nextNeg(); |
| 93 | } | 79 | } |
| 94 | } | 80 | } |
| 95 | return true; | 81 | return true; |
| 96 | } | 82 | } |
| 97 | 83 | ||
| 98 | - bool getPos(cv::Mat &_img) | 84 | + bool getPos(Mat &_img) |
| 99 | { | 85 | { |
| 100 | if (posIdx >= posImages.size()) | 86 | if (posIdx >= posImages.size()) |
| 101 | return false; | 87 | return false; |
| @@ -104,20 +90,20 @@ struct ImageHandler | @@ -104,20 +90,20 @@ struct ImageHandler | ||
| 104 | return true; | 90 | return true; |
| 105 | } | 91 | } |
| 106 | 92 | ||
| 107 | - QList<cv::Mat> posImages, negImages; | 93 | + QList<Mat> posImages, negImages; |
| 108 | 94 | ||
| 109 | int posIdx, negIdx; | 95 | int posIdx, negIdx; |
| 110 | 96 | ||
| 111 | - cv::Mat src, img; | ||
| 112 | - cv::Point offset, point; | 97 | + Mat src, img; |
| 98 | + Point offset, point; | ||
| 113 | float scale; | 99 | float scale; |
| 114 | float scaleFactor; | 100 | float scaleFactor; |
| 115 | float stepFactor; | 101 | float stepFactor; |
| 116 | size_t round; | 102 | size_t round; |
| 117 | - cv::Size winSize; | 103 | + Size winSize; |
| 118 | }; | 104 | }; |
| 119 | 105 | ||
| 120 | -class _CascadeClassifier : public Classifier | 106 | +class CascadeClassifier : public Classifier |
| 121 | { | 107 | { |
| 122 | Q_OBJECT | 108 | Q_OBJECT |
| 123 | 109 | ||
| @@ -242,6 +228,7 @@ private: | @@ -242,6 +228,7 @@ private: | ||
| 242 | qFatal("Cannot get another positive sample!"); | 228 | qFatal("Cannot get another positive sample!"); |
| 243 | 229 | ||
| 244 | if (classify(pos) == 1.0f) { | 230 | if (classify(pos) == 1.0f) { |
| 231 | + printf("POS current samples: %d\r", images.size()); | ||
| 245 | images.append(pos); | 232 | images.append(pos); |
| 246 | labels.append(1.0f); | 233 | labels.append(1.0f); |
| 247 | } | 234 | } |
| @@ -257,6 +244,7 @@ private: | @@ -257,6 +244,7 @@ private: | ||
| 257 | qFatal("Cannot get another negative sample!"); | 244 | qFatal("Cannot get another negative sample!"); |
| 258 | 245 | ||
| 259 | if (classify(neg) == 1.0f) { | 246 | if (classify(neg) == 1.0f) { |
| 247 | + printf("NEG current samples: %d\r", images.size() - posCount); | ||
| 260 | images.append(neg); | 248 | images.append(neg); |
| 261 | labels.append(0.0f); | 249 | labels.append(0.0f); |
| 262 | } | 250 | } |
| @@ -269,7 +257,7 @@ private: | @@ -269,7 +257,7 @@ private: | ||
| 269 | } | 257 | } |
| 270 | }; | 258 | }; |
| 271 | 259 | ||
| 272 | -BR_REGISTER(Classifier, _CascadeClassifier) | 260 | +BR_REGISTER(Classifier, CascadeClassifier) |
| 273 | 261 | ||
| 274 | } // namespace br | 262 | } // namespace br |
| 275 | 263 |
openbr/plugins/metadata/cascade.cpp
| @@ -22,7 +22,6 @@ | @@ -22,7 +22,6 @@ | ||
| 22 | #include <openbr/core/opencvutils.h> | 22 | #include <openbr/core/opencvutils.h> |
| 23 | #include <openbr/core/resource.h> | 23 | #include <openbr/core/resource.h> |
| 24 | #include <openbr/core/qtutils.h> | 24 | #include <openbr/core/qtutils.h> |
| 25 | -#include <openbr/core/cascade.h> | ||
| 26 | 25 | ||
| 27 | using namespace cv; | 26 | using namespace cv; |
| 28 | 27 | ||
| @@ -65,34 +64,19 @@ private: | @@ -65,34 +64,19 @@ private: | ||
| 65 | * \author Josh Klontz \cite jklontz | 64 | * \author Josh Klontz \cite jklontz |
| 66 | * \author David Crouse \cite dgcrouse | 65 | * \author David Crouse \cite dgcrouse |
| 67 | */ | 66 | */ |
| 68 | -class CascadeTransform : public MetaTransform | 67 | +class CascadeTransform : public UntrainableMetaTransform |
| 69 | { | 68 | { |
| 70 | Q_OBJECT | 69 | Q_OBJECT |
| 71 | Q_PROPERTY(QString model READ get_model WRITE set_model RESET reset_model STORED false) | 70 | Q_PROPERTY(QString model READ get_model WRITE set_model RESET reset_model STORED false) |
| 72 | Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) | 71 | Q_PROPERTY(int minSize READ get_minSize WRITE set_minSize RESET reset_minSize STORED false) |
| 73 | Q_PROPERTY(int minNeighbors READ get_minNeighbors WRITE set_minNeighbors RESET reset_minNeighbors STORED false) | 72 | Q_PROPERTY(int minNeighbors READ get_minNeighbors WRITE set_minNeighbors RESET reset_minNeighbors STORED false) |
| 74 | Q_PROPERTY(bool ROCMode READ get_ROCMode WRITE set_ROCMode RESET reset_ROCMode STORED false) | 73 | Q_PROPERTY(bool ROCMode READ get_ROCMode WRITE set_ROCMode RESET reset_ROCMode STORED false) |
| 75 | - | ||
| 76 | - // Training parameters | ||
| 77 | - Q_PROPERTY(QString vecFile READ get_vecFile WRITE set_vecFile RESET reset_vecFile STORED false) | ||
| 78 | - Q_PROPERTY(QString negFile READ get_negFile WRITE set_negFile RESET reset_negFile STORED false) | ||
| 79 | - Q_PROPERTY(int winWidth READ get_winWidth WRITE set_winWidth RESET reset_winWidth STORED false) | ||
| 80 | - Q_PROPERTY(int winHeight READ get_winHeight WRITE set_winHeight RESET reset_winHeight STORED false) | ||
| 81 | - Q_PROPERTY(int numPos READ get_numPos WRITE set_numPos RESET reset_numPos STORED false) | ||
| 82 | - Q_PROPERTY(int numNeg READ get_numNeg WRITE set_numNeg RESET reset_numNeg STORED false) | ||
| 83 | 74 | ||
| 84 | BR_PROPERTY(QString, model, "FrontalFace") | 75 | BR_PROPERTY(QString, model, "FrontalFace") |
| 85 | BR_PROPERTY(int, minSize, 64) | 76 | BR_PROPERTY(int, minSize, 64) |
| 86 | BR_PROPERTY(int, minNeighbors, 5) | 77 | BR_PROPERTY(int, minNeighbors, 5) |
| 87 | BR_PROPERTY(bool, ROCMode, false) | 78 | BR_PROPERTY(bool, ROCMode, false) |
| 88 | 79 | ||
| 89 | - BR_PROPERTY(QString, vecFile, "data.vec") | ||
| 90 | - BR_PROPERTY(QString, negFile, "neg.txt") | ||
| 91 | - BR_PROPERTY(int, winWidth, 24) | ||
| 92 | - BR_PROPERTY(int, winHeight, 24) | ||
| 93 | - BR_PROPERTY(int, numPos, 1000) | ||
| 94 | - BR_PROPERTY(int, numNeg, 1000) | ||
| 95 | - | ||
| 96 | Resource<CascadeClassifier> cascadeResource; | 80 | Resource<CascadeClassifier> cascadeResource; |
| 97 | 81 | ||
| 98 | void init() | 82 | void init() |
| @@ -101,99 +85,6 @@ class CascadeTransform : public MetaTransform | @@ -101,99 +85,6 @@ class CascadeTransform : public MetaTransform | ||
| 101 | if (model == "Ear" || model == "Eye" || model == "FrontalFace" || model == "ProfileFace") | 85 | if (model == "Ear" || model == "Eye" || model == "FrontalFace" || model == "ProfileFace") |
| 102 | this->trainable = false; | 86 | this->trainable = false; |
| 103 | } | 87 | } |
| 104 | - | ||
| 105 | - QList<Mat> getPos() | ||
| 106 | - { | ||
| 107 | - FILE *file = fopen(vecFile.toStdString().c_str(), "rb"); | ||
| 108 | - if ( !file ) | ||
| 109 | - qFatal("Couldn't open the file"); | ||
| 110 | - | ||
| 111 | - short* vec = 0; | ||
| 112 | - int count, vecSize, last, base; | ||
| 113 | - | ||
| 114 | - short tmp = 0; | ||
| 115 | - if( fread( &count, sizeof( count ), 1, file ) != 1 || | ||
| 116 | - fread( &vecSize, sizeof( vecSize ), 1, file ) != 1 || | ||
| 117 | - fread( &tmp, sizeof( tmp ), 1, file ) != 1 || | ||
| 118 | - fread( &tmp, sizeof( tmp ), 1, file ) != 1 ) | ||
| 119 | - CV_Error_( CV_StsParseError, ("wrong file format for %s\n", qPrintable(vecFile)) ); | ||
| 120 | - base = sizeof( count ) + sizeof( vecSize ) + 2*sizeof( tmp ); | ||
| 121 | - | ||
| 122 | - last = 0; | ||
| 123 | - vec = (short*) cvAlloc( sizeof( *vec ) * vecSize ); | ||
| 124 | - CV_Assert( vec ); | ||
| 125 | - | ||
| 126 | - QList<Mat> posImages; | ||
| 127 | - for (int i = 0; i < 35770; i++) { | ||
| 128 | - Mat pos(winHeight, winWidth, CV_8UC1); | ||
| 129 | - | ||
| 130 | - CV_Assert( pos.rows * pos.cols == vecSize ); | ||
| 131 | - uchar tmp = 0; | ||
| 132 | - size_t elements_read = fread( &tmp, sizeof( tmp ), 1, file ); | ||
| 133 | - if( elements_read != 1 ) | ||
| 134 | - CV_Error( CV_StsBadArg, "Can not get new positive sample. The most possible reason is " | ||
| 135 | - "insufficient count of samples in given vec-file.\n"); | ||
| 136 | - elements_read = fread( vec, sizeof( vec[0] ), vecSize, file ); | ||
| 137 | - if( elements_read != (size_t)(vecSize) ) | ||
| 138 | - CV_Error( CV_StsBadArg, "Can not get new positive sample. Seems that vec-file has incorrect structure.\n"); | ||
| 139 | - | ||
| 140 | - if( feof( file ) || last++ >= count ) | ||
| 141 | - CV_Error( CV_StsBadArg, "Can not get new positive sample. vec-file is over.\n"); | ||
| 142 | - | ||
| 143 | - for( int r = 0; r < pos.rows; r++ ) | ||
| 144 | - for( int c = 0; c < pos.cols; c++ ) | ||
| 145 | - pos.ptr(r)[c] = (uchar)vec[r * pos.cols + c]; | ||
| 146 | - posImages.append(pos); | ||
| 147 | - } | ||
| 148 | - return posImages; | ||
| 149 | - } | ||
| 150 | - | ||
| 151 | - QList<Mat> getNeg() | ||
| 152 | - { | ||
| 153 | - QList<Mat> negs; | ||
| 154 | - | ||
| 155 | - std::string dirname, str; | ||
| 156 | - std::ifstream file(negFile.toStdString().c_str()); | ||
| 157 | - | ||
| 158 | - size_t pos = negFile.toStdString().rfind('\\'); | ||
| 159 | - char dlmrt = '\\'; | ||
| 160 | - if (pos == string::npos) | ||
| 161 | - { | ||
| 162 | - pos = negFile.toStdString().rfind('/'); | ||
| 163 | - dlmrt = '/'; | ||
| 164 | - } | ||
| 165 | - dirname = pos == string::npos ? "" : negFile.toStdString().substr(0, pos) + dlmrt; | ||
| 166 | - while( !file.eof() ) | ||
| 167 | - { | ||
| 168 | - std::getline(file, str); | ||
| 169 | - if (str.empty()) break; | ||
| 170 | - if (str.at(0) == '#' ) continue; | ||
| 171 | - negs.append(imread(dirname + str, CV_LOAD_IMAGE_GRAYSCALE)); | ||
| 172 | - } | ||
| 173 | - file.close(); | ||
| 174 | - | ||
| 175 | - return negs; | ||
| 176 | - } | ||
| 177 | - | ||
| 178 | - // Train transform | ||
| 179 | - void train(const TemplateList& data) | ||
| 180 | - { | ||
| 181 | - (void)data; | ||
| 182 | - | ||
| 183 | - BrCascadeClassifier classifier; | ||
| 184 | - | ||
| 185 | - QList<Mat> posImages = getPos(); | ||
| 186 | - QList<Mat> negImages = getNeg(); | ||
| 187 | - | ||
| 188 | - CascadeBoostParams stageParams(CvBoost::GENTLE, 0.999, 0.5, 0.95, 1, 200); | ||
| 189 | - | ||
| 190 | - QString cascadeDir = Globals->sdkPath + "/share/openbr/models/openbrcascades/" + model; | ||
| 191 | - classifier.train(cascadeDir.toStdString(), | ||
| 192 | - posImages, negImages, | ||
| 193 | - numPos, numNeg, 1024, 1024, 12, | ||
| 194 | - Size(winWidth, winHeight), | ||
| 195 | - stageParams); | ||
| 196 | - } | ||
| 197 | 88 | ||
| 198 | void project(const Template &src, Template &dst) const | 89 | void project(const Template &src, Template &dst) const |
| 199 | { | 90 | { |
openbr/plugins/representation/mblbp.cpp
| @@ -22,6 +22,11 @@ class MBLBPRepresentation : public Representation | @@ -22,6 +22,11 @@ class MBLBPRepresentation : public Representation | ||
| 22 | { | 22 | { |
| 23 | Q_OBJECT | 23 | Q_OBJECT |
| 24 | 24 | ||
| 25 | + Q_PROPERTY(int winWidth READ get_winWidth WRITE set_winWidth RESET reset_winWidth STORED false) | ||
| 26 | + Q_PROPERTY(int winHeight READ get_winHeight WRITE set_winHeight RESET reset_winHeight STORED false) | ||
| 27 | + BR_PROPERTY(int, winWidth, 24) | ||
| 28 | + BR_PROPERTY(int, winHeight, 24) | ||
| 29 | + | ||
| 25 | void init() | 30 | void init() |
| 26 | { | 31 | { |
| 27 | int offset = winWidth + 1; | 32 | int offset = winWidth + 1; |
| @@ -45,9 +50,11 @@ class MBLBPRepresentation : public Representation | @@ -45,9 +50,11 @@ class MBLBPRepresentation : public Representation | ||
| 45 | 50 | ||
| 46 | Mat evaluate(const Mat &image, const QList<int> &indices) const | 51 | Mat evaluate(const Mat &image, const QList<int> &indices) const |
| 47 | { | 52 | { |
| 48 | - Mat result(1, indices.size(), CV_32FC1); | ||
| 49 | - for (int i = 0; i < indices.size(); i++) | ||
| 50 | - result.at<float>(i) = (float)features[indices[i]].calc(image); | 53 | + int size = indices.empty() ? numFeatures() : indices.size(); |
| 54 | + | ||
| 55 | + Mat result(1, size, CV_32FC1); | ||
| 56 | + for (int i = 0; i < size; i++) | ||
| 57 | + result.at<float>(i) = evaluate(image, indices.empty() ? i : indices[i]); | ||
| 51 | return result; | 58 | return result; |
| 52 | } | 59 | } |
| 53 | 60 |