123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- #include "FeatureLearningRegionBased.h"
- //STL
- #include <iostream>
- //core
- #include <core/image/FilterT.h>
- #include <core/image/CircleT.h>
- #include <core/image/Convert.h>
- #include <core/vector/VectorT.h>
- #include <segmentation/GenericRegionSegmentationMethodSelection.h>
- //vislearning
- #include <vislearning/baselib/Globals.h>
- using namespace std;
- using namespace NICE;
- using namespace OBJREC;
- //**********************************************
- //
- // PROTECTED METHODS
- //
- //**********************************************
- //**********************************************
- //
- // PUBLIC METHODS
- //
- //**********************************************
- FeatureLearningRegionBased::FeatureLearningRegionBased ( const Config *_conf,
- const MultiDataset *_md, const std::string & _section )
- : FeatureLearningPrototypes ( _conf, _md, _section )
- {
- //save and read segmentation results from files
- this->reuseSegmentation = conf->gB ( "FPCPixel", "reuseSegmentation", true );
-
- // select your segmentation method here
- // currently, the following options are supported: "MarkovCluster", "GraphBased", "MeanShift", "SLIC"
- string rsMethode = conf->gS ( section, "segmentationMethod", "MeanShift" );
-
- OBJREC::RegionSegmentationMethod *tmpRegionSeg = OBJREC::GenericRegionSegmentationMethodSelection::selectRegionSegmentationMethod(conf, rsMethode);
-
- if ( reuseSegmentation )
- this->segmentationAlgo = new RSCache ( conf, tmpRegionSeg );
- else
- this->segmentationAlgo = tmpRegionSeg;
-
- this->i_gridSize = conf->gI( "LFColorSandeTest" , "grid" , 5 );
- }
- FeatureLearningRegionBased::~FeatureLearningRegionBased()
- {
- // clean-up
- }
- void FeatureLearningRegionBased::learnNewFeatures ( const std::string & _filename )
- {
- NICE::ColorImage img( _filename );
-
- int xsize ( img.width() );
- int ysize ( img.height() );
-
- //variables to store feature information
- NICE::VVector newFeatures;
- NICE::VVector cfeatures;
- NICE::VVector positions;
- //compute features
- std::cerr << " EXTRACT FEATURES FROM UNSEEN IMAGE" << std::endl;
- Globals::setCurrentImgFN ( _filename );
- featureExtractor->extractFeatures ( img, newFeatures, positions );
-
- //normalization :)
- for ( NICE::VVector::iterator i = newFeatures.begin();
- i != newFeatures.end();
- i++)
- {
- i->normalizeL1();
- }
-
- //compute region segmentation
- std::cerr << " COMPUTE REGION SEGMENTATION" << std::endl;
- NICE::Matrix mask;
- int amountRegions = segmentationAlgo->segRegions ( img, mask );
-
- //compute novelty scores on a feature level
- std::cerr << " COMPUTE NOVELTY SCORES ON A FEATURE LEVEL" << std::endl;
- FloatImage noveltyImageGaussFiltered ( xsize, ysize );
- this->evaluateCurrentCodebookForGivenFeatures( newFeatures, positions, noveltyImageGaussFiltered );
-
- // compute scores for every region
- std::cerr << " COMPUTE SCORES FOR EVERY REGION" << std::endl;
- std::vector<double> regionNoveltyMeasure (amountRegions, 0.0);
- std::vector<int> regionSize (amountRegions, 0);
-
- for ( int y = 0; y < ysize; y += i_gridSize) //y++)
- {
- for (int x = 0; x < xsize; x += i_gridSize) //x++)
- {
- int r = mask(x,y);
- regionSize[r]++;
- //count the amount of "novelty" for the corresponding region
- regionNoveltyMeasure[r] += noveltyImageGaussFiltered(x,y);
- }
- }
-
- //loop over all regions and compute averaged novelty scores
- //NOTE this might be unuseful, since lateron we combine novelty score and region size (e.g. by multiplying)
- // however, we do not want to settle the combination in adavance
- for(int r = 0; r < amountRegions; r++)
- {
- regionNoveltyMeasure[r] /= regionSize[r];
- }
- //a new region should cover at least 3% of the image for not being penalized
- double d_minimalImageAmountForAcceptableRegions ( 0.03 );
- int minimalImageAmountForAcceptableRegions ( round( d_minimalImageAmountForAcceptableRegions * (xsize/i_gridSize) * (ysize/i_gridSize) ) );
-
- std::cerr << "minimalImageAmountForAcceptableRegions: " << minimalImageAmountForAcceptableRegions << std::endl;
-
- //compute final scores for all regions
- NICE::Vector regionScores ( amountRegions, 0.0 );
- std::cerr << "used region sizes for computation: " << std::endl;
- for(int r = 0; r < amountRegions; r++)
- {
- regionScores[r] = std::min( regionSize[r], minimalImageAmountForAcceptableRegions ) * regionNoveltyMeasure[r];
- std::cerr << " " << std::min( regionSize[r], minimalImageAmountForAcceptableRegions );
- }
- std::cerr << std::endl << std::endl;
-
- int indexOfBestRegion ( regionScores.MaxIndex() );
-
-
- ////////////////////////////////////
- //
- // VISUALIZE REGION SCORES
- //
- ////////////////////////////////////
-
- NICE::FloatImage regionScoreImage ( xsize, ysize );
- NICE::FloatImage regionNoveltyImage ( xsize, ysize ); //contains novelty score averaged over region
- NICE::FloatImage regionRelevanceImage ( xsize, ysize ); //contains higher scores for larger regions (but with upper limit)
-
- regionScoreImage.set( 0.0 );
- regionNoveltyImage.set( 0.0 );
- regionRelevanceImage.set( 0.0 );
-
- for ( int y = 0; y < ysize; y++)
- {
- for (int x = 0; x < xsize; x++)
- {
- int r = mask(x,y);
- regionNoveltyImage(x,y) = regionNoveltyMeasure[r];
- regionRelevanceImage(x,y) = regionSize[r];
- regionScoreImage(x,y) = regionScores[r];
- }
- }
-
- std::cerr << "highest region score: " << regionScoreImage.max()<< " -- smallest region score: " << regionScoreImage.min() << std::endl;
- std::cerr << "highest region novelty score: " << regionNoveltyImage.max() << " -- smallest region novelty score: " << regionNoveltyImage.min() << std::endl;
-
- NICE::ColorImage regionScoreImageRGB ( xsize, ysize );
- NICE::ColorImage regionNoveltyScoreImageRGB ( xsize, ysize );
- NICE::ColorImage regionRelevanceScoreImageRGB ( xsize, ysize );
- //TODO properly specify the maximum value for score visualization here :)
- imageToPseudoColorWithRangeSpecification( regionScoreImage, regionScoreImageRGB, 0 /* min */, 2.2 /* max */ );
- imageToPseudoColorWithRangeSpecification( regionNoveltyImage, regionNoveltyScoreImageRGB, 0 /* min */, 0.012 /* max */ );
- imageToPseudoColorWithRangeSpecification( regionRelevanceImage, regionRelevanceScoreImageRGB, 0 /* min */, minimalImageAmountForAcceptableRegions /* max */ );
- if ( b_showResults )
- {
- showImage(regionNoveltyScoreImageRGB, "Current (new) image with region NOVELTY scores");
- showImage(regionRelevanceScoreImageRGB, "Current (new) image with region RELEVANCE scores");
- showImage(regionScoreImageRGB, "Current (new) image with FINAL region scores");
- }
- else
- {
- std::vector< std::string > list2;
- StringTools::split ( _filename, '/', list2 );
-
- //write novelty score image
- std::string destinationNovelty ( s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_1_1_regionNoveltyScores.ppm");
- regionNoveltyScoreImageRGB.writePPM( destinationNovelty );
-
- //write relevance score image
- std::string destinationRelevance ( s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_1_2_regionRelevanceScores.ppm");
- regionRelevanceScoreImageRGB.writePPM( destinationRelevance );
- //write image with final scores for region
- std::string destination ( s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_1_3_regionScores.ppm");
- regionScoreImageRGB.writePPM( destination );
- }
-
-
- //compute representative for best region
-
- NICE::Vector representative ( newFeatures.begin()->size(), 0.0 );
-
- // //FIRST TRY: average feature vectors of the "best" region
- // NICE::VVector::const_iterator posIt = positions.begin();
- // for ( NICE::VVector::const_iterator featIt = newFeatures.begin();
- // featIt != newFeatures.end();
- // featIt++, posIt++)
- // {
- //
- // //only considere features that actually belong to the best region
- // if ( mask( (*posIt)[0], (*posIt)[1] ) != indexOfBestRegion )
- // continue;
- //
- // representative += *featIt;
- // }
- //
- // //simple mean feature vector
- // representative /= regionSize[indexOfBestRegion];
- // //normalization
- // representative.normalizeL1();
-
- // //SECOND TRY: simply take the first feature vector of the "best" region (although this one should lay on the border, and so on...)
- // NICE::VVector::const_iterator posIt = positions.begin();
- // for ( NICE::VVector::const_iterator featIt = newFeatures.begin();
- // featIt != newFeatures.end();
- // featIt++, posIt++)
- // {
- //
- // //only considere features that actually belong to the best region
- // if ( mask( (*posIt)[0], (*posIt)[1] ) != indexOfBestRegion )
- // continue;
- //
- // representative = *featIt;
- // i_posXOfNewPrototype = (*posIt)[0];
- // i_posYOfNewPrototype = (*posIt)[1];
- // //break after the first positive feature
- // break;
- // }
-
- //THIRD TRY: simply take the feature vector of the "best" region with largest novelty score within this region
- // ... (hopefully, this is no outlier wrt to this region...)
-
- double maxNovelty ( 0.0 );
- NICE::VVector::const_iterator mostNovelFeature = newFeatures.begin() ;
-
- NICE::VVector::const_iterator posIt = positions.begin();
- for ( NICE::VVector::const_iterator featIt = newFeatures.begin();
- featIt != newFeatures.end();
- featIt++, posIt++)
- {
-
- //only considere features that actually belong to the best region
- if ( mask( (*posIt)[0], (*posIt)[1] ) != indexOfBestRegion )
- continue;
-
- //did we found a feature of the "best"region with larger novelty score then the current most novel one?
- if ( noveltyImageGaussFiltered( (*posIt)[0], (*posIt)[1] ) > maxNovelty )
- {
- maxNovelty = noveltyImageGaussFiltered( (*posIt)[0], (*posIt)[1] );
- mostNovelFeature = featIt;
- i_posXOfNewPrototype = (*posIt)[0];
- i_posYOfNewPrototype = (*posIt)[1];
- }
- }
- representative = *mostNovelFeature;
-
- std::cerr << " New representative: " << std::endl << representative << std::endl;
-
- //include the chosen information into the currently used prototypes
- prototypes.push_back( representative );
-
- if ( b_evaluationWhileFeatureLearning )
- {
-
- NICE::ColorImage imgTmp( _filename );
-
- double distToNewCluster ( std::numeric_limits<double>::max() );
- int indexOfMostSimFeat( 0 );
- double tmpDist;
- int tmpCnt ( 0 );
-
- for ( NICE::VVector::iterator i = newFeatures.begin();
- i != newFeatures.end();
- i++, tmpCnt++)
- {
- tmpDist = this->distFunction->calculate( *i, representative );
- if ( tmpDist < distToNewCluster )
- {
- distToNewCluster = tmpDist;
- indexOfMostSimFeat = tmpCnt;
- }
- }
-
- std::cerr << "** minDist to new cluster: " <<distToNewCluster << std::endl;
-
- int posX ( ( positions[indexOfMostSimFeat] ) [0] );
- int posY ( ( positions[indexOfMostSimFeat] ) [1] );
-
- std::cerr << "position of most similar feature --- posX: " << posX << " - posY " << posY << std::endl;
- std::cerr << "position of new prototype --- posX: " << i_posXOfNewPrototype << " - posY " << i_posYOfNewPrototype << std::endl;
- NICE::Circle circ ( Coord( posX, posY), 10 /* radius*/, Color(200,0,255) );
- imgTmp.draw(circ);
-
- if ( b_showResults )
- showImage(imgTmp, "Current (new) image and most similar feature for new cluster");
- else
- {
- std::vector< std::string > list2;
- StringTools::split ( _filename, '/', list2 );
- std::string destination ( s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_2_bestNewCluster.ppm");
- imgTmp.writePPM( destination );
- }
- }
-
- //this was a new image, so we increase our internal counter
- (this->newImageCounter)++;
- }
|