FeatureLearningRegionBased.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. #include "FeatureLearningRegionBased.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/vector/VectorT.h>
  9. #include <segmentation/GenericRegionSegmentationMethodSelection.h>
  10. //vislearning
  11. #include <vislearning/baselib/Globals.h>
  12. using namespace std;
  13. using namespace NICE;
  14. using namespace OBJREC;
  15. //**********************************************
  16. //
  17. // PROTECTED METHODS
  18. //
  19. //**********************************************
  20. //**********************************************
  21. //
  22. // PUBLIC METHODS
  23. //
  24. //**********************************************
  25. FeatureLearningRegionBased::FeatureLearningRegionBased ( const Config *_conf,
  26. const MultiDataset *_md, const std::string & _section )
  27. : FeatureLearningPrototypes ( _conf, _md, _section )
  28. {
  29. //save and read segmentation results from files
  30. this->reuseSegmentation = conf->gB ( "FPCPixel", "reuseSegmentation", true );
  31. // select your segmentation method here
  32. // currently, the following options are supported: "MarkovCluster", "GraphBased", "MeanShift", "SLIC"
  33. string rsMethode = conf->gS ( section, "segmentationMethod", "MeanShift" );
  34. OBJREC::RegionSegmentationMethod *tmpRegionSeg = OBJREC::GenericRegionSegmentationMethodSelection::selectRegionSegmentationMethod(conf, rsMethode);
  35. if ( reuseSegmentation )
  36. this->segmentationAlgo = new RSCache ( conf, tmpRegionSeg );
  37. else
  38. this->segmentationAlgo = tmpRegionSeg;
  39. this->i_gridSize = conf->gI( "LFColorSandeTest" , "grid" , 5 );
  40. }
  41. FeatureLearningRegionBased::~FeatureLearningRegionBased()
  42. {
  43. // clean-up
  44. }
  45. void FeatureLearningRegionBased::learnNewFeatures ( const std::string & _filename )
  46. {
  47. NICE::ColorImage img( _filename );
  48. int xsize ( img.width() );
  49. int ysize ( img.height() );
  50. //variables to store feature information
  51. NICE::VVector newFeatures;
  52. NICE::VVector cfeatures;
  53. NICE::VVector positions;
  54. //compute features
  55. std::cerr << " EXTRACT FEATURES FROM UNSEEN IMAGE" << std::endl;
  56. Globals::setCurrentImgFN ( _filename );
  57. featureExtractor->extractFeatures ( img, newFeatures, positions );
  58. //normalization :)
  59. for ( NICE::VVector::iterator i = newFeatures.begin();
  60. i != newFeatures.end();
  61. i++)
  62. {
  63. i->normalizeL1();
  64. }
  65. //compute region segmentation
  66. std::cerr << " COMPUTE REGION SEGMENTATION" << std::endl;
  67. NICE::Matrix mask;
  68. int amountRegions = segmentationAlgo->segRegions ( img, mask );
  69. //compute novelty scores on a feature level
  70. std::cerr << " COMPUTE NOVELTY SCORES ON A FEATURE LEVEL" << std::endl;
  71. FloatImage noveltyImageGaussFiltered ( xsize, ysize );
  72. this->evaluateCurrentCodebookForGivenFeatures( newFeatures, positions, noveltyImageGaussFiltered );
  73. // compute scores for every region
  74. std::cerr << " COMPUTE SCORES FOR EVERY REGION" << std::endl;
  75. std::vector<double> regionNoveltyMeasure (amountRegions, 0.0);
  76. std::vector<int> regionSize (amountRegions, 0);
  77. for ( int y = 0; y < ysize; y += i_gridSize) //y++)
  78. {
  79. for (int x = 0; x < xsize; x += i_gridSize) //x++)
  80. {
  81. int r = mask(x,y);
  82. regionSize[r]++;
  83. //count the amount of "novelty" for the corresponding region
  84. regionNoveltyMeasure[r] += noveltyImageGaussFiltered(x,y);
  85. }
  86. }
  87. //loop over all regions and compute averaged novelty scores
  88. //NOTE this might be unuseful, since lateron we combine novelty score and region size (e.g. by multiplying)
  89. // however, we do not want to settle the combination in adavance
  90. for(int r = 0; r < amountRegions; r++)
  91. {
  92. regionNoveltyMeasure[r] /= regionSize[r];
  93. }
  94. //a new region should cover at least 3% of the image for not being penalized
  95. double d_minimalImageAmountForAcceptableRegions ( 0.03 );
  96. int minimalImageAmountForAcceptableRegions ( round( d_minimalImageAmountForAcceptableRegions * (xsize/i_gridSize) * (ysize/i_gridSize) ) );
  97. std::cerr << "minimalImageAmountForAcceptableRegions: " << minimalImageAmountForAcceptableRegions << std::endl;
  98. //compute final scores for all regions
  99. NICE::Vector regionScores ( amountRegions, 0.0 );
  100. std::cerr << "used region sizes for computation: " << std::endl;
  101. for(int r = 0; r < amountRegions; r++)
  102. {
  103. regionScores[r] = std::min( regionSize[r], minimalImageAmountForAcceptableRegions ) * regionNoveltyMeasure[r];
  104. std::cerr << " " << std::min( regionSize[r], minimalImageAmountForAcceptableRegions );
  105. }
  106. std::cerr << std::endl << std::endl;
  107. int indexOfBestRegion ( regionScores.MaxIndex() );
  108. ////////////////////////////////////
  109. //
  110. // VISUALIZE REGION SCORES
  111. //
  112. ////////////////////////////////////
  113. NICE::FloatImage regionScoreImage ( xsize, ysize );
  114. NICE::FloatImage regionNoveltyImage ( xsize, ysize ); //contains novelty score averaged over region
  115. NICE::FloatImage regionRelevanceImage ( xsize, ysize ); //contains higher scores for larger regions (but with upper limit)
  116. regionScoreImage.set( 0.0 );
  117. regionNoveltyImage.set( 0.0 );
  118. regionRelevanceImage.set( 0.0 );
  119. for ( int y = 0; y < ysize; y++)
  120. {
  121. for (int x = 0; x < xsize; x++)
  122. {
  123. int r = mask(x,y);
  124. regionNoveltyImage(x,y) = regionNoveltyMeasure[r];
  125. regionRelevanceImage(x,y) = regionSize[r];
  126. regionScoreImage(x,y) = regionScores[r];
  127. }
  128. }
  129. std::cerr << "highest region score: " << regionScoreImage.max()<< " -- smallest region score: " << regionScoreImage.min() << std::endl;
  130. std::cerr << "highest region novelty score: " << regionNoveltyImage.max() << " -- smallest region novelty score: " << regionNoveltyImage.min() << std::endl;
  131. NICE::ColorImage regionScoreImageRGB ( xsize, ysize );
  132. NICE::ColorImage regionNoveltyScoreImageRGB ( xsize, ysize );
  133. NICE::ColorImage regionRelevanceScoreImageRGB ( xsize, ysize );
  134. //TODO properly specify the maximum value for score visualization here :)
  135. imageToPseudoColorWithRangeSpecification( regionScoreImage, regionScoreImageRGB, 0 /* min */, 2.2 /* max */ );
  136. imageToPseudoColorWithRangeSpecification( regionNoveltyImage, regionNoveltyScoreImageRGB, 0 /* min */, 0.012 /* max */ );
  137. imageToPseudoColorWithRangeSpecification( regionRelevanceImage, regionRelevanceScoreImageRGB, 0 /* min */, minimalImageAmountForAcceptableRegions /* max */ );
  138. if ( b_showResults )
  139. showImage(regionScoreImageRGB, "Current (new) image with region scores");
  140. else
  141. {
  142. std::vector< std::string > list2;
  143. StringTools::split ( _filename, '/', list2 );
  144. //write novelty score image
  145. std::string destinationNovelty ( s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_1_1_regionNoveltyScores.ppm");
  146. regionNoveltyScoreImageRGB.writePPM( destinationNovelty );
  147. //write relevance score image
  148. std::string destinationRelevance ( s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_1_2_regionRelevanceScores.ppm");
  149. regionRelevanceScoreImageRGB.writePPM( destinationRelevance );
  150. //write image with final scores for region
  151. std::string destination ( s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_1_3_regionScores.ppm");
  152. regionScoreImageRGB.writePPM( destination );
  153. }
  154. //compute representative for best region
  155. NICE::Vector representative ( newFeatures.begin()->size(), 0.0 );
  156. // //first try: average feature vectors of the "best" region
  157. // NICE::VVector::const_iterator posIt = positions.begin();
  158. // for ( NICE::VVector::const_iterator featIt = newFeatures.begin();
  159. // featIt != newFeatures.end();
  160. // featIt++, posIt++)
  161. // {
  162. //
  163. // //only considere features that actually belong to the best region
  164. // if ( mask( (*posIt)[0], (*posIt)[1] ) != indexOfBestRegion )
  165. // continue;
  166. //
  167. // representative += *featIt;
  168. // }
  169. //
  170. // //simple mean feature vector
  171. // representative /= regionSize[indexOfBestRegion];
  172. // //normalization
  173. // representative.normalizeL1();
  174. // //second try: simply take the first feature vector of the "best" region (although this one should lay on the border, and so on...)
  175. // NICE::VVector::const_iterator posIt = positions.begin();
  176. // for ( NICE::VVector::const_iterator featIt = newFeatures.begin();
  177. // featIt != newFeatures.end();
  178. // featIt++, posIt++)
  179. // {
  180. //
  181. // //only considere features that actually belong to the best region
  182. // if ( mask( (*posIt)[0], (*posIt)[1] ) != indexOfBestRegion )
  183. // continue;
  184. //
  185. // representative = *featIt;
  186. // i_posXOfNewPrototype = (*posIt)[0];
  187. // i_posYOfNewPrototype = (*posIt)[1];
  188. // //break after the first positive feature
  189. // break;
  190. // }
  191. //third try: simply take the feature vector of the "best" region with largest novelty score within this region
  192. // ... (hopefully, this is no outlier wrt to this region...)
  193. double maxNovelty ( 0.0 );
  194. NICE::VVector::const_iterator mostNovelFeature = newFeatures.begin() ;
  195. NICE::VVector::const_iterator posIt = positions.begin();
  196. for ( NICE::VVector::const_iterator featIt = newFeatures.begin();
  197. featIt != newFeatures.end();
  198. featIt++, posIt++)
  199. {
  200. //only considere features that actually belong to the best region
  201. if ( mask( (*posIt)[0], (*posIt)[1] ) != indexOfBestRegion )
  202. continue;
  203. //did we found a feature of the "best"region with larger novelty score then the current most novel one?
  204. if ( noveltyImageGaussFiltered( (*posIt)[0], (*posIt)[1] ) > maxNovelty )
  205. {
  206. maxNovelty = noveltyImageGaussFiltered( (*posIt)[0], (*posIt)[1] );
  207. mostNovelFeature = featIt;
  208. i_posXOfNewPrototype = (*posIt)[0];
  209. i_posYOfNewPrototype = (*posIt)[1];
  210. }
  211. }
  212. representative = *mostNovelFeature;
  213. std::cerr << " New representative: " << std::endl << representative << std::endl;
  214. //include the chosen information into the currently used prototypes
  215. prototypes.push_back( representative );
  216. if ( b_evaluationWhileFeatureLearning )
  217. {
  218. NICE::ColorImage imgTmp( _filename );
  219. double distToNewCluster ( std::numeric_limits<double>::max() );
  220. int indexOfMostSimFeat( 0 );
  221. double tmpDist;
  222. int tmpCnt ( 0 );
  223. for ( NICE::VVector::iterator i = newFeatures.begin();
  224. i != newFeatures.end();
  225. i++, tmpCnt++)
  226. {
  227. tmpDist = this->distFunction->calculate( *i, representative );
  228. if ( tmpDist < distToNewCluster )
  229. {
  230. distToNewCluster = tmpDist;
  231. indexOfMostSimFeat = tmpCnt;
  232. }
  233. }
  234. std::cerr << "** minDist to new cluster: " <<distToNewCluster << std::endl;
  235. int posX ( ( positions[indexOfMostSimFeat] ) [0] );
  236. int posY ( ( positions[indexOfMostSimFeat] ) [1] );
  237. std::cerr << "position of most similar feature --- posX: " << posX << " - posY " << posY << std::endl;
  238. std::cerr << "position of new prototype --- posX: " << i_posXOfNewPrototype << " - posY " << i_posYOfNewPrototype << std::endl;
  239. NICE::Circle circ ( Coord( posX, posY), 10 /* radius*/, Color(200,0,255) );
  240. imgTmp.draw(circ);
  241. if ( b_showResults )
  242. showImage(imgTmp, "Current (new) image and most similar feature for new cluster");
  243. else
  244. {
  245. std::vector< std::string > list2;
  246. StringTools::split ( _filename, '/', list2 );
  247. std::string destination ( s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_2_bestNewCluster.ppm");
  248. imgTmp.writePPM( destination );
  249. }
  250. }
  251. //this was a new image, so we increase our internal counter
  252. (this->newImageCounter)++;
  253. }