FeatureLearningPrototypes.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. #include "FeatureLearningPrototypes.h"
  2. //STL
  3. #include <iostream>
  4. //core
  5. #include <core/image/FilterT.h>
  6. #include <core/image/CircleT.h>
  7. #include <core/image/Convert.h>
  8. #include <core/imagedisplay/ImageDisplay.h>
  9. #include <core/vector/VectorT.h>
  10. //vislearning
  11. #include <vislearning/features/localfeatures/LFonHSG.h>
  12. #include <vislearning/features/localfeatures/LFColorSande.h>
  13. #include <vislearning/features/localfeatures/LocalFeatureColorWeijer.h>
  14. #include <vislearning/features/localfeatures/LFReadCache.h>
  15. #include <vislearning/features/localfeatures/LFWriteCache.h>
  16. //
  17. #include <vislearning/math/cluster/KMeans.h>
  18. #include <vislearning/math/cluster/KMedian.h>
  19. #include <vislearning/math/cluster/GMM.h>
  20. using namespace std;
  21. using namespace NICE;
  22. using namespace OBJREC;
  23. //**********************************************
  24. //
  25. // PROTECTED METHODS
  26. //
  27. //**********************************************
  28. void FeatureLearningPrototypes::setClusterAlgo( const std::string & _clusterAlgoString)
  29. {
  30. //be careful with previously allocated memory
  31. if (this->clusterAlgo != NULL)
  32. delete clusterAlgo;
  33. if (_clusterAlgoString.compare("kmeans") == 0)
  34. {
  35. this->clusterAlgo = new OBJREC::KMeans(this->initialNumberOfClusters);
  36. }
  37. else if (_clusterAlgoString.compare("kmedian") == 0)
  38. {
  39. this->clusterAlgo = new OBJREC::KMedian(this->initialNumberOfClusters);
  40. }
  41. else if (_clusterAlgoString.compare("GMM") == 0)
  42. {
  43. this->clusterAlgo = new OBJREC::GMM(this->conf, this->initialNumberOfClusters);
  44. }
  45. else
  46. {
  47. std::cerr << "Unknown cluster algorithm selected, use k-means instead" << std::endl;
  48. this->clusterAlgo = new OBJREC::KMeans(this->initialNumberOfClusters);
  49. }
  50. }
  51. void FeatureLearningPrototypes::setFeatureExtractor( const bool & _setForTraining )
  52. {
  53. //be careful with previously allocated memory
  54. if (this->featureExtractor != NULL)
  55. delete featureExtractor;
  56. //feature stuff
  57. // which OpponentSIFT implementation to use {NICE, VANDESANDE}
  58. std::string opSiftImpl;
  59. opSiftImpl = this->conf->gS ( "Descriptor", "implementation", "VANDESANDE" );
  60. // read features?
  61. bool readfeat;
  62. readfeat = this->conf->gB ( "Descriptor", "read", true );
  63. // write features?
  64. bool writefeat;
  65. writefeat = this->conf->gB ( "Descriptor", "write", true );
  66. // Welche Opponentsift Implementierung soll genutzt werden ?
  67. LocalFeatureRepresentation *cSIFT = NULL;
  68. LocalFeatureRepresentation *writeFeats = NULL;
  69. LocalFeatureRepresentation *readFeats = NULL;
  70. this->featureExtractor = NULL;
  71. if ( opSiftImpl == "NICE" )
  72. {
  73. if ( _setForTraining )
  74. cSIFT = new OBJREC::LFonHSG ( this->conf, "HSGTrain" );
  75. else
  76. cSIFT = new OBJREC::LFonHSG ( this->conf, "HSGTest" );
  77. }
  78. else if ( opSiftImpl == "VANDESANDE" )
  79. {
  80. if ( _setForTraining )
  81. cSIFT = new OBJREC::LFColorSande ( this->conf, "LFColorSandeTrain" );
  82. else
  83. cSIFT = new OBJREC::LFColorSande ( this->conf, "LFColorSandeTest" );
  84. }
  85. else
  86. {
  87. fthrow ( Exception, "feattype: %s not yet supported" << opSiftImpl );
  88. }
  89. this->featureExtractor = cSIFT;
  90. if ( writefeat )
  91. {
  92. // write the features to a file, if there isn't any to read
  93. writeFeats = new LFWriteCache ( this->conf, cSIFT );
  94. this->featureExtractor = writeFeats;
  95. }
  96. if ( readfeat )
  97. {
  98. // read the features from a file
  99. if ( writefeat )
  100. {
  101. readFeats = new LFReadCache ( this->conf, writeFeats, -1 );
  102. }
  103. else
  104. {
  105. readFeats = new LFReadCache ( this->conf, cSIFT, -1 );
  106. }
  107. this->featureExtractor = readFeats;
  108. }
  109. //only set feature stuff to NULL, deletion of the underlying object is done in the destructor
  110. if ( cSIFT != NULL )
  111. cSIFT = NULL;
  112. if ( writeFeats != NULL )
  113. writeFeats = NULL;
  114. if ( readFeats != NULL )
  115. readFeats = NULL ;
  116. }
  117. void FeatureLearningPrototypes::extractFeaturesFromTrainingImages( const OBJREC::MultiDataset *_md, NICE::VVector & examplesTraining )
  118. {
  119. examplesTraining.clear();
  120. int numberOfTrainImage ( 0 );
  121. const LabeledSet *trainFiles = (*_md)["train"];
  122. //run over all training images
  123. LOOP_ALL_S( *trainFiles )
  124. {
  125. EACH_INFO( classno, info );
  126. std::string filename = info.img();
  127. NICE::ColorImage img( filename );
  128. if ( b_showTrainingImages )
  129. {
  130. showImage( img, "Input" );
  131. }
  132. //variables to store feature informatio
  133. NICE::VVector features;
  134. NICE::VVector cfeatures;
  135. NICE::VVector positions;
  136. //compute features
  137. Globals::setCurrentImgFN ( filename );
  138. if (featureExtractor == NULL)
  139. std::cerr << "feature Extractor is NULL" << std::endl;
  140. else
  141. featureExtractor->extractFeatures ( img, features, positions );
  142. //store feature information in larger data structure
  143. for ( NICE::VVector::iterator i = features.begin();
  144. i != features.end();
  145. i++)
  146. {
  147. //normalization :)
  148. i->normalizeL1();
  149. examplesTraining.push_back(*i);
  150. }
  151. //don't waste memory
  152. features.clear();
  153. positions.clear();
  154. numberOfTrainImage++;
  155. }//Loop over all training images
  156. }
  157. void FeatureLearningPrototypes::train ( const OBJREC::MultiDataset *_md )
  158. {
  159. bool loadSuccess = this->loadInitialCodebook();
  160. if ( !loadSuccess )
  161. {
  162. //**********************************************
  163. //
  164. // EXTRACT FEATURES FROM TRAINING IMAGES
  165. //
  166. //**********************************************
  167. std::cerr << " EXTRACT FEATURES FROM TRAINING IMAGES" << std::endl;
  168. NICE::VVector examplesTraining;
  169. this->extractFeaturesFromTrainingImages( _md, examplesTraining );
  170. //**********************************************
  171. //
  172. // CLUSTER FEATURES FROM TRAINING IMAGES
  173. //
  174. // THIS GIVES US AN INITIAL CODEBOOK
  175. //
  176. //**********************************************
  177. std::cerr << " CLUSTER FEATURES FROM TRAINING IMAGES" << std::endl;
  178. //go, go, go...
  179. prototypes.clear();
  180. std::vector< double > weights;
  181. std::vector< int > assignment;
  182. clusterAlgo->cluster ( examplesTraining, prototypes, weights, assignment);
  183. weights.clear();
  184. assignment.clear();
  185. //normalization
  186. for (NICE::VVector::iterator protoIt = prototypes.begin(); protoIt != prototypes.end(); protoIt++)
  187. {
  188. protoIt->normalizeL1();
  189. }
  190. }
  191. this->writeInitialCodebook();
  192. }
  193. bool FeatureLearningPrototypes::loadInitialCodebook ( )
  194. {
  195. if ( b_loadInitialCodebook )
  196. {
  197. std::cerr << " INITIAL CODEBOOK ALREADY COMPUTED - RE-USE IT" << std::endl;
  198. std::cerr << " // WARNING - WE DO NOT VERIFY WHETHER THIS IS THE CORRECT CODEBOOK FOR THIS TRAINING SET!!!!" << std::endl;
  199. prototypes.clear();
  200. try
  201. {
  202. prototypes.read(cacheInitialCodebook);
  203. }
  204. catch (...)
  205. {
  206. std::cerr << "Error while loading initial codebook from " << cacheInitialCodebook << std::endl;
  207. return false;
  208. }
  209. return true;
  210. }
  211. else
  212. return false;
  213. }
  214. bool FeatureLearningPrototypes::writeInitialCodebook ( )
  215. {
  216. if ( b_saveInitialCodebook )
  217. {
  218. std::cerr << " SAVE INITIAL CODEBOOK " << std::endl;
  219. try
  220. {
  221. prototypes.write( cacheInitialCodebook );
  222. }
  223. catch (...)
  224. {
  225. std::cerr << "Error while saving initial codebook" << std::endl;
  226. return false;
  227. }
  228. return true;
  229. }
  230. else
  231. return false;
  232. }
  233. void FeatureLearningPrototypes::evaluateCurrentCodebookForGivenFeatures( const NICE::VVector & _features,
  234. const NICE::VVector & _positions,
  235. NICE::FloatImage & _noveltyImageGaussFiltered,
  236. NICE::FloatImage * _noveltyImage )
  237. {
  238. bool wasNoveltyImageGiven ( true );
  239. if ( _noveltyImage == NULL )
  240. {
  241. _noveltyImage = new FloatImage ( _noveltyImageGaussFiltered.width(), _noveltyImageGaussFiltered.height() );
  242. wasNoveltyImageGiven = false;
  243. }
  244. _noveltyImageGaussFiltered.set( 0.0 );
  245. _noveltyImage->set( 0.0 );
  246. NICE::VVector::const_iterator posIt = _positions.begin();
  247. for ( NICE::VVector::const_iterator i = _features.begin();
  248. i != _features.end();
  249. i++, posIt++)
  250. {
  251. //loop over codebook representatives
  252. double minDist ( std::numeric_limits<double>::max() );
  253. for (NICE::VVector::const_iterator it = prototypes.begin(); it != prototypes.end(); it++)
  254. {
  255. //compute distance
  256. double tmpDist ( this->distFunction->calculate(*i,*it) );
  257. if (tmpDist < minDist)
  258. minDist = tmpDist;
  259. }
  260. //take minimum distance and store in in a float image
  261. (*_noveltyImage) ( (*posIt)[0], (*posIt)[1] ) = minDist;
  262. }
  263. //gauss-filtering for nicer visualization
  264. float sigma ( 3.0 );
  265. FilterT<float, float, float> filter;
  266. filter.filterGaussSigmaApproximate ( *_noveltyImage, sigma, & _noveltyImageGaussFiltered );
  267. if ( ! wasNoveltyImageGiven )
  268. delete _noveltyImage;
  269. }
  270. //**********************************************
  271. //
  272. // PUBLIC METHODS
  273. //
  274. //**********************************************
  275. FeatureLearningPrototypes::FeatureLearningPrototypes ( const Config *_conf,
  276. const MultiDataset *_md, const std::string & _section )
  277. : FeatureLearningGeneric ( _conf, _section )
  278. {
  279. // define the initial number of clusters our codebook shall contain
  280. initialNumberOfClusters = conf->gI(section, "initialNumberOfClusters", 10);
  281. // define the clustering algorithm to be used
  282. std::string clusterAlgoString = conf->gS(section, "clusterAlgo", "kmeans");
  283. // define the distance function to be used
  284. std::string distFunctionString = conf->gS(section, "distFunction", "euclidian");
  285. //**********************************************
  286. //
  287. // SET UP VARIABLES AND METHODS
  288. // - FEATURE TYPE
  289. // - CLUSTERING ALGO
  290. // - DISTANCE FUNCTION
  291. // - ...
  292. //
  293. //**********************************************
  294. std::cerr << " SET UP VARIABLES AND METHODS " << std::endl;
  295. //feature extraction for initial codebook
  296. this->featureExtractor = NULL;
  297. this->setFeatureExtractor( true /* set for training */ );
  298. //clustering algorithm
  299. this->clusterAlgo = NULL;
  300. this->setClusterAlgo( clusterAlgoString );
  301. if (distFunctionString.compare("euclidian") == 0)
  302. {
  303. distFunction = new NICE::EuclidianDistance<double>();
  304. }
  305. else
  306. {
  307. std::cerr << "Unknown vector distance selected, use euclidian instead" << std::endl;
  308. distFunction = new NICE::EuclidianDistance<double>();
  309. }
  310. //run the training to initially compute a codebook and stuff like that
  311. this->train( _md );
  312. //so far, we have not seen any new image
  313. this->newImageCounter = 0;
  314. //TODO stupid
  315. this->maxValForVisualization = conf->gD( section, "stupidMaxValForVisualization", 0.005 ) ;
  316. //feature extraction for unseen images
  317. this->setFeatureExtractor( false /* set for training */ );
  318. }
  319. FeatureLearningPrototypes::~FeatureLearningPrototypes()
  320. {
  321. // clean-up
  322. if ( clusterAlgo != NULL )
  323. delete clusterAlgo;
  324. if ( distFunction != NULL )
  325. delete distFunction;
  326. if ( featureExtractor != NULL )
  327. delete featureExtractor;
  328. }
  329. NICE::FloatImage FeatureLearningPrototypes::evaluateCurrentCodebookByDistance ( const std::string & _filename , const bool & beforeComputingNewFeatures )
  330. {
  331. std::cerr << " VISUALIZATION ----- maxValForVisualization: " << maxValForVisualization << std::endl;
  332. NICE::ColorImage img( _filename );
  333. if ( b_showTrainingImages )
  334. {
  335. showImage( img, "Input" );
  336. }
  337. int xsize ( img.width() );
  338. int ysize ( img.height() );
  339. //variables to store feature information
  340. NICE::VVector features;
  341. NICE::VVector cfeatures;
  342. NICE::VVector positions;
  343. //compute features
  344. Globals::setCurrentImgFN ( _filename );
  345. featureExtractor->extractFeatures ( img, features, positions );
  346. //normalization
  347. for ( NICE::VVector::iterator i = features.begin();
  348. i != features.end();
  349. i++)
  350. {
  351. //normalization :)
  352. i->normalizeL1();
  353. }
  354. FloatImage noveltyImage ( xsize, ysize );
  355. FloatImage noveltyImageGaussFiltered ( xsize, ysize );
  356. this->evaluateCurrentCodebookForGivenFeatures( features, positions, noveltyImageGaussFiltered, &noveltyImage );
  357. double maxDist ( noveltyImage.max() );
  358. double maxFiltered ( noveltyImageGaussFiltered.max() );
  359. std::cerr << "maximum distance of Training images: " << maxDist << std::endl;
  360. std::cerr << "maximum distance of Training images after filtering: " << maxFiltered << std::endl;
  361. if ( beforeComputingNewFeatures )
  362. this->oldMaxDist = maxFiltered;
  363. //convert float to RGB
  364. NICE::ColorImage noveltyImageRGB ( xsize, ysize );
  365. if ( beforeComputingNewFeatures )
  366. {
  367. imageToPseudoColorWithRangeSpecification( noveltyImageGaussFiltered, noveltyImageRGB, 0 /* min */, maxValForVisualization /* maxFiltered*/ /* max */ );
  368. std::cerr << "set max value to: " << noveltyImageGaussFiltered.max() << std::endl;
  369. }
  370. else
  371. {
  372. imageToPseudoColorWithRangeSpecification( noveltyImageGaussFiltered, noveltyImageRGB, 0 /* min */, maxValForVisualization /*this->oldMaxDist*/ /* max */ );
  373. std::cerr << "set max value to: " << this->oldMaxDist << std::endl;
  374. }
  375. if ( b_showResults )
  376. showImage(noveltyImageRGB, "Novelty Image");
  377. else
  378. {
  379. std::vector< std::string > list2;
  380. StringTools::split ( _filename, '/', list2 );
  381. std::string destination ( s_resultdir + NICE::intToString(this->newImageCounter -1 ) + "_" + list2.back() + "_3_updatedNoveltyMap.ppm");
  382. if ( beforeComputingNewFeatures )
  383. destination = s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_0_initialNoveltyMap.ppm";
  384. noveltyImageRGB.writePPM( destination );
  385. }
  386. // now look where the closest features for the current cluster indices are
  387. int tmpProtCnt ( 0 );
  388. for (NICE::VVector::const_iterator protIt = prototypes.begin(); protIt != prototypes.end(); protIt++, tmpProtCnt++)
  389. {
  390. double distToCurrentCluster ( std::numeric_limits<double>::max() );
  391. int indexOfMostSimFeat( 0 );
  392. double tmpDist;
  393. int featureCnt ( 0 );
  394. for ( NICE::VVector::iterator i = features.begin();
  395. i != features.end();
  396. i++, featureCnt++)
  397. {
  398. tmpDist = this->distFunction->calculate( *i, *protIt );
  399. if ( tmpDist < distToCurrentCluster )
  400. {
  401. distToCurrentCluster = tmpDist;
  402. indexOfMostSimFeat = featureCnt;
  403. }
  404. }
  405. int posX ( ( positions[indexOfMostSimFeat] ) [0] );
  406. int posY ( ( positions[indexOfMostSimFeat] ) [1] );
  407. //position (for OpponentSIFT of van de Sande): x y scale orientation cornerness
  408. /*What is the interpretation of scale?
  409. The scale parameter was implemented to correspond with the Gaussian filter sigma at which points were detected. Therefore, the
  410. scale is not directly interpretable as the size of the region described in terms of number of pixels. However, it is linearly
  411. related the radius of the circular area described. To capture the area of the Gaussian originally used, we have a 3x
  412. magnification factor. But, remember that SIFT has 4x4 cells, and this is a measure for a single cell. So, because we are
  413. working with a radius, multiply by 2. Due to the square shape of the region, we need to extend the outer radius even further
  414. by sqrt(2), otherwise the corners of the outer cells are cut off by our circle. So, the largest outer radius is
  415. Round(scale * 3 * 2 * sqrt(2)). The area from which the SIFT descriptor is computed is a square which fits within a circle
  416. of this radius. Also, due to the Gaussian weighting applied within SIFT, the area that really matters is much, much smaller:
  417. the outer parts get a low weight.
  418. For the default scale of 1.2, we get a outer circle radius of 10. The potential sampling area then becomes -10..10, e.g. a
  419. 21x21patch. However, the square area which fits inside this circle is smaller: about 15x15. The corners of this 15x15square
  420. touch the outer circle. */
  421. /*Why is the direction (angle) field always 0?
  422. Estimating the dominant orientation of a descriptor is useful in matching scenarios. However, in an object/scene categorization
  423. setting, the additional invariance reduces accuracy. Being able to discriminate between dominant directions of up and right
  424. is very useful here, and rotated down images are quite rare in an object categorization setting. Therefore, orientation
  425. estimation is disabled in the color descriptor software. The subsequent rotation of the descriptor to achieve
  426. rotation-invariance is still possible by supplying your own regions and angles for an image (through --loadRegions). However,
  427. by default, no such rotation is performed, since the default angle is 0. */
  428. //adapt the pseudo color transformation as done in Convert.cpp
  429. size_t seg = ( size_t ) ( tmpProtCnt/(float)prototypes.size() * 6.0 );
  430. double y = ( 6 * tmpProtCnt/(float)prototypes.size() - seg );
  431. Color circleColor;
  432. switch ( seg ) {
  433. case 0:
  434. circleColor = Color( 0,0,(int)round(y*255) );
  435. break;
  436. case 1:
  437. circleColor = Color( 0,(int)round(y*255),255 );
  438. break;
  439. case 2:
  440. circleColor = Color( 0,255,(int)round((1-y)*255) );
  441. break;
  442. case 3:
  443. circleColor = Color( (int)round(y*255),255,0 );
  444. break;
  445. case 4:
  446. circleColor = Color( 255,(int)round((1-y)*255),0 );
  447. break;
  448. case 5:
  449. circleColor = Color( 255,(int)round(y*255),(int)round(y*255) );
  450. break;
  451. default:
  452. circleColor = Color( 255,255,255 );
  453. break;
  454. }
  455. NICE::Circle circ ( Coord( posX, posY), (int) round(2*3*sqrt(2)*( positions[indexOfMostSimFeat] )[2]) /* radius*/, circleColor );
  456. img.draw(circ);
  457. }
  458. if ( b_showResults )
  459. showImage(img, "Current image and most similar features for current prototypes");
  460. else
  461. {
  462. std::vector< std::string > list2;
  463. StringTools::split ( _filename, '/', list2 );
  464. std::string destination ( s_resultdir + NICE::intToString(this->newImageCounter-1) + "_" + list2.back() + "_3_updatedCurrentCluster.ppm");
  465. if ( beforeComputingNewFeatures )
  466. destination = s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_0_initialCurrentCluster.ppm";
  467. img.writePPM( destination );
  468. }
  469. return noveltyImageGaussFiltered;
  470. }
  471. NICE::ImageT< int > FeatureLearningPrototypes::evaluateCurrentCodebookByAssignments(const std::string& _filename, const bool& beforeComputingNewFeatures, const bool & _binaryShowLatestPrototype)
  472. {
  473. std::cerr << "evaluateCurrentCodebookByAssignments" << std::endl;
  474. NICE::ColorImage img( _filename );
  475. int xsize ( img.width() );
  476. int ysize ( img.height() );
  477. //variables to store feature information
  478. NICE::VVector features;
  479. NICE::VVector cfeatures;
  480. NICE::VVector positions;
  481. //compute features
  482. Globals::setCurrentImgFN ( _filename );
  483. featureExtractor->extractFeatures ( img, features, positions );
  484. //normalization
  485. for ( NICE::VVector::iterator i = features.begin();
  486. i != features.end();
  487. i++)
  488. {
  489. //normalization :)
  490. i->normalizeL1();
  491. }
  492. //this is the image we will return finally
  493. NICE::ImageT< int > clusterImage ( xsize, ysize );
  494. clusterImage.set ( 0 );
  495. // after iterating over all features from the new image, this vector contains
  496. // distances to the most similar feature for every prototype
  497. NICE::Vector minDistances ( this->prototypes.size() );
  498. NICE::VVector::const_iterator posIt = positions.begin();
  499. for ( NICE::VVector::const_iterator i = features.begin();
  500. i != features.end();
  501. i++, posIt++ )
  502. {
  503. //loop over codebook representatives
  504. double minDist ( std::numeric_limits<double>::max() );
  505. int indexOfNearestPrototype ( 0 );
  506. int prototypeCounter ( 0 );
  507. for (NICE::VVector::const_iterator it = this->prototypes.begin(); it != this->prototypes.end(); it++, prototypeCounter++)
  508. {
  509. //compute distance
  510. double tmpDist ( this->distFunction->calculate(*i,*it) );
  511. //check what the closest prototype is
  512. if (tmpDist < minDist)
  513. {
  514. minDist = tmpDist;
  515. indexOfNearestPrototype = prototypeCounter;
  516. }
  517. //check whether we found a feature for the current prototype which is more similar then the previous best one
  518. if ( minDistances[ prototypeCounter ] > tmpDist )
  519. minDistances[ prototypeCounter ] = tmpDist;
  520. }
  521. //take minimum distance and store in in a float image
  522. // for nice visualization, we plot the cluster index into a square of size 3 x 3
  523. //TODO currently hard coded!!!
  524. int noProtoTypes ( this->prototypes.size() -1 );
  525. for ( int tmpY = (*posIt)[1] - 1; tmpY < (*posIt)[1] + 1; tmpY++)
  526. {
  527. for ( int tmpX = (*posIt)[0] - 1; tmpX < (*posIt)[0] + 1; tmpX++)
  528. {
  529. if ( _binaryShowLatestPrototype )
  530. {
  531. //just a binary image - 1 if newest prototype is nearest - 0 if not
  532. if ( indexOfNearestPrototype == noProtoTypes)
  533. clusterImage ( tmpX, tmpY ) = 1;
  534. else
  535. clusterImage ( tmpX, tmpY ) = 0;
  536. }
  537. else
  538. //as many different values as current prototypes available
  539. clusterImage ( tmpX, tmpY ) = indexOfNearestPrototype;
  540. }
  541. }
  542. }
  543. std::cerr << "Codebook evaluation by assignments... min distances in image for every prototype: " << std::endl << " " << minDistances << std::endl;
  544. //show how many clusters we have
  545. if ( !_binaryShowLatestPrototype )
  546. {
  547. int tmpCnt ( 0 );
  548. for (NICE::VVector::const_iterator protoIt = prototypes.begin(); protoIt != prototypes.end(); protoIt++, tmpCnt++)
  549. {
  550. for ( int tmpY = 1 + 2 - 2; tmpY < (2 + 2); tmpY++)
  551. {
  552. for ( int tmpX = 1 + 4*tmpCnt ; tmpX < (1 + 4*tmpCnt + 3); tmpX++)
  553. {
  554. //Take care, this might go "over" the image
  555. clusterImage ( tmpX, tmpY ) = (Ipp8u) tmpCnt;
  556. }
  557. }
  558. }
  559. }
  560. return clusterImage;
  561. }
  562. void FeatureLearningPrototypes::evaluateCurrentCodebookByConfusionMatrix( NICE::Matrix & _confusionMat )
  563. {
  564. _confusionMat.resize ( this->prototypes.size(), this->prototypes.size() );
  565. _confusionMat.set( 0.0 );
  566. double tmpDist ( 0.0 );
  567. NICE::VVector::const_iterator protoItJ = prototypes.begin();
  568. for ( int j = 0; j < prototypes.size(); j++, protoItJ++)
  569. {
  570. NICE::VVector::const_iterator protoItI = protoItJ;
  571. for ( int i = j; i < prototypes.size(); i++, protoItI++)
  572. {
  573. tmpDist = this->distFunction->calculate( *protoItJ, *protoItI );
  574. //assuming symmetric distances
  575. _confusionMat ( i, j ) = tmpDist;
  576. // if ( i != j )
  577. // _confusionMat ( j, i ) = tmpDist;
  578. }
  579. }
  580. }
  581. NICE::VVector * FeatureLearningPrototypes::getCurrentCodebook()
  582. {
  583. return &(this->prototypes);
  584. }