cascadeclassifier.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. #include "opencv2/core.hpp"
  2. #include "cascadeclassifier.h"
  3. #include <queue>
  4. using namespace std;
  5. using namespace cv;
  6. static const char* stageTypes[] = { CC_BOOST };
  7. static const char* featureTypes[] = { CC_HAAR, CC_LBP, CC_HOG };
  8. CvCascadeParams::CvCascadeParams() : stageType( defaultStageType ),
  9. featureType( defaultFeatureType ), winSize( cvSize(24, 24) )
  10. {
  11. name = CC_CASCADE_PARAMS;
  12. }
  13. CvCascadeParams::CvCascadeParams( int _stageType, int _featureType ) : stageType( _stageType ),
  14. featureType( _featureType ), winSize( cvSize(24, 24) )
  15. {
  16. name = CC_CASCADE_PARAMS;
  17. }
  18. //---------------------------- CascadeParams --------------------------------------
  19. void CvCascadeParams::write( FileStorage &fs ) const
  20. {
  21. string stageTypeStr = stageType == BOOST ? CC_BOOST : string();
  22. CV_Assert( !stageTypeStr.empty() );
  23. fs << CC_STAGE_TYPE << stageTypeStr;
  24. string featureTypeStr = featureType == CvFeatureParams::HAAR ? CC_HAAR :
  25. featureType == CvFeatureParams::LBP ? CC_LBP :
  26. featureType == CvFeatureParams::HOG ? CC_HOG :
  27. 0;
  28. CV_Assert( !stageTypeStr.empty() );
  29. fs << CC_FEATURE_TYPE << featureTypeStr;
  30. fs << CC_HEIGHT << winSize.height;
  31. fs << CC_WIDTH << winSize.width;
  32. }
  33. bool CvCascadeParams::read( const FileNode &node )
  34. {
  35. if ( node.empty() )
  36. return false;
  37. string stageTypeStr, featureTypeStr;
  38. FileNode rnode = node[CC_STAGE_TYPE];
  39. if ( !rnode.isString() )
  40. return false;
  41. rnode >> stageTypeStr;
  42. stageType = !stageTypeStr.compare( CC_BOOST ) ? BOOST : -1;
  43. if (stageType == -1)
  44. return false;
  45. rnode = node[CC_FEATURE_TYPE];
  46. if ( !rnode.isString() )
  47. return false;
  48. rnode >> featureTypeStr;
  49. featureType = !featureTypeStr.compare( CC_HAAR ) ? CvFeatureParams::HAAR :
  50. !featureTypeStr.compare( CC_LBP ) ? CvFeatureParams::LBP :
  51. !featureTypeStr.compare( CC_HOG ) ? CvFeatureParams::HOG :
  52. -1;
  53. if (featureType == -1)
  54. return false;
  55. node[CC_HEIGHT] >> winSize.height;
  56. node[CC_WIDTH] >> winSize.width;
  57. return winSize.height > 0 && winSize.width > 0;
  58. }
  59. void CvCascadeParams::printDefaults() const
  60. {
  61. CvParams::printDefaults();
  62. cout << " [-stageType <";
  63. for( int i = 0; i < (int)(sizeof(stageTypes)/sizeof(stageTypes[0])); i++ )
  64. {
  65. cout << (i ? " | " : "") << stageTypes[i];
  66. if ( i == defaultStageType )
  67. cout << "(default)";
  68. }
  69. cout << ">]" << endl;
  70. cout << " [-featureType <{";
  71. for( int i = 0; i < (int)(sizeof(featureTypes)/sizeof(featureTypes[0])); i++ )
  72. {
  73. cout << (i ? ", " : "") << featureTypes[i];
  74. if ( i == defaultStageType )
  75. cout << "(default)";
  76. }
  77. cout << "}>]" << endl;
  78. cout << " [-w <sampleWidth = " << winSize.width << ">]" << endl;
  79. cout << " [-h <sampleHeight = " << winSize.height << ">]" << endl;
  80. }
  81. void CvCascadeParams::printAttrs() const
  82. {
  83. cout << "stageType: " << stageTypes[stageType] << endl;
  84. cout << "featureType: " << featureTypes[featureType] << endl;
  85. cout << "sampleWidth: " << winSize.width << endl;
  86. cout << "sampleHeight: " << winSize.height << endl;
  87. }
  88. bool CvCascadeParams::scanAttr( const string prmName, const string val )
  89. {
  90. bool res = true;
  91. if( !prmName.compare( "-stageType" ) )
  92. {
  93. for( int i = 0; i < (int)(sizeof(stageTypes)/sizeof(stageTypes[0])); i++ )
  94. if( !val.compare( stageTypes[i] ) )
  95. stageType = i;
  96. }
  97. else if( !prmName.compare( "-featureType" ) )
  98. {
  99. for( int i = 0; i < (int)(sizeof(featureTypes)/sizeof(featureTypes[0])); i++ )
  100. if( !val.compare( featureTypes[i] ) )
  101. featureType = i;
  102. }
  103. else if( !prmName.compare( "-w" ) )
  104. {
  105. winSize.width = atoi( val.c_str() );
  106. }
  107. else if( !prmName.compare( "-h" ) )
  108. {
  109. winSize.height = atoi( val.c_str() );
  110. }
  111. else
  112. res = false;
  113. return res;
  114. }
  115. //---------------------------- CascadeClassifier --------------------------------------
  116. bool CvCascadeClassifier::train( const string _cascadeDirName,
  117. const string _posFilename,
  118. const string _negFilename,
  119. int _numPos, int _numNeg,
  120. int _precalcValBufSize, int _precalcIdxBufSize,
  121. int _numStages,
  122. const CvCascadeParams& _cascadeParams,
  123. const CvFeatureParams& _featureParams,
  124. const CvCascadeBoostParams& _stageParams,
  125. bool baseFormatSave,
  126. double acceptanceRatioBreakValue )
  127. {
  128. // Start recording clock ticks for training time output
  129. double time = (double)getTickCount();
  130. if( _cascadeDirName.empty() || _posFilename.empty() || _negFilename.empty() )
  131. CV_Error( CV_StsBadArg, "_cascadeDirName or _bgfileName or _vecFileName is NULL" );
  132. string dirName;
  133. if (_cascadeDirName.find_last_of("/\\") == (_cascadeDirName.length() - 1) )
  134. dirName = _cascadeDirName;
  135. else
  136. dirName = _cascadeDirName + '/';
  137. numPos = _numPos;
  138. numNeg = _numNeg;
  139. numStages = _numStages;
  140. if ( !imgReader.create( _posFilename, _negFilename, _cascadeParams.winSize ) )
  141. {
  142. cout << "Image reader can not be created from -vec " << _posFilename
  143. << " and -bg " << _negFilename << "." << endl;
  144. return false;
  145. }
  146. if ( !load( dirName ) )
  147. {
  148. cascadeParams = _cascadeParams;
  149. featureParams = CvFeatureParams::create(cascadeParams.featureType);
  150. featureParams->init(_featureParams);
  151. stageParams = makePtr<CvCascadeBoostParams>();
  152. *stageParams = _stageParams;
  153. featureEvaluator = CvFeatureEvaluator::create(cascadeParams.featureType);
  154. featureEvaluator->init( featureParams, numPos + numNeg, cascadeParams.winSize );
  155. stageClassifiers.reserve( numStages );
  156. }else{
  157. // Make sure that if model parameters are preloaded, that people are aware of this,
  158. // even when passing other parameters to the training command
  159. cout << "---------------------------------------------------------------------------------" << endl;
  160. cout << "Training parameters are pre-loaded from the parameter file in data folder!" << endl;
  161. cout << "Please empty this folder if you want to use a NEW set of training parameters." << endl;
  162. cout << "---------------------------------------------------------------------------------" << endl;
  163. }
  164. cout << "PARAMETERS:" << endl;
  165. cout << "cascadeDirName: " << _cascadeDirName << endl;
  166. cout << "vecFileName: " << _posFilename << endl;
  167. cout << "bgFileName: " << _negFilename << endl;
  168. cout << "numPos: " << _numPos << endl;
  169. cout << "numNeg: " << _numNeg << endl;
  170. cout << "numStages: " << numStages << endl;
  171. cout << "precalcValBufSize[Mb] : " << _precalcValBufSize << endl;
  172. cout << "precalcIdxBufSize[Mb] : " << _precalcIdxBufSize << endl;
  173. cout << "acceptanceRatioBreakValue : " << acceptanceRatioBreakValue << endl;
  174. cascadeParams.printAttrs();
  175. stageParams->printAttrs();
  176. featureParams->printAttrs();
  177. cout << "Number of unique features given windowSize [" << _cascadeParams.winSize.width << "," << _cascadeParams.winSize.height << "] : " << featureEvaluator->getNumFeatures() << "" << endl;
  178. int startNumStages = (int)stageClassifiers.size();
  179. if ( startNumStages > 1 )
  180. cout << endl << "Stages 0-" << startNumStages-1 << " are loaded" << endl;
  181. else if ( startNumStages == 1)
  182. cout << endl << "Stage 0 is loaded" << endl;
  183. double requiredLeafFARate = pow( (double) stageParams->maxFalseAlarm, (double) numStages ) /
  184. (double)stageParams->max_depth;
  185. double tempLeafFARate;
  186. for( int i = startNumStages; i < numStages; i++ )
  187. {
  188. cout << endl << "===== TRAINING " << i << "-stage =====" << endl;
  189. cout << "<BEGIN" << endl;
  190. if ( !updateTrainingSet( requiredLeafFARate, tempLeafFARate ) )
  191. {
  192. cout << "Train dataset for temp stage can not be filled. "
  193. "Branch training terminated." << endl;
  194. break;
  195. }
  196. if( tempLeafFARate <= requiredLeafFARate )
  197. {
  198. cout << "Required leaf false alarm rate achieved. "
  199. "Branch training terminated." << endl;
  200. break;
  201. }
  202. if( (tempLeafFARate <= acceptanceRatioBreakValue) && (acceptanceRatioBreakValue >= 0) ){
  203. cout << "The required acceptanceRatio for the model has been reached to avoid overfitting of trainingdata. "
  204. "Branch training terminated." << endl;
  205. break;
  206. }
  207. Ptr<CvCascadeBoost> tempStage = makePtr<CvCascadeBoost>();
  208. bool isStageTrained = tempStage->train( featureEvaluator,
  209. curNumSamples, _precalcValBufSize, _precalcIdxBufSize,
  210. *stageParams );
  211. cout << "END>" << endl;
  212. if(!isStageTrained)
  213. break;
  214. stageClassifiers.push_back( tempStage );
  215. // save params
  216. if( i == 0)
  217. {
  218. std::string paramsFilename = dirName + CC_PARAMS_FILENAME;
  219. FileStorage fs( paramsFilename, FileStorage::WRITE);
  220. if ( !fs.isOpened() )
  221. {
  222. cout << "Parameters can not be written, because file " << paramsFilename
  223. << " can not be opened." << endl;
  224. return false;
  225. }
  226. fs << FileStorage::getDefaultObjectName(paramsFilename) << "{";
  227. writeParams( fs );
  228. fs << "}";
  229. }
  230. // save current stage
  231. char buf[10];
  232. sprintf(buf, "%s%d", "stage", i );
  233. string stageFilename = dirName + buf + ".xml";
  234. FileStorage fs( stageFilename, FileStorage::WRITE );
  235. if ( !fs.isOpened() )
  236. {
  237. cout << "Current stage can not be written, because file " << stageFilename
  238. << " can not be opened." << endl;
  239. return false;
  240. }
  241. fs << FileStorage::getDefaultObjectName(stageFilename) << "{";
  242. tempStage->write( fs, Mat() );
  243. fs << "}";
  244. // Output training time up till now
  245. double seconds = ( (double)getTickCount() - time)/ getTickFrequency();
  246. int days = int(seconds) / 60 / 60 / 24;
  247. int hours = (int(seconds) / 60 / 60) % 24;
  248. int minutes = (int(seconds) / 60) % 60;
  249. int seconds_left = int(seconds) % 60;
  250. cout << "Training until now has taken " << days << " days " << hours << " hours " << minutes << " minutes " << seconds_left <<" seconds." << endl;
  251. }
  252. if(stageClassifiers.size() == 0)
  253. {
  254. cout << "Cascade classifier can't be trained. Check the used training parameters." << endl;
  255. return false;
  256. }
  257. save( dirName + CC_CASCADE_FILENAME, baseFormatSave );
  258. return true;
  259. }
  260. int CvCascadeClassifier::predict( int sampleIdx )
  261. {
  262. CV_DbgAssert( sampleIdx < numPos + numNeg );
  263. for (vector< Ptr<CvCascadeBoost> >::iterator it = stageClassifiers.begin();
  264. it != stageClassifiers.end();++it )
  265. {
  266. if ( (*it)->predict( sampleIdx ) == 0.f )
  267. return 0;
  268. }
  269. return 1;
  270. }
  271. bool CvCascadeClassifier::updateTrainingSet( double minimumAcceptanceRatio, double& acceptanceRatio)
  272. {
  273. int64 posConsumed = 0, negConsumed = 0;
  274. imgReader.restart();
  275. int posCount = fillPassedSamples( 0, numPos, true, 0, posConsumed );
  276. if( !posCount )
  277. return false;
  278. cout << "POS count : consumed " << posCount << " : " << (int)posConsumed << endl;
  279. int proNumNeg = cvRound( ( ((double)numNeg) * ((double)posCount) ) / numPos ); // apply only a fraction of negative samples. double is required since overflow is possible
  280. int negCount = fillPassedSamples( posCount, proNumNeg, false, minimumAcceptanceRatio, negConsumed );
  281. if ( !negCount )
  282. if ( !(negConsumed > 0 && ((double)negCount+1)/(double)negConsumed <= minimumAcceptanceRatio) )
  283. return false;
  284. curNumSamples = posCount + negCount;
  285. acceptanceRatio = negConsumed == 0 ? 0 : ( (double)negCount/(double)(int64)negConsumed );
  286. cout << "NEG count : acceptanceRatio " << negCount << " : " << acceptanceRatio << endl;
  287. return true;
  288. }
  289. int CvCascadeClassifier::fillPassedSamples( int first, int count, bool isPositive, double minimumAcceptanceRatio, int64& consumed )
  290. {
  291. int getcount = 0;
  292. Mat img(cascadeParams.winSize, CV_8UC1);
  293. for( int i = first; i < first + count; i++ )
  294. {
  295. for( ; ; )
  296. {
  297. if( consumed != 0 && ((double)getcount+1)/(double)(int64)consumed <= minimumAcceptanceRatio )
  298. return getcount;
  299. bool isGetImg = isPositive ? imgReader.getPos( img ) :
  300. imgReader.getNeg( img );
  301. if( !isGetImg )
  302. return getcount;
  303. consumed++;
  304. featureEvaluator->setImage( img, isPositive ? 1 : 0, i );
  305. if( predict( i ) == 1 )
  306. {
  307. getcount++;
  308. printf("%s current samples: %d\r", isPositive ? "POS":"NEG", getcount);
  309. fflush(stdout);
  310. break;
  311. }
  312. }
  313. }
  314. return getcount;
  315. }
  316. void CvCascadeClassifier::writeParams( FileStorage &fs ) const
  317. {
  318. cascadeParams.write( fs );
  319. fs << CC_STAGE_PARAMS << "{"; stageParams->write( fs ); fs << "}";
  320. fs << CC_FEATURE_PARAMS << "{"; featureParams->write( fs ); fs << "}";
  321. }
  322. void CvCascadeClassifier::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
  323. {
  324. featureEvaluator->writeFeatures( fs, featureMap );
  325. }
  326. void CvCascadeClassifier::writeStages( FileStorage &fs, const Mat& featureMap ) const
  327. {
  328. char cmnt[30];
  329. int i = 0;
  330. fs << CC_STAGES << "[";
  331. for( vector< Ptr<CvCascadeBoost> >::const_iterator it = stageClassifiers.begin();
  332. it != stageClassifiers.end();++it, ++i )
  333. {
  334. sprintf( cmnt, "stage %d", i );
  335. cvWriteComment( fs.fs, cmnt, 0 );
  336. fs << "{";
  337. (*it)->write( fs, featureMap );
  338. fs << "}";
  339. }
  340. fs << "]";
  341. }
  342. bool CvCascadeClassifier::readParams( const FileNode &node )
  343. {
  344. if ( !node.isMap() || !cascadeParams.read( node ) )
  345. return false;
  346. stageParams = makePtr<CvCascadeBoostParams>();
  347. FileNode rnode = node[CC_STAGE_PARAMS];
  348. if ( !stageParams->read( rnode ) )
  349. return false;
  350. featureParams = CvFeatureParams::create(cascadeParams.featureType);
  351. rnode = node[CC_FEATURE_PARAMS];
  352. if ( !featureParams->read( rnode ) )
  353. return false;
  354. return true;
  355. }
  356. bool CvCascadeClassifier::readStages( const FileNode &node)
  357. {
  358. FileNode rnode = node[CC_STAGES];
  359. if (!rnode.empty() || !rnode.isSeq())
  360. return false;
  361. stageClassifiers.reserve(numStages);
  362. FileNodeIterator it = rnode.begin();
  363. for( int i = 0; i < min( (int)rnode.size(), numStages ); i++, it++ )
  364. {
  365. Ptr<CvCascadeBoost> tempStage = makePtr<CvCascadeBoost>();
  366. if ( !tempStage->read( *it, featureEvaluator, *stageParams) )
  367. return false;
  368. stageClassifiers.push_back(tempStage);
  369. }
  370. return true;
  371. }
  372. // For old Haar Classifier file saving
  373. #define ICV_HAAR_TYPE_ID "opencv-haar-classifier"
  374. #define ICV_HAAR_SIZE_NAME "size"
  375. #define ICV_HAAR_STAGES_NAME "stages"
  376. #define ICV_HAAR_TREES_NAME "trees"
  377. #define ICV_HAAR_FEATURE_NAME "feature"
  378. #define ICV_HAAR_RECTS_NAME "rects"
  379. #define ICV_HAAR_TILTED_NAME "tilted"
  380. #define ICV_HAAR_THRESHOLD_NAME "threshold"
  381. #define ICV_HAAR_LEFT_NODE_NAME "left_node"
  382. #define ICV_HAAR_LEFT_VAL_NAME "left_val"
  383. #define ICV_HAAR_RIGHT_NODE_NAME "right_node"
  384. #define ICV_HAAR_RIGHT_VAL_NAME "right_val"
  385. #define ICV_HAAR_STAGE_THRESHOLD_NAME "stage_threshold"
  386. #define ICV_HAAR_PARENT_NAME "parent"
  387. #define ICV_HAAR_NEXT_NAME "next"
  388. void CvCascadeClassifier::save( const string filename, bool baseFormat )
  389. {
  390. FileStorage fs( filename, FileStorage::WRITE );
  391. if ( !fs.isOpened() )
  392. return;
  393. fs << FileStorage::getDefaultObjectName(filename);
  394. if ( !baseFormat )
  395. {
  396. Mat featureMap;
  397. getUsedFeaturesIdxMap( featureMap );
  398. fs << "{";
  399. writeParams( fs );
  400. fs << CC_STAGE_NUM << (int)stageClassifiers.size();
  401. writeStages( fs, featureMap );
  402. writeFeatures( fs, featureMap );
  403. }
  404. else
  405. {
  406. //char buf[256];
  407. CvSeq* weak;
  408. if ( cascadeParams.featureType != CvFeatureParams::HAAR )
  409. CV_Error( CV_StsBadFunc, "old file format is used for Haar-like features only");
  410. fs << "{:" ICV_HAAR_TYPE_ID;
  411. fs << ICV_HAAR_SIZE_NAME << "[:" << cascadeParams.winSize.width <<
  412. cascadeParams.winSize.height << "]";
  413. fs << ICV_HAAR_STAGES_NAME << "[";
  414. for( size_t si = 0; si < stageClassifiers.size(); si++ )
  415. {
  416. fs << "{"; //stage
  417. /*sprintf( buf, "stage %d", si );
  418. CV_CALL( cvWriteComment( fs, buf, 1 ) );*/
  419. weak = stageClassifiers[si]->get_weak_predictors();
  420. fs << ICV_HAAR_TREES_NAME << "[";
  421. for( int wi = 0; wi < weak->total; wi++ )
  422. {
  423. int inner_node_idx = -1, total_inner_node_idx = -1;
  424. queue<const CvDTreeNode*> inner_nodes_queue;
  425. CvCascadeBoostTree* tree = *((CvCascadeBoostTree**) cvGetSeqElem( weak, wi ));
  426. fs << "[";
  427. /*sprintf( buf, "tree %d", wi );
  428. CV_CALL( cvWriteComment( fs, buf, 1 ) );*/
  429. const CvDTreeNode* tempNode;
  430. inner_nodes_queue.push( tree->get_root() );
  431. total_inner_node_idx++;
  432. while (!inner_nodes_queue.empty())
  433. {
  434. tempNode = inner_nodes_queue.front();
  435. inner_node_idx++;
  436. fs << "{";
  437. fs << ICV_HAAR_FEATURE_NAME << "{";
  438. ((CvHaarEvaluator*)featureEvaluator.get())->writeFeature( fs, tempNode->split->var_idx );
  439. fs << "}";
  440. fs << ICV_HAAR_THRESHOLD_NAME << tempNode->split->ord.c;
  441. if( tempNode->left->left || tempNode->left->right )
  442. {
  443. inner_nodes_queue.push( tempNode->left );
  444. total_inner_node_idx++;
  445. fs << ICV_HAAR_LEFT_NODE_NAME << total_inner_node_idx;
  446. }
  447. else
  448. fs << ICV_HAAR_LEFT_VAL_NAME << tempNode->left->value;
  449. if( tempNode->right->left || tempNode->right->right )
  450. {
  451. inner_nodes_queue.push( tempNode->right );
  452. total_inner_node_idx++;
  453. fs << ICV_HAAR_RIGHT_NODE_NAME << total_inner_node_idx;
  454. }
  455. else
  456. fs << ICV_HAAR_RIGHT_VAL_NAME << tempNode->right->value;
  457. fs << "}"; // ICV_HAAR_FEATURE_NAME
  458. inner_nodes_queue.pop();
  459. }
  460. fs << "]";
  461. }
  462. fs << "]"; //ICV_HAAR_TREES_NAME
  463. fs << ICV_HAAR_STAGE_THRESHOLD_NAME << stageClassifiers[si]->getThreshold();
  464. fs << ICV_HAAR_PARENT_NAME << (int)si-1 << ICV_HAAR_NEXT_NAME << -1;
  465. fs << "}"; //stage
  466. } /* for each stage */
  467. fs << "]"; //ICV_HAAR_STAGES_NAME
  468. }
  469. fs << "}";
  470. }
  471. bool CvCascadeClassifier::load( const string cascadeDirName )
  472. {
  473. FileStorage fs( cascadeDirName + CC_PARAMS_FILENAME, FileStorage::READ );
  474. if ( !fs.isOpened() )
  475. return false;
  476. FileNode node = fs.getFirstTopLevelNode();
  477. if ( !readParams( node ) )
  478. return false;
  479. featureEvaluator = CvFeatureEvaluator::create(cascadeParams.featureType);
  480. featureEvaluator->init( featureParams, numPos + numNeg, cascadeParams.winSize );
  481. fs.release();
  482. char buf[16] = {0};
  483. for ( int si = 0; si < numStages; si++ )
  484. {
  485. sprintf( buf, "%s%d", "stage", si);
  486. fs.open( cascadeDirName + buf + ".xml", FileStorage::READ );
  487. node = fs.getFirstTopLevelNode();
  488. if ( !fs.isOpened() )
  489. break;
  490. Ptr<CvCascadeBoost> tempStage = makePtr<CvCascadeBoost>();
  491. if ( !tempStage->read( node, featureEvaluator, *stageParams ))
  492. {
  493. fs.release();
  494. break;
  495. }
  496. stageClassifiers.push_back(tempStage);
  497. }
  498. return true;
  499. }
  500. void CvCascadeClassifier::getUsedFeaturesIdxMap( Mat& featureMap )
  501. {
  502. int varCount = featureEvaluator->getNumFeatures() * featureEvaluator->getFeatureSize();
  503. featureMap.create( 1, varCount, CV_32SC1 );
  504. featureMap.setTo(Scalar(-1));
  505. for( vector< Ptr<CvCascadeBoost> >::const_iterator it = stageClassifiers.begin();
  506. it != stageClassifiers.end();++it )
  507. (*it)->markUsedFeaturesInMap( featureMap );
  508. for( int fi = 0, idx = 0; fi < varCount; fi++ )
  509. if ( featureMap.at<int>(0, fi) >= 0 )
  510. featureMap.ptr<int>(0)[fi] = idx++;
  511. }