FeatureLearningClusterBased.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. #include "FeatureLearningClusterBased.h"
  2. #include <iostream>
  3. #include <core/image/FilterT.h>
  4. #include <core/image/CircleT.h>
  5. #include <core/image/Convert.h>
  6. #include <core/vector/VectorT.h>
  7. // #include <vislearning/baselib/ICETools.h>
  8. //
  9. #include <vislearning/features/localfeatures/LFonHSG.h>
  10. #include <vislearning/features/localfeatures/LFColorSande.h>
  11. #include <vislearning/features/localfeatures/LFColorWeijer.h>
  12. #include <vislearning/features/localfeatures/LFReadCache.h>
  13. #include <vislearning/features/localfeatures/LFWriteCache.h>
  14. //
  15. #include <vislearning/math/cluster/KMeans.h>
  16. #include <vislearning/math/cluster/GMM.h>
  17. using namespace std;
  18. using namespace NICE;
  19. using namespace OBJREC;
  20. //**********************************************
  21. //
  22. // PROTECTED METHODS
  23. //
  24. //**********************************************
  25. void FeatureLearningClusterBased::setClusterAlgo( const std::string & _clusterAlgoString, const bool & _setForInitialTraining)
  26. {
  27. //be careful with previously allocated memory
  28. if (this->clusterAlgo != NULL)
  29. delete clusterAlgo;
  30. if (_clusterAlgoString.compare("kmeans") == 0)
  31. {
  32. if ( _setForInitialTraining )
  33. this->clusterAlgo = new OBJREC::KMeans(this->initialNumberOfClusters);
  34. else
  35. this->clusterAlgo = new OBJREC::KMeans(this->numberOfClustersForNewImage);
  36. }
  37. else if (_clusterAlgoString.compare("GMM") == 0)
  38. {
  39. if ( _setForInitialTraining )
  40. this->clusterAlgo = new OBJREC::GMM(this->conf, this->initialNumberOfClusters);
  41. else
  42. this->clusterAlgo = new OBJREC::GMM(this->conf, this->numberOfClustersForNewImage);
  43. }
  44. else
  45. {
  46. std::cerr << "Unknown cluster algorithm selected, use k-means instead" << std::endl;
  47. if ( _setForInitialTraining )
  48. this->clusterAlgo = new OBJREC::KMeans(this->initialNumberOfClusters);
  49. else
  50. this->clusterAlgo = new OBJREC::KMeans(this->numberOfClustersForNewImage);
  51. }
  52. }
  53. void FeatureLearningClusterBased::extractFeaturesFromTrainingImages( const OBJREC::MultiDataset *_md, NICE::VVector & examplesTraining )
  54. {
  55. examplesTraining.clear();
  56. int numberOfTrainImage ( 0 );
  57. const LabeledSet *trainFiles = (*_md)["train"];
  58. //run over all training images
  59. LOOP_ALL_S( *trainFiles )
  60. {
  61. EACH_INFO( classno, info );
  62. std::string filename = info.img();
  63. NICE::ColorImage img( filename );
  64. if ( showTrainingImages )
  65. {
  66. showImage( img, "Input" );
  67. }
  68. //variables to store feature informatio
  69. NICE::VVector features;
  70. NICE::VVector cfeatures;
  71. NICE::VVector positions;
  72. //compute features
  73. Globals::setCurrentImgFN ( filename );
  74. if (featureExtractor == NULL)
  75. std::cerr << "feature Extractor is NULL" << std::endl;
  76. else
  77. featureExtractor->extractFeatures ( img, features, positions );
  78. //store feature information in larger data structure
  79. for ( NICE::VVector::iterator i = features.begin();
  80. i != features.end();
  81. i++)
  82. {
  83. //normalization :)
  84. i->normalizeL1();
  85. examplesTraining.push_back(*i);
  86. }
  87. //don't waste memory
  88. features.clear();
  89. positions.clear();
  90. numberOfTrainImage++;
  91. }//Loop over all training images
  92. }
  93. void FeatureLearningClusterBased::train ( const OBJREC::MultiDataset *_md )
  94. {
  95. bool loadSuccess = this->loadInitialCodebook();
  96. if ( !loadSuccess )
  97. {
  98. //**********************************************
  99. //
  100. // EXTRACT FEATURES FROM TRAINING IMAGES
  101. //
  102. //**********************************************
  103. std::cerr << " EXTRACT FEATURES FROM TRAINING IMAGES" << std::endl;
  104. NICE::VVector examplesTraining;
  105. this->extractFeaturesFromTrainingImages( _md, examplesTraining );
  106. //**********************************************
  107. //
  108. // CLUSTER FEATURES FROM TRAINING IMAGES
  109. //
  110. // THIS GIVES US AN INITIAL CODEBOOK
  111. //
  112. //**********************************************
  113. std::cerr << " CLUSTER FEATURES FROM TRAINING IMAGES" << std::endl;
  114. //go, go, go...
  115. prototypes.clear();
  116. std::vector< double > weights;
  117. std::vector< int > assignment;
  118. clusterAlgo->cluster ( examplesTraining, prototypes, weights, assignment);
  119. weights.clear();
  120. assignment.clear();
  121. }
  122. this->writeInitialCodebook();
  123. }
  124. bool FeatureLearningClusterBased::loadInitialCodebook ( )
  125. {
  126. if ( b_loadInitialCodebook )
  127. {
  128. std::cerr << " INITIAL CODEBOOK ALREADY COMPUTED - RE-USE IT" << std::endl;
  129. std::cerr << " // WARNING - WE DO NOT VERIFY WHETHER THIS IS THE CORRECT CODEBOOK FOR THIS TRAINING SET!!!!" << std::endl;
  130. prototypes.clear();
  131. try
  132. {
  133. prototypes.read(cacheInitialCodebook);
  134. }
  135. catch (...)
  136. {
  137. std::cerr << "Error while loading initial codebook" << std::endl;
  138. return false;
  139. }
  140. return true;
  141. }
  142. else
  143. return false;
  144. }
  145. bool FeatureLearningClusterBased::writeInitialCodebook ( )
  146. {
  147. if ( b_saveInitialCodebook )
  148. {
  149. std::cerr << " SAVE INITIAL CODEBOOK " << std::endl;
  150. try
  151. {
  152. prototypes.write( cacheInitialCodebook );
  153. }
  154. catch (...)
  155. {
  156. std::cerr << "Error while saving initial codebook" << std::endl;
  157. return false;
  158. }
  159. return true;
  160. }
  161. else
  162. return false;
  163. }
  164. //**********************************************
  165. //
  166. // PUBLIC METHODS
  167. //
  168. //**********************************************
  169. FeatureLearningClusterBased::FeatureLearningClusterBased ( const Config *_conf,
  170. const MultiDataset *_md, const std::string & _section )
  171. : FeatureLearningGeneric ( _conf, _section )
  172. {
  173. //feature stuff
  174. //! which OpponentSIFT implementation to use {NICE, VANDESANDE}
  175. std::string opSiftImpl;
  176. opSiftImpl = conf->gS ( "Descriptor", "implementation", "VANDESANDE" );
  177. //! read features?
  178. bool readfeat;
  179. readfeat = conf->gB ( "Descriptor", "read", true );
  180. //! write features?
  181. bool writefeat;
  182. writefeat = conf->gB ( "Descriptor", "write", true );
  183. showTrainingImages = conf->gB( section, "showTrainingImages", false );
  184. showResults = conf->gB( section, "showResults", false );
  185. resultdir = conf->gS( section, "resultdir", "/tmp/");
  186. //! define the initial number of clusters our codebook shall contain
  187. initialNumberOfClusters = conf->gI(section, "initialNumberOfClusters", 10);
  188. //! define the number of clusters we want to compute for an unseen image
  189. numberOfClustersForNewImage = conf->gI(section, "numberOfClustersForNewImage", 10);
  190. //! define the clustering algorithm to be used
  191. std::string clusterAlgoString = conf->gS(section, "clusterAlgo", "kmeans");
  192. //! define the distance function to be used
  193. std::string distFunctionString = conf->gS(section, "distFunction", "euclidian");
  194. //**********************************************
  195. //
  196. // SET UP VARIABLES AND METHODS
  197. // - FEATURE TYPE
  198. // - CLUSTERING ALGO
  199. // - DISTANCE FUNCTION
  200. // - ...
  201. //
  202. //**********************************************
  203. std::cerr << " SET UP VARIABLES AND METHODS " << std::endl;
  204. // Welche Opponentsift Implementierung soll genutzt werden ?
  205. LocalFeatureRepresentation *cSIFT = NULL;
  206. LocalFeatureRepresentation *writeFeats = NULL;
  207. LocalFeatureRepresentation *readFeats = NULL;
  208. this->featureExtractor = NULL;
  209. if ( opSiftImpl == "NICE" )
  210. {
  211. cSIFT = new OBJREC::LFonHSG ( conf, "HSGtrain" );
  212. }
  213. else if ( opSiftImpl == "VANDESANDE" )
  214. {
  215. cSIFT = new OBJREC::LFColorSande ( conf, "LFColorSandeTrain" );
  216. }
  217. else
  218. {
  219. fthrow ( Exception, "feattype: %s not yet supported" << opSiftImpl );
  220. }
  221. this->featureExtractor = cSIFT;
  222. if ( writefeat )
  223. {
  224. // write the features to a file, if there isn't any to read
  225. writeFeats = new LFWriteCache ( conf, cSIFT );
  226. this->featureExtractor = writeFeats;
  227. }
  228. if ( readfeat )
  229. {
  230. // read the features from a file
  231. if ( writefeat )
  232. {
  233. readFeats = new LFReadCache ( conf, writeFeats, -1 );
  234. }
  235. else
  236. {
  237. readFeats = new LFReadCache ( conf, cSIFT, -1 );
  238. }
  239. this->featureExtractor = readFeats;
  240. }
  241. this->clusterAlgo = NULL;
  242. this->setClusterAlgo( clusterAlgoString, true /*set cluster algo for training*/ );
  243. if (distFunctionString.compare("euclidian") == 0)
  244. {
  245. distFunction = new NICE::EuclidianDistance<double>();
  246. }
  247. else
  248. {
  249. std::cerr << "Unknown vector distance selected, use euclidian instead" << std::endl;
  250. distFunction = new NICE::EuclidianDistance<double>();
  251. }
  252. //run the training to initially compute a codebook and stuff like that
  253. this->train( _md );
  254. //only set feature stuff to NULL, deletion of the underlying object is done in the destructor
  255. if ( cSIFT != NULL )
  256. cSIFT = NULL;
  257. if ( writeFeats != NULL )
  258. writeFeats = NULL;
  259. if ( readFeats != NULL )
  260. readFeats = NULL ;
  261. this->setClusterAlgo( clusterAlgoString, false /*set cluster algo for feature learning*/ );
  262. //so far, we have not seen any new image
  263. this->newImageCounter = 0;
  264. //TODO stupid
  265. this->maxValForVisualization = 0.005;
  266. }
  267. FeatureLearningClusterBased::~FeatureLearningClusterBased()
  268. {
  269. // clean-up
  270. if ( clusterAlgo != NULL )
  271. delete clusterAlgo;
  272. if ( distFunction != NULL )
  273. delete distFunction;
  274. if ( featureExtractor != NULL )
  275. delete featureExtractor;
  276. }
  277. void FeatureLearningClusterBased::learnNewFeatures ( const std::string & _filename )
  278. {
  279. NICE::ColorImage img( _filename );
  280. int xsize ( img.width() );
  281. int ysize ( img.height() );
  282. //variables to store feature information
  283. NICE::VVector newFeatures;
  284. NICE::VVector cfeatures;
  285. NICE::VVector positions;
  286. //compute features
  287. std::cerr << " EXTRACT FEATURES FROM UNSEEN IMAGE" << std::endl;
  288. Globals::setCurrentImgFN ( _filename );
  289. featureExtractor->extractFeatures ( img, newFeatures, positions );
  290. //store feature information in larger data structure
  291. for ( NICE::VVector::iterator i = newFeatures.begin();
  292. i != newFeatures.end();
  293. i++)
  294. {
  295. //normalization :)
  296. i->normalizeL1();
  297. }
  298. //cluster features
  299. std::cerr << " CLUSTER FEATURES FROM UNSEEN IMAGE" << std::endl;
  300. NICE::VVector prototypesForNewImage;
  301. std::vector< double > weights;
  302. std::vector< int > assignment;
  303. clusterAlgo->cluster ( newFeatures, prototypesForNewImage, weights, assignment);
  304. if ( b_evaluationWhileFeatureLearning )
  305. {
  306. //visualize new clusters
  307. int tmpProtCnt ( 0 );
  308. for (NICE::VVector::const_iterator protIt = prototypesForNewImage.begin(); protIt != prototypesForNewImage.end(); protIt++, tmpProtCnt++)
  309. {
  310. double distToNewCluster ( std::numeric_limits<double>::max() );
  311. int indexOfMostSimFeat( 0 );
  312. double tmpDist;
  313. int tmpCnt ( 0 );
  314. for ( NICE::VVector::iterator i = newFeatures.begin();
  315. i != newFeatures.end();
  316. i++, tmpCnt++)
  317. {
  318. tmpDist = this->distFunction->calculate( *i, *protIt );
  319. if ( tmpDist < distToNewCluster )
  320. {
  321. distToNewCluster = tmpDist;
  322. indexOfMostSimFeat = tmpCnt;
  323. }
  324. }
  325. int posX ( ( positions[indexOfMostSimFeat] ) [0] );
  326. int posY ( ( positions[indexOfMostSimFeat] ) [1] );
  327. NICE::Circle circ ( Coord( posX, posY), 10 /* radius*/, Color(200,0,255) );
  328. img.draw(circ);
  329. }
  330. //draw features most similar to old clusters
  331. tmpProtCnt = 0;
  332. for (NICE::VVector::const_iterator protIt = prototypes.begin(); protIt != prototypes.end(); protIt++, tmpProtCnt++)
  333. {
  334. double distToNewCluster ( std::numeric_limits<double>::max() );
  335. int indexOfMostSimFeat( 0 );
  336. double tmpDist;
  337. int tmpCnt ( 0 );
  338. for ( NICE::VVector::iterator i = newFeatures.begin();
  339. i != newFeatures.end();
  340. i++, tmpCnt++)
  341. {
  342. tmpDist = this->distFunction->calculate( *i, *protIt );
  343. if ( tmpDist < distToNewCluster )
  344. {
  345. distToNewCluster = tmpDist;
  346. indexOfMostSimFeat = tmpCnt;
  347. }
  348. }
  349. int posX ( ( positions[indexOfMostSimFeat] ) [0] );
  350. int posY ( ( positions[indexOfMostSimFeat] ) [1] );
  351. NICE::Circle circ ( Coord( posX, posY), 5 /* radius*/, Color(200,255,0 ) );
  352. img.draw(circ);
  353. }
  354. if ( showResults )
  355. showImage(img, "Current (new) image and most similar feature for new cluster");
  356. else
  357. {
  358. std::vector< std::string > list2;
  359. StringTools::split ( _filename, '/', list2 );
  360. std::string destination ( resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_1_oldAndNewClusters.ppm");
  361. img.writePPM( destination );
  362. }
  363. }
  364. //compute score for every cluster: #assigned features * distance to current cluster centers
  365. NICE::Vector distancesToCurrentClusters ( numberOfClustersForNewImage, 0.0 );
  366. NICE::Vector clusterSizes ( numberOfClustersForNewImage, 0.0 ); //i.e., the number of assignments, or a derived number
  367. //compute "relevance" of every new cluster
  368. std::cerr << " COMPUTE SIZES OF NEW CLUSTERS" << std::endl;
  369. for (std::vector<int>::const_iterator assignIt = assignment.begin(); assignIt != assignment.end(); assignIt++)
  370. {
  371. clusterSizes[*assignIt]++;
  372. }
  373. clusterSizes.normalizeL1();
  374. std::cerr << "cluster Sizes: " << clusterSizes << std::endl;
  375. //compute distances of new cluster centers to old cluster centers
  376. std::cerr << " COMPUTE DISTANCES BETWEEN NEW AND OLD CLUSTERS" << std::endl;
  377. NICE::Vector::iterator distanceIt = distancesToCurrentClusters.begin();
  378. for ( NICE::VVector::const_iterator newProtIt = prototypesForNewImage.begin(); newProtIt != prototypesForNewImage.end(); newProtIt++, distanceIt++)
  379. {
  380. double minDist ( std::numeric_limits<double>::max() );
  381. double tmpDist;
  382. for ( NICE::VVector::const_iterator protIt = prototypes.begin(); protIt != prototypes.end(); protIt ++)
  383. {
  384. //compute distance
  385. tmpDist = this->distFunction->calculate( *protIt, *newProtIt );
  386. if (tmpDist < minDist)
  387. minDist = tmpDist;
  388. }
  389. *distanceIt = minDist;
  390. }
  391. std::cerr << "distances: " << distancesToCurrentClusters << std::endl;
  392. //compute final scores for the new image
  393. NICE::Vector clusterScores ( numberOfClustersForNewImage, 0.0 );
  394. for (uint i = 0; i < numberOfClustersForNewImage; i++)
  395. {
  396. clusterScores[i] = clusterSizes[i] * distancesToCurrentClusters[i];
  397. }
  398. std::cerr << "final cluster scores for new image: " << clusterScores << std::endl;
  399. NICE::Vector chosenClusterCenter ( prototypesForNewImage[ clusterScores.MaxIndex() ] );
  400. //include the chosen information into the currently used prototypes
  401. prototypes.push_back( chosenClusterCenter );
  402. if ( b_evaluationWhileFeatureLearning )
  403. {
  404. NICE::ColorImage imgTmp( _filename );
  405. double distToNewCluster ( std::numeric_limits<double>::max() );
  406. int indexOfMostSimFeat( 0 );
  407. double tmpDist;
  408. int tmpCnt ( 0 );
  409. for ( NICE::VVector::iterator i = newFeatures.begin();
  410. i != newFeatures.end();
  411. i++, tmpCnt++)
  412. {
  413. tmpDist = this->distFunction->calculate( *i, chosenClusterCenter );
  414. if ( tmpDist < distToNewCluster )
  415. {
  416. distToNewCluster = tmpDist;
  417. indexOfMostSimFeat = tmpCnt;
  418. }
  419. }
  420. int posX ( ( positions[indexOfMostSimFeat] ) [0] );
  421. int posY ( ( positions[indexOfMostSimFeat] ) [1] );
  422. NICE::Circle circ ( Coord( posX, posY), 10 /* radius*/, Color(200,0,255) );
  423. imgTmp.draw(circ);
  424. if ( showResults )
  425. showImage(imgTmp, "Current (new) image and most similar feature for new cluster");
  426. else
  427. {
  428. std::vector< std::string > list2;
  429. StringTools::split ( _filename, '/', list2 );
  430. std::string destination ( resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_2_bestNewCluster.ppm");
  431. imgTmp.writePPM( destination );
  432. }
  433. }
  434. //this was a new image, so we increase our internal counter
  435. (this->newImageCounter)++;
  436. }
  437. NICE::FloatImage FeatureLearningClusterBased::evaluateCurrentCodebook ( const std::string & _filename , const bool & beforeComputingNewFeatures )
  438. {
  439. NICE::ColorImage img( _filename );
  440. if ( showTrainingImages )
  441. {
  442. showImage( img, "Input" );
  443. }
  444. int xsize ( img.width() );
  445. int ysize ( img.height() );
  446. //variables to store feature information
  447. NICE::VVector features;
  448. NICE::VVector cfeatures;
  449. NICE::VVector positions;
  450. //compute features
  451. Globals::setCurrentImgFN ( _filename );
  452. featureExtractor->extractFeatures ( img, features, positions );
  453. FloatImage noveltyImage ( xsize, ysize );
  454. noveltyImage.set ( 0.0 );
  455. double maxDist ( 0.0 );
  456. NICE::VVector::const_iterator posIt = positions.begin();
  457. //store feature information in larger data structure
  458. for ( NICE::VVector::iterator i = features.begin();
  459. i != features.end();
  460. i++, posIt++)
  461. {
  462. //normalization :)
  463. i->normalizeL1();
  464. //loop over codebook representatives
  465. double minDist ( std::numeric_limits<double>::max() );
  466. for (NICE::VVector::const_iterator it = prototypes.begin(); it != prototypes.end(); it++)
  467. {
  468. //compute distance
  469. double tmpDist ( this->distFunction->calculate(*i,*it) );
  470. if (tmpDist < minDist)
  471. minDist = tmpDist;
  472. }
  473. if (minDist > maxDist)
  474. maxDist = minDist;
  475. //take minimum distance and store in in a float image
  476. noveltyImage ( (*posIt)[0], (*posIt)[1] ) = minDist;
  477. }
  478. //gauss-filtering for nicer visualization
  479. FloatImage noveltyImageGaussFiltered ( xsize, ysize );
  480. float sigma ( 3.0 );
  481. FilterT<float, float, float> filter;
  482. filter.filterGaussSigmaApproximate ( noveltyImage, sigma, &noveltyImageGaussFiltered );
  483. double maxFiltered ( noveltyImageGaussFiltered.max() );
  484. std::cerr << "maximum distance of Training images: " << maxDist << std::endl;
  485. std::cerr << "maximum distance of Training images after filtering: " << maxFiltered << std::endl;
  486. if ( beforeComputingNewFeatures )
  487. this->oldMaxDist = maxFiltered;
  488. //for suitable visualization of scores between zero (known) and one (unknown)
  489. // noveltyImageGaussFiltered( 0 , 0 ) = std::max<double>(maxDist, 1.0);
  490. //convert float to RGB
  491. NICE::ColorImage noveltyImageRGB ( xsize, ysize );
  492. // ICETools::convertToRGB ( noveltyImageGaussFiltered, noveltyImageRGB );
  493. if ( beforeComputingNewFeatures )
  494. {
  495. imageToPseudoColorWithRangeSpecification( noveltyImageGaussFiltered, noveltyImageRGB, 0 /* min */, maxValForVisualization /* maxFiltered*/ /* max */ );
  496. std::cerr << "set max value to: " << noveltyImageGaussFiltered.max() << std::endl;
  497. }
  498. else
  499. {
  500. imageToPseudoColorWithRangeSpecification( noveltyImageGaussFiltered, noveltyImageRGB, 0 /* min */, maxValForVisualization /*this->oldMaxDist*/ /* max */ );
  501. std::cerr << "set max value to: " << this->oldMaxDist << std::endl;
  502. }
  503. if ( showResults )
  504. showImage(noveltyImageRGB, "Novelty Image");
  505. else
  506. {
  507. std::vector< std::string > list2;
  508. StringTools::split ( _filename, '/', list2 );
  509. std::string destination ( resultdir + NICE::intToString(this->newImageCounter -1 ) + "_" + list2.back() + "_3_updatedNoveltyMap.ppm");
  510. if ( beforeComputingNewFeatures )
  511. destination = resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_0_initialNoveltyMap.ppm";
  512. noveltyImageRGB.writePPM( destination );
  513. }
  514. // now look where the closest features for the current cluster indices are
  515. int tmpProtCnt ( 0 );
  516. for (NICE::VVector::const_iterator protIt = prototypes.begin(); protIt != prototypes.end(); protIt++, tmpProtCnt++)
  517. {
  518. double distToNewCluster ( std::numeric_limits<double>::max() );
  519. int indexOfMostSimFeat( 0 );
  520. double tmpDist;
  521. int tmpCnt ( 0 );
  522. for ( NICE::VVector::iterator i = features.begin();
  523. i != features.end();
  524. i++, tmpCnt++)
  525. {
  526. tmpDist = this->distFunction->calculate( *i, *protIt );
  527. if ( tmpDist < distToNewCluster )
  528. {
  529. distToNewCluster = tmpDist;
  530. indexOfMostSimFeat = tmpCnt;
  531. }
  532. }
  533. int posX ( ( positions[indexOfMostSimFeat] ) [0] );
  534. int posY ( ( positions[indexOfMostSimFeat] ) [1] );
  535. NICE::Circle circ ( Coord( posX, posY), 2*tmpProtCnt /* radius*/, Color(200,0,255 ) );
  536. img.draw(circ);
  537. }
  538. if ( showResults )
  539. showImage(img, "Current image and most similar features for current cluster");
  540. else
  541. {
  542. std::vector< std::string > list2;
  543. StringTools::split ( _filename, '/', list2 );
  544. std::string destination ( resultdir + NICE::intToString(this->newImageCounter-1) + "_" + list2.back() + "_3_updatedCurrentCluster.ppm");
  545. if ( beforeComputingNewFeatures )
  546. destination = resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_0_initialCurrentCluster.ppm";
  547. img.writePPM( destination );
  548. }
  549. return noveltyImageGaussFiltered;
  550. }