浏览代码

Merge branch 'master' of /home/dbv/git/nice.git/vislearning into cmake

Conflicts:
	classifier/vclassifier/VCNearestNeighbour.cpp
	features/simplefeatures/CodebookPrototypes.cpp
	math/pdf/tests/TestPDF.cpp
Johannes Ruehle 11 年之前
父节点
当前提交
a4de671279
共有 98 个文件被更改,包括 10148 次插入1798 次删除
  1. 15 0
      cbaselib/ClassificationResults.cpp
  2. 3 0
      cbaselib/ClassificationResults.h
  3. 22 0
      cbaselib/LabeledSet.cpp
  4. 5 0
      cbaselib/LabeledSet.h
  5. 40 3
      cbaselib/MultiDataset.cpp
  6. 6 0
      classifier/classifierbase/FeaturePoolClassifier.cpp
  7. 3 0
      classifier/classifierbase/FeaturePoolClassifier.h
  8. 7 0
      classifier/classifierbase/VecClassifier.h
  9. 249 0
      classifier/fpclassifier/FPCGPHIK.cpp
  10. 99 0
      classifier/fpclassifier/FPCGPHIK.h
  11. 3 1
      classifier/fpclassifier/libdepend.inc
  12. 89 0
      classifier/fpclassifier/tests/Makefile.inc
  13. 536 0
      classifier/fpclassifier/tests/TestFPCGPHIK.cpp
  14. 31 0
      classifier/fpclassifier/tests/TestFPCGPHIK.h
  15. 二进制
      classifier/fpclassifier/tests/sparse20x30matrixM.mat
  16. 二进制
      classifier/fpclassifier/tests/sparse3x3matrixA.mat
  17. 42 0
      classifier/fpclassifier/tests/toyExample1.data
  18. 9 0
      classifier/fpclassifier/tests/toyExample2.data
  19. 1502 0
      classifier/fpclassifier/tests/toyExampleLargeLargeScale.data
  20. 604 0
      classifier/fpclassifier/tests/toyExampleLargeScale.data
  21. 46 18
      classifier/genericClassifierSelection.h
  22. 317 317
      classifier/kernelclassifier/KCGPRegOneVsAll.cpp
  23. 2 2
      classifier/kernelclassifier/progs/libdepend.inc
  24. 56 33
      classifier/vclassifier/VCNearestNeighbour.cpp
  25. 1 0
      classifier/vclassifier/VCNearestNeighbour.h
  26. 296 0
      featureLearning/FeatureLearningClusterBased.cpp
  27. 69 0
      featureLearning/FeatureLearningClusterBased.h
  28. 43 0
      featureLearning/FeatureLearningGeneric.cpp
  29. 130 0
      featureLearning/FeatureLearningGeneric.h
  30. 707 0
      featureLearning/FeatureLearningPrototypes.cpp
  31. 127 0
      featureLearning/FeatureLearningPrototypes.h
  32. 324 0
      featureLearning/FeatureLearningRegionBased.cpp
  33. 73 0
      featureLearning/FeatureLearningRegionBased.h
  34. 8 0
      featureLearning/Makefile
  35. 103 0
      featureLearning/Makefile.inc
  36. 6 0
      featureLearning/libdepend.inc
  37. 8 0
      featureLearning/progs/Makefile
  38. 88 0
      featureLearning/progs/Makefile.inc
  39. 6 0
      featureLearning/progs/libdepend.inc
  40. 346 0
      featureLearning/progs/testFeatureLearning.cpp
  41. 158 58
      features/localfeatures/GenericLFSelection.h
  42. 4 0
      features/localfeatures/GenericLocalFeatureSelection.h
  43. 16 14
      features/localfeatures/IDRandomSampling.h
  44. 7 3
      features/localfeatures/LFColorSande.cpp
  45. 49 308
      features/localfeatures/LFColorWeijer.cpp
  46. 4 60
      features/localfeatures/LFColorWeijer.h
  47. 29 27
      features/localfeatures/LFGenericLocal.h
  48. 5 4
      features/localfeatures/LFReadCache.cpp
  49. 69 63
      features/localfeatures/LFReadCache.h
  50. 2 0
      features/localfeatures/LFReadCache.tcc
  51. 5 4
      features/localfeatures/LFWriteCache.cpp
  52. 55 50
      features/localfeatures/LFWriteCache.h
  53. 27 24
      features/localfeatures/LocalFeature.h
  54. 14 12
      features/localfeatures/LocalFeatureLFInterface.cpp
  55. 44 41
      features/localfeatures/LocalFeatureLFInterface.h
  56. 8 2
      features/localfeatures/LocalFeatureRepresentation.h
  57. 1 1
      features/localfeatures/libdepend.inc
  58. 38 4
      features/localfeatures/progs/testColorWeijer.cpp
  59. 142 0
      features/simplefeatures/BoWFeatureConverter.cpp
  60. 101 0
      features/simplefeatures/BoWFeatureConverter.h
  61. 106 28
      features/simplefeatures/Codebook.cpp
  62. 160 64
      features/simplefeatures/Codebook.h
  63. 107 59
      features/simplefeatures/CodebookPrototypes.cpp
  64. 60 31
      features/simplefeatures/CodebookPrototypes.h
  65. 20 20
      math/cluster/ClusterAlgorithm.h
  66. 6 6
      math/cluster/GMM.cpp
  67. 0 1
      math/cluster/GMM.h
  68. 15 13
      math/cluster/GSCluster.cpp
  69. 25 16
      math/cluster/GSCluster.h
  70. 94 0
      math/cluster/GenericClusterAlgorithmSelection.h
  71. 256 241
      math/cluster/KMeans.cpp
  72. 99 39
      math/cluster/KMeans.h
  73. 17 9
      math/cluster/KMeansHeuristic.cpp
  74. 37 26
      math/cluster/KMeansHeuristic.h
  75. 18 18
      math/cluster/KMeansMatlab.cpp
  76. 55 46
      math/cluster/KMeansMatlab.h
  77. 430 0
      math/cluster/KMedian.cpp
  78. 131 0
      math/cluster/KMedian.h
  79. 157 0
      math/cluster/RandomClustering.cpp
  80. 112 0
      math/cluster/RandomClustering.h
  81. 118 93
      math/cluster/SpectralCluster.cpp
  82. 47 38
      math/cluster/SpectralCluster.h
  83. 89 0
      math/cluster/tests/Makefile.inc
  84. 89 0
      math/cluster/tests/TestKMedian.cpp
  85. 32 0
      math/cluster/tests/TestKMedian.h
  86. 8 0
      noveltyDetection/Makefile
  87. 103 0
      noveltyDetection/Makefile.inc
  88. 72 0
      noveltyDetection/NDCodebookLevelImagePooling.cpp
  89. 97 0
      noveltyDetection/NDCodebookLevelImagePooling.h
  90. 24 0
      noveltyDetection/NoveltyDetector.cpp
  91. 84 0
      noveltyDetection/NoveltyDetector.h
  92. 230 0
      noveltyDetection/NoveltyDetectorCodebookLevel.cpp
  93. 125 0
      noveltyDetection/NoveltyDetectorCodebookLevel.h
  94. 6 0
      noveltyDetection/libdepend.inc
  95. 8 0
      noveltyDetection/progs/Makefile
  96. 5 0
      noveltyDetection/progs/libdepend.inc
  97. 303 0
      progs/evaluateCompleteBoWPipeline.cpp
  98. 4 1
      progs/libdepend.inc

+ 15 - 0
cbaselib/ClassificationResults.cpp

@@ -102,3 +102,18 @@ double ClassificationResults::getAverageRecognitionRate() const
   confusion.normalizeColumnsL1();
   return confusion.trace()/confusion.rows();  
 }
+
+double ClassificationResults::getOverallRecognitionRate() const
+{
+  const_iterator i = begin();
+  NICE::Matrix confusion ( i->scores.size(),i->scores.size(),0.0 );
+
+  for ( ; i != end(); i++ )
+  {
+    const ClassificationResult & r = *i;
+    uint classno_estimated = r.classno;
+    uint classno_groundtruth = r.classno_groundtruth;
+    confusion( classno_estimated, classno_groundtruth ) += 1;
+  }
+  return confusion.trace()/size();  
+}

+ 3 - 0
cbaselib/ClassificationResults.h

@@ -54,6 +54,9 @@ class ClassificationResults : public std::vector<ClassificationResult>
         
         /** return average recognition rate, useful for  multi-class problems */
         double getAverageRecognitionRate() const;
+        
+        /** return overall recognition rate, useful for  multi-class problems */
+        double getOverallRecognitionRate() const;        
 };
 
 

+ 22 - 0
cbaselib/LabeledSet.cpp

@@ -468,4 +468,26 @@ void LabeledSetVector::getFlatRepresentation ( VVector & vecSet, NICE::Vector &
 
 }
 
+void LabeledSetVector::removePointersToDataWithoutDeletion()
+{
+  //remove pointers in the order-struct if needed
+  if ( ! this->selection ) {
+    for ( Permutation::iterator i  = this->insertOrder.begin();
+          i != this->insertOrder.end();
+          i++ )
+    {
+      i->second = NULL;
+    }
+  }
+  
+  //remove pointers in normal map
+  for ( std::map< int, std::vector<NICE::Vector *> >::iterator iter = this->begin(); iter != this->end(); ++iter )
+  {
+    for ( int j = 0; j < (int)iter->second.size(); j++ )
+    {
+      iter->second[j] = NULL;
+    }
+  }  
+}
+
 #endif

+ 5 - 0
cbaselib/LabeledSet.h

@@ -165,6 +165,11 @@ class LabeledSetVector :
      * @param vecSetLabels labels (output)
      */
     void getFlatRepresentation ( NICE::VVector & vecSet, NICE::Vector & vecSetLabels ) const;
+    
+    /**
+     * @brief set all pointers to the data to NULL, i.e., keep the data in storage, but remove the pointers of this data struct
+     */
+    void removePointersToDataWithoutDeletion();
 
     friend class LabeledSetSelection<LabeledSetVector>;
 };

+ 40 - 3
cbaselib/MultiDataset.cpp

@@ -49,8 +49,12 @@ void MultiDataset::selectExamples ( const std::string & examples_command,
     vector<string> parts;
     StringTools::split ( cmd, ' ', parts );
 
-    if ( (parts.size() != 3) && ((parts.size() != 2) || (parts[0] != "all")) )
+    if ( (parts.size() != 3) && ((parts.size() != 2) || (parts[0].compare("all") != 0)) )
+    {
+      std::cerr << "parts.size(): "<<parts.size()<<std::endl;
+      std::cerr << " parts[0]: " << parts[0] << std::endl;
       fthrow( Exception, "Syntax error " << examples_command );
+    }
 
     const std::string & mode = parts[0];
     const std::string & csel = parts[1];
@@ -142,13 +146,27 @@ void MultiDataset::selectExamples ( const std::string & examples_command,
 /** MultiDataset ------- constructor */
 MultiDataset::MultiDataset( const Config *conf , LabeledSetFactory *pSetFactory)
 {
+  //read all blocks from our config file
   std::set<string> blocks;
   conf->getAllBlocks ( blocks );
+  
+#ifdef DEBUG_MultiDataset  
+  std::cerr << "found the following config blocks: " << std::endl;
+  for ( std::set<string>::const_iterator blockIt = blocks.begin(); blockIt != blocks.end(); blockIt++)
+  {
+    std::cerr << *blockIt << " ";
+  }
+  std::cerr << std::endl;
+#endif  
 
   lfl.setFactory( pSetFactory );
 
+  //for every dataset (e.g., train and test), we store a single confog file
   map<string, Config> dsconfs;
+  //for every dataset (e.g., train and test), we store the position of the file directory
   map<string, string> dirs;
+  
+  //first of all, remove all blocks which do correspond to specified datasets, i.e., that do not contain a "dataset" entry
   for ( set<string>::iterator i = blocks.begin();
         i != blocks.end();  )
   {
@@ -172,7 +190,17 @@ MultiDataset::MultiDataset( const Config *conf , LabeledSetFactory *pSetFactory)
       i++;
     }
   }
+  
+#ifdef DEBUG_MultiDataset  
+  std::cerr << "found the following datasets within all config blocks: " << std::endl;
+  for ( std::set<string>::const_iterator blockIt = blocks.begin(); blockIt != blocks.end(); blockIt++)
+  {
+    std::cerr << *blockIt << " ";
+  }
+  std::cerr << std::endl;  
+#endif
 
+  //is there a dataset specified that contains images for both, training and testing?
   if ( blocks.find("traintest") != blocks.end() )
   {
     LabeledSet ls_base;
@@ -224,11 +252,13 @@ MultiDataset::MultiDataset( const Config *conf , LabeledSetFactory *pSetFactory)
     datasets["train"] = ls_train;
   }
 
+  //now read files for every specified dataset (e.g., train and test)
   for ( set<string>::const_iterator i = blocks.begin();
         i != blocks.end();
         i++ )
   {
     std::string name = *i;
+    std::cerr << "read: " << name << std::endl;
     if ( classnames.find(name) != classnames.end() )
       continue;
 
@@ -261,8 +291,11 @@ MultiDataset::MultiDataset( const Config *conf , LabeledSetFactory *pSetFactory)
 #endif
         classnames[name].readFromConfig ( dsconfs[name], classselection );
     }
-		
-
+    
+#ifdef DEBUG_MultiDataset
+    std::cerr << "we set up everything to read this dataset - so now call lfl.get" << std::endl;
+#endif
+    
     lfl.get (   dirs[name],
                 dsconfs[name],
                 classnames[name],
@@ -277,6 +310,10 @@ MultiDataset::MultiDataset( const Config *conf , LabeledSetFactory *pSetFactory)
     fprintf (stderr, "MultiDataset: all information about %s set obtained ! (size %d)\n", name.c_str(), ls_base.count() );
 #endif
 
+#ifdef DEBUG_MultiDataset    
+    std::cerr << "we now call selectExamples to pick only a subset if desired" << std::endl;
+#endif
+    
     std::string examples = conf->gS(name, "examples", "all *" );
     selectExamples ( examples, ls_base, ls, dummy, classnames[name] );
 

+ 6 - 0
classifier/classifierbase/FeaturePoolClassifier.cpp

@@ -78,3 +78,9 @@ void FeaturePoolClassifier::setComplexity ( int size )
     fprintf (stderr, "FeaturePoolClassifier::setComplexity: not yet implemented in subordinate class\n");
     exit(-1);
 }
+
+void FeaturePoolClassifier::addMultipleExamples( OBJREC::Examples & newExamples)
+{
+    fprintf (stderr, "FeaturePoolClassifier::addMultipleExamples: not yet implemented in subordinate class\n");
+    exit(-1);
+}

+ 3 - 0
classifier/classifierbase/FeaturePoolClassifier.h

@@ -50,6 +50,9 @@ class FeaturePoolClassifier : public NICE::Persistent
 
 	/** set complexity for the next training process e.g. number of weak classifiers */
 	virtual void setComplexity ( int size );
+  
+  /** add multiple examples given in the OBJREC::Examples data structure*/
+  virtual void addMultipleExamples( OBJREC::Examples & newExamples);
 
 };
 

+ 7 - 0
classifier/classifierbase/VecClassifier.h

@@ -15,6 +15,7 @@
 #include "vislearning/cbaselib/ClassificationResult.h"
 
 #define ROADWORKS fthrow(NICE::Exception, "clone(): not yet implemented!");
+#define ROADWORKSADD fthrow(NICE::Exception, "teach (int classno, const NICE::Vector & x ): not yet implemented!");
 
 namespace OBJREC
 {
@@ -56,6 +57,12 @@ class VecClassifier : public NICE::Persistent
     {
       ROADWORKS;
     };
+    
+    virtual void teach (int classno, const NICE::Vector & x )
+    {
+      ROADWORKSADD;
+    };
+
 };
 
 #undef ROADWORKS

+ 249 - 0
classifier/fpclassifier/FPCGPHIK.cpp

@@ -0,0 +1,249 @@
+/** 
+* @file FPCGPHIK.cpp
+* @brief feature pool interface for our GP HIK classifier
+* @author Alexander Freytag
+* @date 02/01/2012
+
+*/
+#include <iostream>
+
+#include "core/basics/numerictools.h"
+#include <core/basics/Timer.h>
+
+#include "FPCGPHIK.h"
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+
+
+FPCGPHIK::FPCGPHIK( const Config *conf, const string & confSection ) 
+{
+  this->verbose = conf->gB(confSection, "verbose", false);
+  this->useSimpleBalancing = conf->gB(confSection, "use_simple_balancing", false);
+  this->minSamples = conf->gI(confSection, "min_samples", -1);
+  this->performOptimizationAfterIncrement = conf->gB(confSection, "performOptimizationAfterIncrement", true);
+  
+  classifier = new GPHIKClassifier(conf, confSection);
+}
+
+FPCGPHIK::~FPCGPHIK()
+{
+  if ( classifier != NULL )
+    delete classifier;
+}
+
+ClassificationResult FPCGPHIK::classify ( Example & pe )
+{
+  const SparseVector *svec = pe.svec;
+
+  if ( svec == NULL )
+    fthrow(Exception, "FPCGPHIK requires example.svec (SparseVector stored in an Example struct)");
+ return this->classify( svec ); 
+}
+
+ClassificationResult FPCGPHIK::classify ( const NICE::SparseVector * example )
+{
+  NICE::SparseVector scores;
+  int result;
+  
+  double uncertainty;
+ 
+  classifier->classify ( example,  result, scores, uncertainty);
+  
+  if ( scores.size() == 0 ) {
+    fthrow(Exception, "Zero scores, something is likely to be wrong here: svec.size() = " << example->size() );
+  }
+  int classes = scores.getDim();
+  FullVector fvscores(classes);
+  
+  NICE::SparseVector::const_iterator it;
+  for(int c = 0; c < classes; c++)
+  {
+    it = scores.find(c);
+    if ( it == scores.end() )
+      fvscores[c] = -std::numeric_limits<double>::max();
+    else
+      fvscores[c] = it->second;
+  }
+
+  ClassificationResult r ( fvscores.maxElement(), fvscores );
+  r.uncertainty = uncertainty;
+  
+  if (verbose)
+  {
+    std::cerr << " FPCGPHIK::classify scores" << std::endl;
+    scores.store(std::cerr);
+    std::cerr << " FPCGPHIK::classify fvscores" << std::endl;
+    fvscores.store(std::cerr);
+  }
+
+  return r;
+}
+
+/** training process */
+void FPCGPHIK::train ( FeaturePool & fp, Examples & examples )
+{
+  // we completely ignore the feature pool :)
+  //
+  initRand(0);
+  Vector classCounts;
+  int minClass = -1;
+  
+  if (verbose) 
+    std::cerr << "FPCGPHIK::train" << std::endl;
+
+  if ( useSimpleBalancing)
+  {
+    classCounts.resize( examples.getMaxClassNo()+1 );
+    classCounts.set( 0.0 );
+    for ( uint i = 0 ; i < examples.size() ; i++ )
+      classCounts[ examples[i].first ]++;
+    // we need a probability distribution
+    //classCounts.normalizeL1();
+    // we need the class index of the class with the least non-zero examples
+    for ( uint i = 0 ; i < classCounts.size(); i++ )
+      if ( (classCounts[i] > 0) && ((minClass < 0) || (classCounts[i] < classCounts[minClass])) )
+        minClass = i;
+    if (verbose)
+    {
+      cerr << "Class distribution: " << classCounts << endl;
+      cerr << "Class with the least number of examples: " << minClass << endl;
+    }
+    if(minSamples < 0)
+      minSamples = classCounts[minClass];
+  }
+
+  // (multi-class) label vector
+  Vector y ( examples.size() /* maximum size */ );
+
+  // flat structure of our training data
+  std::vector< SparseVector * > sparseExamples;
+
+  if (verbose)
+    cerr << "Converting (and sampling) feature vectors" << endl;
+  for ( uint i = 0 ; i < examples.size() ; i++ )
+  {
+    const Example & example = examples[i].second;
+    int classno = examples[i].first;
+    
+    // simple weird balancing method
+    if ( useSimpleBalancing ) 
+    {
+      double t = randDouble() * classCounts[classno];
+      if ( t >= minSamples ) continue;
+    }
+
+    y[ sparseExamples.size() ] = classno;
+    if ( example.svec == NULL )
+      fthrow(Exception, "FPCGPHIK requires example.svec (SparseVector stored in an Example struct)");
+    sparseExamples.push_back( example.svec );    
+  }
+
+  // we only use a subset for training
+  y.resize( sparseExamples.size() );
+  
+  classifier->train(sparseExamples, y);
+}
+
+/** training process */
+void FPCGPHIK::train ( const std::vector< SparseVector *> & examples, std::map<int, NICE::Vector> & binLabels )
+{
+  classifier->train(examples, binLabels);
+}
+
+void FPCGPHIK::clear ()
+{
+  if ( classifier != NULL )
+    delete classifier;
+  classifier = NULL;
+}
+
+FeaturePoolClassifier *FPCGPHIK::clone () const
+{
+  fthrow(Exception, "FPCGPHIK: clone() not yet implemented" );
+
+  return NULL;
+}
+
+void FPCGPHIK::predictUncertainty( Example & pe, NICE::Vector & uncertainties )
+{
+  const SparseVector *svec = pe.svec;  
+  if ( svec == NULL )
+    fthrow(Exception, "FPCGPHIK requires example.svec (SparseVector stored in an Example struct)");
+  classifier->predictUncertainty(svec, uncertainties);
+}
+   
+void FPCGPHIK::predictUncertainty( const NICE::SparseVector * example, NICE::Vector & uncertainties )
+{  
+  classifier->predictUncertainty(example, uncertainties);
+}
+
+//---------------------------------------------------------------------
+//                           protected methods
+//---------------------------------------------------------------------
+void FPCGPHIK::restore ( std::istream & is, int format )
+{
+  if (is.good())
+  {
+    classifier->restore(is, format);  
+    
+    std::string tmp;
+    is >> tmp; //"performOptimizationAfterIncrement: "
+    is >> this->performOptimizationAfterIncrement;
+  }
+  else
+  {
+    std::cerr << "FPCGPHIK::restore -- InStream not initialized - restoring not possible!" << std::endl;
+  }
+}
+
+void FPCGPHIK::store ( std::ostream & os, int format ) const
+{
+  if (os.good())
+  {
+    os.precision (numeric_limits<double>::digits10 + 1);
+    
+    classifier->store(os, format);
+    
+    os << "performOptimizationAfterIncrement: " << performOptimizationAfterIncrement << std::endl;
+  }
+  else
+  {
+    std::cerr << "OutStream not initialized - storing not possible!" << std::endl;
+  }
+}
+
+void FPCGPHIK::addExample( const Example & pe, const double & label)
+{
+  const SparseVector *svec = pe.svec;
+  classifier->addExample(svec, label, this->performOptimizationAfterIncrement);
+}
+
+void FPCGPHIK::addMultipleExamples( Examples & newExamples)
+{
+  //are new examples available? If not, nothing has to be done
+  if ( newExamples.size() < 1)
+    return;
+  
+  // (multi-class) label vector
+  Vector y ( newExamples.size() );
+
+  // flat structure of our training data
+  std::vector< const SparseVector * > sparseExamples;
+
+  if (verbose)
+    cerr << "Converting (and sampling) feature vectors" << endl;
+  for ( uint i = 0 ; i < newExamples.size() ; i++ )
+  {
+    const Example & example = newExamples[i].second;
+    int classno = newExamples[i].first;
+
+    y[ i ] = classno;
+    if ( example.svec == NULL )
+      fthrow(Exception, "FPCGPHIK requires example.svec (SparseVector stored in an Example struct)");
+    sparseExamples.push_back( example.svec );    
+  }  
+  
+  classifier->addMultipleExamples(sparseExamples, y, this->performOptimizationAfterIncrement);  
+}

+ 99 - 0
classifier/fpclassifier/FPCGPHIK.h

@@ -0,0 +1,99 @@
+/** 
+* @file FPCGPHIK.h
+* @author Alexander Freytag, Erik Rodner
+* @date 02/01/2012
+
+*/
+#ifndef _NICE_GPHIKCLASSIFIERNICEINCLUDE
+#define _NICE_GPHIKCLASSIFIERNICEINCLUDE
+
+#include <string>
+#include "core/basics/Config.h"
+#include "vislearning/classifier/classifierbase/FeaturePoolClassifier.h"
+
+#include <gp-hik-core/GPHIKClassifier.h>
+#include <gp-hik-core/FMKGPHyperparameterOptimization.h>
+#include <gp-hik-core/parameterizedFunctions/ParameterizedFunction.h>
+
+namespace OBJREC {
+  
+/** @class FPCGPHIK
+ * Wrapper class (feature pool interface) for our GP HIK classifier 
+ *
+ * @author Alexander Freytag, Erik Rodner
+ */
+class FPCGPHIK : public FeaturePoolClassifier
+{
+
+  protected:
+    
+    NICE::GPHIKClassifier * classifier;
+    
+    /** verbose flag for useful output*/
+    bool verbose;
+    
+    /** a simple balancing strategy: use only that many examples of each class, as the smallest class provides*/
+    bool useSimpleBalancing; 
+    int minSamples;
+    
+    /** When adding new examples, do we want to run a whole optimization of all involved hyperparameters? default: true*/
+    bool performOptimizationAfterIncrement;
+
+  public:
+
+    /** simple constructor */
+    FPCGPHIK( const NICE::Config *conf, const std::string & confSection = "GPHIKClassifier" );
+      
+    /** simple destructor */
+    virtual ~FPCGPHIK();
+   
+    /** 
+    * @brief classify a given example with the previously learnt model
+    * @param pe example to be classified given in a sparse representation
+    */
+    virtual ClassificationResult classify ( OBJREC::Example & pe );
+    /** 
+     * @brief classify a given example with the previously learnt model
+     * @date 19-06-2012 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param examples example to be classified given in a sparse representation
+     */    
+    ClassificationResult classify ( const NICE::SparseVector * example );
+
+    /** training process */
+    virtual void train ( OBJREC::FeaturePool & fp, OBJREC::Examples & examples );
+    /** 
+     * @brief train this classifier using a given set of examples and a given set of binary label vectors 
+     * @date 19-06-2012 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param examples examples to use given in a sparse data structure
+     * @param binLabels corresponding binary labels with class no. There is no need here that every examples has only on positive entry in this set (1,-1)
+     */
+    void train ( const std::vector< NICE::SparseVector *> & examples, std::map<int, NICE::Vector> & binLabels );
+    
+    /** Persistent interface */
+    virtual void restore ( std::istream & is, int format = 0 );
+    virtual void store ( std::ostream & os, int format = 0 ) const;
+    virtual void clear ();
+
+    virtual FeaturePoolClassifier *clone () const;
+    
+    /** prediction of classification uncertainty */
+    void predictUncertainty( OBJREC::Example & pe, NICE::Vector & uncertainties );
+    /** 
+     * @brief prediction of classification uncertainty
+     * @date 19-06-2012 (dd-mm-yyyy)
+     * @author Alexander Freytag
+     * @param examples example for which the classification uncertainty shall be predicted, given in a sparse representation
+     * @param uncertainties contains the resulting classification uncertainties (1 entry for standard setting, m entries for binary-balanced setting)
+     */       
+    void predictUncertainty( const NICE::SparseVector * example, NICE::Vector & uncertainties );
+    
+    void addExample( const OBJREC::Example & pe, const double & label);
+    virtual void addMultipleExamples( OBJREC::Examples & newExamples);
+    
+};
+
+}
+
+#endif

+ 3 - 1
classifier/fpclassifier/libdepend.inc

@@ -1 +1,3 @@
-$(call PKG_DEPEND_INT,vislearning/classifier/classifierbase)
+$(call PKG_DEPEND_INT,vislearning/classifier/classifierbase)
+$(call PKG_DEPEND_INT,gp-hik-core/)
+

+ 89 - 0
classifier/fpclassifier/tests/Makefile.inc

@@ -0,0 +1,89 @@
+# BINARY-DIRECTORY-MAKEFILE
+# conventions:
+# - there are no subdirectories, they are ignored!
+# - all ".C", ".cpp" and ".c" files in the current directory are considered
+#   independent binaries, and linked as such.
+# - the binaries depend on the library of the parent directory
+# - the binary names are created with $(BINNAME), i.e. it will be more or less
+#   the name of the .o file
+# - all binaries will be added to the default build list ALL_BINARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+#SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+#include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# include the libdepend.inc file, which gives additional dependencies for the
+# libraries and binaries. additionally, an automatic dependency from the library
+# of the parent directory is added (commented out in the code below).
+
+-include $(SUBDIR)libdepend.inc
+
+PARENTDIR:=$(patsubst %/,%,$(dir $(patsubst %/,%,$(SUBDIR))))
+$(call PKG_DEPEND_INT,$(PARENTDIR))
+$(call PKG_DEPEND_EXT,CPPUNIT)
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+      $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+CHECKS:=$(BINDIR)$(call LIBNAME,$(SUBDIR))
+ALL_CHECKS+=$(CHECKS)
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. each binary depends on the corresponding .o file and
+# on the libraries specified by the INTLIBS/EXTLIBS. these dependencies can be
+# specified manually or they are automatically stored in a .bd file.
+
+$(foreach head,$(wildcard $(SUBDIR)*.h),$(eval $(shell grep -q Q_OBJECT $(head) && echo $(head) | sed -e's@^@/@;s@.*/\(.*\)\.h$$@$(BINDIR)\1:$(OBJDIR)moc_\1.o@')))
+$(eval $(foreach c,$(CHECKS),$(c):$(BUILDDIR)$(CPPUNIT_MAIN_OBJ) $(OBJS) $(call PRINT_INTLIB_DEPS,$(c),.a)))
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 536 - 0
classifier/fpclassifier/tests/TestFPCGPHIK.cpp

@@ -0,0 +1,536 @@
+#ifdef NICE_USELIB_CPPUNIT
+
+#include <string>
+#include <exception>
+#include <iostream>
+#include <fstream>
+
+//----------
+
+#include <core/basics/Timer.h>
+
+//----------
+
+#include <vislearning/cbaselib/ClassificationResults.h>
+#include <vislearning/classifier/kernelclassifier/KCGPRegOneVsAll.h>
+
+//----------
+
+#include "vislearning/classifier/fpclassifier/FPCGPHIK.h"
+
+//----------
+
+#include "TestFPCGPHIK.h"
+
+
+const bool verbose = false;
+const bool verboseStartEnd = true;
+
+using namespace OBJREC;
+using namespace NICE;
+using namespace std;
+
+CPPUNIT_TEST_SUITE_REGISTRATION( TestFPCGPHIK );
+
+void TestFPCGPHIK::setUp() {
+}
+
+void TestFPCGPHIK::tearDown() {
+}
+
+void myClassifierTest( FPCGPHIK & classifier, const Matrix & mX, const Vector & vY )
+{
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::myClassifierTest ===================== " << std::endl;
+  
+  Examples examples;
+
+  for ( uint i = 0 ; i < vY.size() ; i++ )
+    if ( i % 2 == 1 )
+    {
+      Example example;
+      example.svec = new SparseVector;
+      example.svec->setDim(3);
+      example.svec->set ( 0, mX(i,0) );
+      example.svec->set ( 1, mX(i,1) );
+      example.svec->set ( 2, 1.0-mX(i,0)-mX(i,1) );
+      examples.push_back ( pair<int, Example> ( vY[i], example ) );
+    }
+
+  FeaturePool fp; // will be ignored
+
+  if ( verbose )
+    std::cerr << "preparation done." << std::endl;
+
+  if ( verbose ) 
+    std::cerr << "learning ..." << std::endl;
+  classifier.train ( fp, examples ); 
+
+  if ( verbose )
+    std::cerr << "testing ..." << std::endl;
+  for ( uint i = 0 ; i < vY.size() ; i++ )
+    if ( i % 2 == 0 )
+    {
+      Example example;
+      example.svec = new SparseVector;
+      example.svec->setDim(3);
+      example.svec->set ( 0, mX(i,0) );
+      example.svec->set ( 1, mX(i,1) );
+      example.svec->set ( 2, 1.0-mX(i,0)-mX(i,1) );
+      ClassificationResult r = classifier.classify ( example );
+      if (verbose)
+      {
+        r.scores >> std::cerr;
+        std::cerr << "predicted uncertainty: " << r.uncertainty << std::endl;
+      }
+    } 
+
+  examples.clean();
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::myClassifierTest done ===================== " << std::endl;
+
+}
+
+void myClassifierStoreRestoreTest( FPCGPHIK & classifier, const Matrix & mX, const Vector & vY )
+{
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::myClassifierStoreRestoreTest ===================== " << std::endl;
+  
+  Examples examples;
+
+  for ( uint i = 0 ; i < vY.size() ; i++ )
+    if ( i % 2 == 1 )
+    {
+      Example example;
+      example.svec = new SparseVector;
+      example.svec->setDim(3);
+      example.svec->set ( 0, mX(i,0) );
+      example.svec->set ( 1, mX(i,1) );
+      example.svec->set ( 2, 1.0-mX(i,0)-mX(i,1) );
+      examples.push_back ( pair<int, Example> ( vY[i], example ) );
+    }
+
+  FeaturePool fp; // will be ignored
+
+  if ( verbose )
+    std::cerr << "preparation done." << std::endl;
+
+  if ( verbose ) 
+    std::cerr << "learning ..." << std::endl;
+  classifier.train ( fp, examples ); 
+  
+  if ( verbose ) 
+    std::cerr << "storing ..." << std::endl;  
+  //test the store-functionality  
+  string destination("/tmp/GPHIK_store.txt");
+  
+  std::filebuf fb;
+  fb.open (destination.c_str(),ios::out);
+  std::ostream os(&fb);
+//   
+  classifier.store(os);  
+//   
+  fb.close();
+  
+  if ( verbose ) 
+    std::cerr << "loading ..." << std::endl;  
+  
+  Config confTmp;
+  FPCGPHIK classifierRestored(&confTmp);
+  
+  std::filebuf fbIn;
+  fbIn.open (destination.c_str(),ios::in);
+  std::istream is(&fbIn);
+//   
+  classifierRestored.restore(is);
+//   
+  fbIn.close();    
+
+  if ( verbose )
+    std::cerr << "testing ..." << std::endl;
+  for ( uint i = 0 ; i < vY.size() ; i++ )
+    if ( i % 2 == 0 )
+    {
+      Example example;
+      example.svec = new SparseVector;
+      example.svec->setDim(3);
+      example.svec->set ( 0, mX(i,0) );
+      example.svec->set ( 1, mX(i,1) );
+      example.svec->set ( 2, 1.0-mX(i,0)-mX(i,1) );
+      ClassificationResult rOrig = classifier.classify ( example );
+      ClassificationResult rRestored = classifierRestored.classify ( example );
+      
+      //scores are of type FullVector
+      //we use the [] operator, since there are no iterators given in FullVector.h
+      bool equal(true);
+      for (int i = 0; i< rOrig.scores.size(); i++)
+      {
+        if ( fabs(rOrig.scores[i] - rRestored.scores[i]) > 10-6)
+        {
+          equal = false;
+          break;
+        }        
+      }
+      
+      CPPUNIT_ASSERT_EQUAL ( equal, true ); 
+    } 
+
+  examples.clean();
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::myClassifierStoreRestoreTest done ===================== " << std::endl;
+
+}
+
+void myClassifierILTest( FPCGPHIK & classifierRetrain, FPCGPHIK & classifierIL, const Matrix & mX, const Vector & vY )
+{
+ 
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::myClassifierILTest ===================== " << std::endl;
+  
+  Examples examples;
+  
+  if (verbose)
+    std::cerr << "vY: " << vY << std::endl;
+
+  for ( uint i = 0 ; i < vY.size() ; i++ )
+  {
+    if ( i % 4 == 1 )
+    {
+      Example example;
+      example.svec = new SparseVector;
+      example.svec->setDim(3);
+      example.svec->set ( 0, mX(i,0) );
+      example.svec->set ( 1, mX(i,1) );
+      example.svec->set ( 2, 1.0-mX(i,0)-mX(i,1) );
+      examples.push_back ( pair<int, Example> ( vY[i], example ) );
+    }
+  }
+
+  if (verbose)
+    std::cerr << "examples.size(): " << examples.size()  << std::endl;
+
+  FeaturePool fp; // will be ignored
+
+  if ( verbose )
+    std::cerr << "preparation done." << std::endl;
+
+  if ( verbose ) 
+    std::cerr << "learning ..." << std::endl;
+  classifierIL.train ( fp, examples ); 
+  
+  //choose next example(s)
+  
+  Examples newExamples;
+  for ( uint i = 0 ; i < vY.size() ; i++ )
+  {
+    if ( i % 4 == 3 )
+    {
+      Example example;
+      example.svec = new SparseVector;
+      example.svec->setDim(3);
+      example.svec->set ( 0, mX(i,0) );
+      example.svec->set ( 1, mX(i,1) );
+      example.svec->set ( 2, 1.0-mX(i,0)-mX(i,1) );
+      newExamples.push_back ( pair<int, Example> ( vY[i], example ) );
+    }  
+  }
+
+//   if ( verbose ) 
+    std::cerr << std::endl << " =============== " << std::endl << "incremental learning ..." << std::endl;
+  
+  // add them to classifierIL
+//   std::cerr << "We add several new examples" << std::endl;
+  Timer t;
+  t.start();  
+//   for (uint i = 0; i < newExamples.size(); i++)
+  for (uint i = 0; i < 1; i++)
+  {
+    classifierIL.addExample( newExamples[i].second, newExamples[i].first);      
+  }  
+  
+  t.stop();  
+  std::cerr << "Time used for incremental training: " << t.getLast() << std::endl;
+
+  //add the new features to feature pool needed for batch training
+//   for (uint i = 0; i < newExamples.size(); i++)
+  for (uint i = 0; i < 2; i++)
+  {  
+    examples.push_back( newExamples[i] );
+  }
+  
+  std::cerr << std::endl << " =============== " << std::endl << "We train the second classifier from the scratch with the additional new example" << std::endl;
+  t.start(); 
+  
+  classifierRetrain.train ( fp, examples );  
+  
+  t.stop();  
+  std::cerr << "Time used for batch training: " << t.getLast() << std::endl;  
+  
+  //evaluate both and compare the resulting scores
+//  if ( verbose )
+    std::cerr << "testing ..." << std::endl;
+  for ( uint i = 0 ; i < vY.size() ; i++ )
+    if ( i % 2 == 0 )
+    {
+      Example example;
+      example.svec = new SparseVector;
+      example.svec->setDim(3);
+      example.svec->set ( 0, mX(i,0) );
+      example.svec->set ( 1, mX(i,1) );
+      example.svec->set ( 2, 1.0-mX(i,0)-mX(i,1) );
+      ClassificationResult resultIL = classifierIL.classify ( example );
+      ClassificationResult resultBatch = classifierRetrain.classify ( example );
+      
+      if (verbose)
+      {
+        std::cerr << "result of IL classifier: " << std::endl;
+        resultIL.scores >> std::cerr;
+        
+        std::cerr << "result of batch classifier: " << std::endl;
+        resultBatch.scores >> std::cerr;
+      }
+      
+      //scores are of type FullVector
+      //we use the [] operator, since there are no iterators given in FullVector.h
+      bool equal(true);
+      for (int i = 0; i< resultIL.scores.size(); i++)
+      {
+        if ( fabs(resultIL.scores[i] - resultBatch.scores[i]) > 10e-3)
+        {
+          equal = false;
+          break;
+        }        
+      }
+      
+      CPPUNIT_ASSERT_EQUAL ( equal, true ); 
+    } 
+
+  examples.clean();
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::myClassifierILTest done ===================== " << std::endl;
+}
+
+void TestFPCGPHIK::testFPCGPHIK() 
+{
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::testFPCGPHIK ===================== " << std::endl;
+
+  Config conf;
+  conf.sD( "FPCGPHIK", "noise", 0.01 );
+  conf.sD( "FPCGPHIK", "parameter_lower_bound", 0.5 );
+  conf.sD( "FPCGPHIK", "parameter_upper_bound", 3.5 );
+  conf.sI( "FPCGPHIK", "uncertaintyPrediction", 1);
+//   conf.sS( "FPCGPHIK", "optimization_method", "none");
+  conf.sS( "FPCGPHIK", "optimization_method", "downhillsimplex");
+  conf.sB( "FPCGPHIK", "uncertaintyPredictionForClassification", true);
+
+  FPCGPHIK * classifier  = new FPCGPHIK ( &conf );
+  
+  Matrix mX;
+  Vector vY;
+  Vector vY_multi;
+
+//   ifstream ifs ("toyExample1.data", ios::in);
+//   ifstream ifs ("toyExampleLargeScale.data", ios::in);
+  ifstream ifs ("toyExampleLargeLargeScale.data", ios::in);
+  CPPUNIT_ASSERT ( ifs.good() );
+  ifs >> mX;
+  ifs >> vY;
+  ifs >> vY_multi;
+  ifs.close();
+  
+  if (verbose)
+  {
+    std::cerr << "data loaded: mX" << std::endl;
+    std::cerr << mX << std::endl;
+    std::cerr << "vY: " << std::endl;
+    std::cerr << vY << std::endl;
+    std::cerr << "vY_multi: " << std::endl;
+    std::cerr << vY_multi << std::endl;
+  }
+
+  if ( verbose )
+    std::cerr << "Binary classification test " << std::endl; 
+
+  myClassifierTest ( *classifier, mX, vY );
+  
+  // ... we remove nothing here since we are only interested in store and restore :)
+  myClassifierStoreRestoreTest ( *classifier, mX, vY );
+  
+  // ... remove previously computed things and start again, this time with incremental settings
+  if (classifier != NULL)
+    delete classifier;
+  
+  classifier  = new FPCGPHIK ( &conf );
+    FPCGPHIK * classifierBatch = new FPCGPHIK ( &conf ); 
+  
+  myClassifierILTest( *classifierBatch, *classifier, mX, vY );
+  
+  if (classifier != NULL)
+    delete classifier;
+  if (classifierBatch != NULL)
+    delete classifierBatch;
+  
+  classifier  = new FPCGPHIK ( &conf );
+  classifierBatch = new FPCGPHIK ( &conf );  
+
+  if ( verbose )
+    std::cerr << "Multi-class classification test " << std::endl; 
+  myClassifierTest ( *classifier, mX, vY_multi );
+  
+  // ... we remove nothing here since we are only interested and store and restore :)
+//   
+//   myClassifierStoreRestoreTest ( classifier, mX, vY_multi );
+  
+  // ... remove previously computed things and start again, this time with incremental settings
+  if (classifier != NULL)
+    delete classifier;
+  if (classifierBatch != NULL)
+    delete classifierBatch;
+  
+  classifier  = new FPCGPHIK ( &conf, "GPHIKClassifier" /* section */);
+  classifierBatch = new FPCGPHIK ( &conf, "GPHIKClassifier" /* section */ ); 
+  
+  myClassifierILTest( *classifierBatch, *classifier, mX, vY_multi );
+  
+  if (classifier != NULL)
+    delete classifier;
+  if (classifierBatch != NULL)
+    delete classifierBatch;  
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::testFPCGPHIK done ===================== " << std::endl;
+ 
+}
+
+void TestFPCGPHIK::testGPHIKVariance()
+{
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::testGPHIKVariance ===================== " << std::endl;
+
+  double noise (0.01);
+  
+  Config conf;
+  conf.sD( "GPHIKClassifier", "noise", noise );
+  conf.sD( "GPHIKClassifier", "parameter_lower_bound", 1.0 );
+  conf.sD( "GPHIKClassifier", "parameter_upper_bound", 1.0 );
+  conf.sS( "GPHIKClassifier", "varianceApproximation", "approximate_rough");
+  conf.sB( "GPHIKClassifier", "learn_balanced", true);
+  conf.sB( "GPHIKClassifier", "uncertaintyPredictionForClassification", true);
+  
+  FPCGPHIK classifier ( &conf );
+  
+  Config confVarApproxQuant(conf);
+  confVarApproxQuant.sB( "GPHIKClassifier", "use_quantization", true );
+  FPCGPHIK classifierQuant ( &confVarApproxQuant );  
+
+  Config confVarApproxFine1(conf);
+  confVarApproxFine1.sS( "GPHIKClassifier", "varianceApproximation", "approximate_fine");  
+  confVarApproxFine1.sI( "GPHIKClassifier", "nrOfEigenvaluesToConsiderForVarApprox", 1);
+  
+  FPCGPHIK classifierVarApproxFine1 ( &confVarApproxFine1 );  
+
+  Config confVarApproxFine2(conf);
+  confVarApproxFine2.sS( "GPHIKClassifier", "varianceApproximation", "approximate_fine");    
+  confVarApproxFine2.sI( "GPHIKClassifier", "nrOfEigenvaluesToConsiderForVarApprox", 2);
+  
+  FPCGPHIK classifierVarApproxFine2 ( &confVarApproxFine2 );    
+  
+  Config confExact(conf);
+  confExact.sS( "GPHIKClassifier", "varianceApproximation", "exact");   
+  
+  FPCGPHIK classifierVarExact ( &confExact );
+  
+  NICE::Matrix mX;
+  NICE::Vector vY;
+  NICE::Vector vY_multi;
+
+  ifstream ifs ("toyExample2.data", ios::in);
+  CPPUNIT_ASSERT ( ifs.good() );
+  ifs >> mX;
+  ifs >> vY;
+  ifs >> vY_multi;
+  ifs.close();
+
+  if (verbose)
+  {
+    std::cerr << "data loaded: mX" << std::endl;
+    std::cerr << mX << std::endl;
+    std::cerr << "vY: " << std::endl;
+    std::cerr << vY << std::endl;
+    std::cerr << "vY_multi: " << std::endl;
+    std::cerr << vY_multi << std::endl;
+  }
+  
+  Examples examples;
+
+  for ( uint i = 0 ; i < vY.size() ; i++ )
+    if ( i % 2 == 0 )
+    {
+      Example example;
+      example.svec = new SparseVector;
+      example.svec->setDim(3);
+      example.svec->set ( 0, mX(i,0) );
+      example.svec->set ( 1, mX(i,1) );
+      example.svec->set ( 2, 1.0-mX(i,0)-mX(i,1) );
+      examples.push_back ( pair<int, Example> ( vY_multi[i], example ) );
+    }
+
+  FeaturePool fp; // will be ignored
+
+  if ( verbose )
+    std::cerr << "preparation for variance testing done." << std::endl;
+
+  if ( verbose ) 
+    std::cerr << "learning for variance testing ..." << std::endl;
+  classifier.train ( fp, examples ); 
+  classifierQuant.train ( fp, examples );
+  classifierVarApproxFine1.train ( fp, examples ); 
+  classifierVarApproxFine2.train ( fp, examples ); 
+  classifierVarExact.train ( fp, examples ); 
+
+  if ( verbose )
+    std::cerr << "testing for variance testing ..." << std::endl;
+  
+  for ( uint i = 0 ; i < vY_multi.size() ; i++ )
+    if ( i % 2 == 1 )
+    {
+      Example example;
+      example.svec = new SparseVector;
+      example.svec->setDim(3);
+      example.svec->set ( 0, mX(i,0) );
+      example.svec->set ( 1, mX(i,1) );
+      example.svec->set ( 2, 1.0-mX(i,0)-mX(i,1) );
+      ClassificationResult r = classifier.classify ( example );
+      ClassificationResult rQuant = classifierQuant.classify ( example );
+      ClassificationResult rVarApproxFine1 = classifierVarApproxFine1.classify ( example );
+      ClassificationResult rVarApproxFine2 = classifierVarApproxFine2.classify ( example );
+      ClassificationResult rExact = classifierVarExact.classify ( example );
+      
+      if (verbose)
+      {
+        std::cerr << "approxUnc: " << r.uncertainty << " approxUncQuant: " << rQuant.uncertainty<< " approxUncFine1: " << rVarApproxFine1.uncertainty << " approxUncFine2: " << rVarApproxFine2.uncertainty << " exactUnc: " << rExact.uncertainty << std::endl;
+      }
+
+      CPPUNIT_ASSERT ( r.uncertainty <=  (1.0 + noise) ); //using the "standard" HIK, this is the upper bound
+      CPPUNIT_ASSERT ( r.uncertainty >  rVarApproxFine1.uncertainty);
+      CPPUNIT_ASSERT ( rQuant.uncertainty >  rVarApproxFine1.uncertainty);
+      CPPUNIT_ASSERT ( rVarApproxFine1.uncertainty >  rVarApproxFine2.uncertainty);
+      CPPUNIT_ASSERT ( rVarApproxFine2.uncertainty >  rExact.uncertainty);
+      
+    } 
+
+  examples.clean();  
+  
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestFPCGPHIK::testGPHIKVariance done ===================== " << std::endl;
+  
+}
+
+#endif

+ 31 - 0
classifier/fpclassifier/tests/TestFPCGPHIK.h

@@ -0,0 +1,31 @@
+#ifndef _TESTFPCGPHIK_H
+#define _TESTFPCGPHIK_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+/**
+ * CppUnit-Testcase. 
+ */
+class TestFPCGPHIK : public CppUnit::TestFixture {
+
+    CPPUNIT_TEST_SUITE( TestFPCGPHIK );
+    
+    CPPUNIT_TEST(testFPCGPHIK);
+    CPPUNIT_TEST(testGPHIKVariance);
+//     CPPUNIT_TEST(testGPHIKIncrementalLearning);
+    
+    CPPUNIT_TEST_SUITE_END();
+  
+ private:
+ 
+ public:
+    void setUp();
+    void tearDown();
+
+    void testFPCGPHIK();
+    void testGPHIKVariance();
+//     void testGPHIKIncrementalLearning();
+
+};
+
+#endif // _TESTFPCGPHIK_H

二进制
classifier/fpclassifier/tests/sparse20x30matrixM.mat


二进制
classifier/fpclassifier/tests/sparse3x3matrixA.mat


+ 42 - 0
classifier/fpclassifier/tests/toyExample1.data

@@ -0,0 +1,42 @@
+39 x 2
+0.1394    0.3699
+0.1210    0.3260
+0.1164    0.2588
+0.1210    0.2032
+0.1417    0.1886
+0.1624    0.2325
+0.1624    0.3319
+0.1509    0.3114
+0.1417    0.2412
+0.1417    0.2763
+0.1279    0.3173
+0.3537    0.3582
+0.3306    0.3056
+0.3306    0.2471
+0.3376    0.2061
+0.3583    0.1740
+0.3698    0.1564
+0.3790    0.2558
+0.3744    0.3173
+0.3698    0.3406
+0.3583    0.2646
+0.3629    0.1944
+0.3468    0.3173
+0.3329    0.2588
+0.3514    0.1974
+0.2224    0.3436
+0.2270    0.3348
+0.2293    0.2675
+0.2339    0.2237
+0.2316    0.1623
+0.2408    0.1857
+0.2615    0.2763
+0.2638    0.3436
+0.2592    0.3904
+0.2477    0.4284
+0.2224    0.3582
+0.2177    0.2909
+0.2224    0.2178
+0.2500    0.1213
+39 < 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 >
+39 < 0 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 >

+ 9 - 0
classifier/fpclassifier/tests/toyExample2.data

@@ -0,0 +1,9 @@
+6 x 2
+0.1    0.3
+0.1    0.2
+0.3    0.3
+0.2    0.2
+0.4    0.1
+0.1    0.5
+6 < 0 0 0 1 1 1 >
+6 < 0 0 3 3 1 1 >

文件差异内容过多而无法显示
+ 1502 - 0
classifier/fpclassifier/tests/toyExampleLargeLargeScale.data


+ 604 - 0
classifier/fpclassifier/tests/toyExampleLargeScale.data

@@ -0,0 +1,604 @@
+600 x 2
+0.342689 0.175671 
+0.30934 0.268245 
+0.283338 0.31431 
+0.322194 0.211048 
+0.27985 0.217818 
+0.253954 0.195404 
+0.435345 0.125535 
+0.312486 0.137852 
+0.268998 0.2357 
+0.254516 0.213503 
+0.315574 0.130796 
+0.39208 0.178418 
+0.262966 0.128216 
+0.258793 0.151603 
+0.32426 0.234761 
+0.292135 0.138279 
+0.331166 0.145197 
+0.3395 0.169078 
+0.283081 0.134257 
+0.2829 0.147042 
+0.257692 0.28673 
+0.31662 0.209292 
+0.274172 0.194507 
+0.368124 0.127353 
+0.378173 0.236568 
+0.313633 0.166162 
+0.308659 0.154215 
+0.307818 0.180172 
+0.306022 0.194493 
+0.256317 0.182305 
+0.253279 0.138247 
+0.286522 0.154934 
+0.343294 0.296202 
+0.435882 0.149799 
+0.266064 0.141986 
+0.362818 0.130809 
+0.424555 0.154075 
+0.312223 0.176338 
+0.346151 0.185167 
+0.303702 0.224405 
+0.250913 0.27087 
+0.278182 0.187886 
+0.305441 0.161418 
+0.390785 0.176948 
+0.419366 0.139879 
+0.298091 0.134676 
+0.311699 0.242829 
+0.293336 0.238481 
+0.349461 0.179128 
+0.294253 0.191256 
+0.255692 0.154904 
+0.273268 0.193811 
+0.376241 0.206254 
+0.329721 0.17215 
+0.331964 0.234789 
+0.335461 0.186645 
+0.296782 0.158248 
+0.368493 0.148484 
+0.255566 0.188169 
+0.343617 0.135276 
+0.252996 0.204645 
+0.285394 0.333677 
+0.313484 0.175742 
+0.250342 0.203408 
+0.266606 0.188748 
+0.283449 0.129172 
+0.340621 0.179734 
+0.315654 0.199744 
+0.27226 0.134784 
+0.296711 0.185527 
+0.253752 0.198492 
+0.257381 0.257684 
+0.346152 0.220506 
+0.36263 0.183317 
+0.278849 0.181596 
+0.301625 0.247397 
+0.318059 0.23282 
+0.271193 0.143659 
+0.40265 0.205326 
+0.457977 0.223787 
+0.277921 0.132572 
+0.44805 0.266026 
+0.292541 0.133553 
+0.320695 0.152126 
+0.293894 0.132603 
+0.310329 0.158675 
+0.308961 0.228526 
+0.310193 0.201196 
+0.357398 0.276934 
+0.362411 0.134546 
+0.252874 0.249074 
+0.323796 0.231816 
+0.258442 0.173894 
+0.343986 0.134667 
+0.356016 0.163639 
+0.322109 0.210639 
+0.28522 0.223836 
+0.396437 0.198424 
+0.283134 0.21192 
+0.279188 0.215173 
+0.260586 0.22736 
+0.329615 0.19164 
+0.339912 0.133774 
+0.257242 0.151432 
+0.353614 0.163562 
+0.332978 0.182046 
+0.302671 0.248665 
+0.259309 0.151224 
+0.318917 0.240108 
+0.344637 0.135684 
+0.256466 0.283143 
+0.356169 0.209122 
+0.251218 0.224075 
+0.424779 0.215246 
+0.372904 0.150395 
+0.428672 0.125709 
+0.391982 0.182144 
+0.26703 0.265749 
+0.266772 0.152864 
+0.418837 0.250821 
+0.303323 0.235758 
+0.311233 0.15944 
+0.390081 0.292144 
+0.289179 0.154131 
+0.269899 0.233753 
+0.292143 0.269953 
+0.389615 0.181187 
+0.281855 0.168289 
+0.355694 0.130023 
+0.258038 0.191685 
+0.322198 0.160255 
+0.265639 0.205397 
+0.266359 0.195618 
+0.291999 0.161498 
+0.287761 0.170072 
+0.264713 0.332262 
+0.294721 0.140154 
+0.273594 0.165844 
+0.310086 0.169887 
+0.341029 0.225881 
+0.316856 0.137035 
+0.300842 0.221668 
+0.301447 0.210899 
+0.292541 0.135141 
+0.282796 0.135598 
+0.267783 0.151061 
+0.461684 0.192769 
+0.311754 0.238481 
+0.252301 0.171746 
+0.370648 0.194599 
+0.363942 0.159229 
+0.353153 0.187895 
+0.343755 0.214295 
+0.35249 0.132681 
+0.321514 0.191171 
+0.32338 0.135597 
+0.365625 0.141555 
+0.33572 0.236221 
+0.255242 0.240287 
+0.272454 0.25177 
+0.260317 0.137604 
+0.293878 0.138076 
+0.262748 0.191504 
+0.329031 0.143135 
+0.338375 0.250212 
+0.345667 0.147506 
+0.309146 0.198383 
+0.282595 0.295251 
+0.262683 0.15159 
+0.296848 0.163558 
+0.264113 0.274616 
+0.338641 0.211817 
+0.259174 0.264645 
+0.330357 0.20687 
+0.353817 0.22874 
+0.269664 0.226656 
+0.252154 0.148463 
+0.366193 0.150144 
+0.256898 0.245194 
+0.304303 0.183618 
+0.335466 0.151312 
+0.262861 0.200441 
+0.262813 0.252586 
+0.313346 0.194787 
+0.289579 0.247262 
+0.286535 0.23699 
+0.310318 0.142124 
+0.341106 0.206294 
+0.273167 0.156972 
+0.269453 0.187743 
+0.355513 0.183233 
+0.263025 0.199449 
+0.313509 0.331514 
+0.311078 0.252023 
+0.281887 0.26323 
+0.255329 0.173521 
+0.300729 0.214255 
+0.286228 0.136099 
+0.299626 0.157784 
+0.271569 0.22316 
+0.300825 0.303776 
+0.27322 0.25126 
+0.176006 0.402724 
+0.226378 0.348555 
+0.168946 0.262155 
+0.139945 0.341302 
+0.141302 0.305834 
+0.15167 0.264065 
+0.13236 0.287971 
+0.259065 0.450122 
+0.167671 0.301213 
+0.232472 0.315405 
+0.318855 0.278831 
+0.149421 0.336895 
+0.167089 0.266261 
+0.125286 0.322987 
+0.186744 0.359308 
+0.181219 0.298146 
+0.162008 0.412922 
+0.142068 0.288868 
+0.20133 0.317385 
+0.152729 0.340693 
+0.156914 0.393993 
+0.151577 0.271511 
+0.137218 0.435257 
+0.135001 0.288495 
+0.233009 0.308706 
+0.253521 0.278079 
+0.126533 0.327627 
+0.129093 0.344601 
+0.271354 0.292011 
+0.228235 0.290139 
+0.213721 0.357127 
+0.152746 0.388868 
+0.137812 0.376055 
+0.247148 0.391889 
+0.199338 0.316814 
+0.19992 0.434137 
+0.265019 0.338816 
+0.138767 0.355017 
+0.139752 0.313471 
+0.217796 0.265376 
+0.152899 0.257636 
+0.248653 0.313653 
+0.154939 0.31371 
+0.235854 0.259526 
+0.165171 0.300912 
+0.246794 0.338431 
+0.203588 0.363351 
+0.155485 0.377965 
+0.211843 0.290398 
+0.306505 0.385808 
+0.261773 0.398547 
+0.194004 0.282203 
+0.176261 0.26052 
+0.188294 0.343489 
+0.234243 0.430868 
+0.181933 0.355282 
+0.170154 0.350051 
+0.161818 0.263494 
+0.302773 0.265246 
+0.168825 0.310823 
+0.164394 0.423268 
+0.29166 0.35488 
+0.271975 0.386961 
+0.296484 0.309649 
+0.196042 0.314222 
+0.145605 0.298324 
+0.255544 0.452838 
+0.189474 0.312347 
+0.176208 0.272894 
+0.16492 0.380216 
+0.187287 0.414524 
+0.178578 0.294622 
+0.278798 0.27663 
+0.132288 0.296908 
+0.254925 0.33015 
+0.350185 0.258513 
+0.16647 0.387784 
+0.155536 0.261762 
+0.31289 0.421124 
+0.1639 0.278125 
+0.299235 0.435447 
+0.126134 0.307695 
+0.163839 0.313053 
+0.143585 0.53421 
+0.162566 0.331135 
+0.220753 0.256421 
+0.219454 0.4336 
+0.19769 0.37137 
+0.131795 0.403685 
+0.180282 0.261803 
+0.196382 0.262449 
+0.20367 0.318381 
+0.130772 0.333474 
+0.180841 0.299823 
+0.214484 0.290828 
+0.138715 0.341963 
+0.251411 0.39227 
+0.125156 0.30578 
+0.266808 0.337032 
+0.240964 0.331971 
+0.175375 0.294612 
+0.179172 0.366302 
+0.147287 0.296443 
+0.164014 0.261311 
+0.273203 0.254742 
+0.136849 0.28521 
+0.213123 0.34695 
+0.173496 0.325799 
+0.292193 0.255454 
+0.138616 0.33484 
+0.25335 0.300546 
+0.158688 0.311034 
+0.145169 0.361547 
+0.128574 0.270011 
+0.15352 0.26367 
+0.159877 0.378762 
+0.140396 0.433171 
+0.133033 0.290889 
+0.163508 0.271152 
+0.210289 0.291615 
+0.14189 0.280736 
+0.149909 0.292447 
+0.180142 0.266672 
+0.144982 0.277738 
+0.159478 0.274755 
+0.164206 0.442762 
+0.178133 0.262889 
+0.166155 0.348706 
+0.290175 0.379262 
+0.154984 0.394628 
+0.250925 0.259417 
+0.141829 0.286385 
+0.173571 0.32318 
+0.155138 0.334199 
+0.19025 0.284642 
+0.132157 0.273714 
+0.169887 0.327512 
+0.231932 0.328859 
+0.163281 0.304052 
+0.145319 0.36004 
+0.144163 0.303037 
+0.158192 0.259722 
+0.198438 0.331068 
+0.127219 0.323939 
+0.155833 0.30954 
+0.190242 0.28389 
+0.199135 0.277733 
+0.321694 0.453193 
+0.141441 0.268926 
+0.281311 0.338708 
+0.189104 0.267739 
+0.133845 0.310823 
+0.209767 0.418156 
+0.297319 0.297564 
+0.161189 0.259427 
+0.213576 0.457596 
+0.270751 0.290435 
+0.201792 0.389826 
+0.135373 0.254834 
+0.133443 0.307913 
+0.146304 0.263914 
+0.254784 0.28866 
+0.205916 0.275338 
+0.196961 0.277155 
+0.239999 0.304274 
+0.172131 0.28929 
+0.145521 0.255641 
+0.25942 0.282277 
+0.167205 0.260999 
+0.169453 0.345352 
+0.255941 0.301047 
+0.264722 0.378455 
+0.133553 0.308037 
+0.137054 0.309238 
+0.20074 0.274192 
+0.250793 0.336116 
+0.162476 0.296901 
+0.137098 0.250421 
+0.193241 0.277141 
+0.185979 0.273677 
+0.17511 0.379876 
+0.149684 0.265748 
+0.225099 0.317336 
+0.132403 0.250674 
+0.13283 0.294247 
+0.158449 0.338396 
+0.252054 0.266546 
+0.154258 0.287316 
+0.223787 0.363484 
+0.160883 0.270353 
+0.152975 0.283687 
+0.237612 0.267854 
+0.18717 0.29144 
+0.174165 0.34938 
+0.165426 0.355092 
+0.287473 0.27884 
+0.128887 0.361068 
+0.179211 0.299544 
+0.215031 0.155091 
+0.142583 0.193322 
+0.276808 0.171428 
+0.1541 0.183927 
+0.194681 0.127557 
+0.128295 0.150629 
+0.235294 0.134568 
+0.201284 0.162832 
+0.314834 0.212242 
+0.142952 0.303737 
+0.195 0.152865 
+0.287761 0.163026 
+0.156109 0.155853 
+0.20319 0.275679 
+0.154476 0.216572 
+0.141193 0.151162 
+0.178573 0.150035 
+0.289051 0.328297 
+0.174799 0.175858 
+0.166596 0.15483 
+0.248603 0.15139 
+0.189713 0.18169 
+0.256645 0.128374 
+0.137268 0.213468 
+0.152469 0.125282 
+0.178565 0.209226 
+0.170197 0.194244 
+0.205242 0.14935 
+0.197247 0.173981 
+0.222782 0.185638 
+0.255122 0.138357 
+0.137221 0.181269 
+0.162759 0.136556 
+0.126264 0.173721 
+0.250943 0.187721 
+0.153073 0.14711 
+0.219836 0.248307 
+0.190877 0.288343 
+0.210659 0.223544 
+0.162835 0.133229 
+0.349274 0.263972 
+0.191313 0.167455 
+0.14183 0.183345 
+0.171238 0.243158 
+0.236826 0.155454 
+0.192282 0.141581 
+0.155562 0.137083 
+0.168371 0.216514 
+0.207958 0.286036 
+0.12849 0.227428 
+0.140926 0.162835 
+0.159604 0.134924 
+0.316663 0.133871 
+0.150814 0.125524 
+0.133106 0.196074 
+0.149622 0.144502 
+0.15218 0.196792 
+0.1625 0.220862 
+0.265263 0.279839 
+0.192861 0.147449 
+0.275367 0.136736 
+0.125005 0.217594 
+0.157708 0.130746 
+0.137828 0.2188 
+0.205963 0.284573 
+0.314706 0.265755 
+0.223344 0.184088 
+0.23382 0.250284 
+0.213944 0.131451 
+0.298037 0.21233 
+0.161291 0.127927 
+0.141618 0.222095 
+0.139736 0.286058 
+0.220316 0.175143 
+0.231751 0.134027 
+0.169706 0.258055 
+0.260142 0.143679 
+0.217887 0.240266 
+0.131439 0.174702 
+0.214523 0.15396 
+0.1768 0.227648 
+0.224522 0.230168 
+0.16444 0.13183 
+0.187441 0.266578 
+0.150256 0.169155 
+0.224854 0.163051 
+0.258784 0.161583 
+0.210855 0.186293 
+0.125887 0.30692 
+0.131581 0.155051 
+0.146777 0.145637 
+0.351453 0.17521 
+0.212764 0.187016 
+0.191882 0.18859 
+0.188817 0.224918 
+0.150217 0.141471 
+0.296471 0.317944 
+0.227911 0.172533 
+0.254149 0.182712 
+0.182149 0.212013 
+0.178375 0.191318 
+0.148463 0.174887 
+0.216658 0.261188 
+0.127068 0.215572 
+0.181236 0.211954 
+0.171546 0.137991 
+0.228025 0.188707 
+0.140536 0.254658 
+0.249636 0.130417 
+0.182512 0.229795 
+0.212421 0.228258 
+0.165297 0.137963 
+0.298921 0.147804 
+0.235353 0.280178 
+0.289942 0.15012 
+0.146599 0.23232 
+0.142329 0.161157 
+0.270889 0.212884 
+0.163608 0.134177 
+0.156306 0.230362 
+0.187909 0.144162 
+0.253675 0.15226 
+0.277975 0.241759 
+0.132958 0.140637 
+0.132167 0.281881 
+0.14486 0.179008 
+0.14129 0.173667 
+0.13792 0.196095 
+0.144878 0.181669 
+0.270531 0.275731 
+0.220914 0.170835 
+0.166041 0.191592 
+0.169549 0.195291 
+0.291418 0.174062 
+0.132584 0.211085 
+0.180231 0.238647 
+0.145224 0.208966 
+0.372008 0.140979 
+0.129183 0.246742 
+0.214086 0.129494 
+0.157116 0.270378 
+0.141035 0.149166 
+0.162474 0.246944 
+0.13349 0.206489 
+0.132278 0.182272 
+0.216111 0.187533 
+0.220175 0.300967 
+0.167512 0.145929 
+0.168184 0.321369 
+0.133267 0.234592 
+0.229341 0.131162 
+0.257111 0.218668 
+0.333441 0.333555 
+0.133784 0.186297 
+0.287145 0.18554 
+0.139222 0.142987 
+0.150074 0.223927 
+0.214144 0.1276 
+0.25632 0.226794 
+0.156132 0.185504 
+0.159565 0.135037 
+0.196861 0.22244 
+0.211956 0.176154 
+0.148823 0.188648 
+0.203664 0.150215 
+0.218453 0.216136 
+0.262688 0.1386 
+0.186142 0.217442 
+0.148249 0.21515 
+0.199327 0.125026 
+0.182995 0.187074 
+0.196654 0.246484 
+0.224754 0.176581 
+0.130524 0.173274 
+0.177737 0.137875 
+0.187153 0.126132 
+0.178623 0.232132 
+0.187313 0.153289 
+0.155405 0.143394 
+0.218375 0.326502 
+0.137907 0.187893 
+0.149386 0.260504 
+0.193591 0.134313 
+0.239484 0.221013 
+0.175538 0.146035 
+0.197115 0.160234 
+0.175092 0.211225 
+0.137077 0.129546 
+0.172193 0.304747 
+0.167678 0.208687 
+0.267804 0.163603 
+0.154224 0.12527 
+0.163461 0.150108 
+0.148395 0.22809 
+0.24221 0.142793 
+0.210785 0.228961 
+0.160274 0.131187 
+0.250532 0.191618 
+0.184075 0.192361 
+0.211521 0.193562 
+
+600 < 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 >
+600 < 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 >

+ 46 - 18
classifier/genericClassifierSelection.h

@@ -1,8 +1,14 @@
 #ifndef _NICE_OBJREC_GENERICCLASSIFIERSELECTION_INCLUDE
 #define _NICE_OBJREC_GENERICCLASSIFIERSELECTION_INCLUDE
 
+//STL
+#include <vector>
+
+//core
 #include "core/basics/StringTools.h"
 
+
+//vislearning  -- vector classifiers
 #include "vislearning/classifier/vclassifier/VCAmitSVM.h"
 #include "vislearning/classifier/vclassifier/VCNearestClassMean.h"
 #include "vislearning/classifier/vclassifier/VCSimpleGaussian.h"
@@ -12,18 +18,9 @@
 #include "vislearning/classifier/vclassifier/VCOneVsOne.h"
 #include "vislearning/classifier/vclassifier/VCOneVsAll.h"
 #include "vislearning/classifier/vclassifier/VCDTSVM.h"
+#include "vislearning/classifier/vclassifier/VCTransform.h"
 
-
-#ifdef NICE_USELIB_SVMLIGHT
-#include "vislearning/classifier/vclassifier/VCSVMLight.h"
-#include "vislearning/classifier/kernelclassifier/KCSVMLight.h"
-#include "vislearning/classifier/vclassifier/VCSVMOneClass.h"
-#endif
-
-#ifdef NICE_USELIB_NICEDTSVM
-#include "nice-dtsvm/VCTreeBasedClassifier.h"
-#endif
-
+//vislearning -- kernel classifiers
 #include "vislearning/classifier/kernelclassifier/KCGPRegression.h"
 #include "vislearning/classifier/kernelclassifier/KCGPLaplace.h"
 #include "vislearning/classifier/kernelclassifier/KCGPLaplaceOneVsAll.h"
@@ -31,22 +28,43 @@
 #include "vislearning/classifier/kernelclassifier/KCGPRegOneVsAll.h"
 #include "vislearning/classifier/kernelclassifier/KCMinimumEnclosingBall.h"
 #include "vislearning/classifier/kernelclassifier/KCGPOneClass.h"
+
+//vislearning -- kernels
 #include "vislearning/math/kernels/KernelStd.h"
 #include "vislearning/math/kernels/KernelExp.h"
 #include "vislearning/math/kernels/KernelRBF.h"
+#include "vislearning/math/kernels/genericKernel.h"
 
-#include "vislearning/classifier/vclassifier/VCTransform.h"
-
+//vislearning -- feature pool classifier
 #include "vislearning/classifier/fpclassifier/boosting/FPCBoosting.h"
 #include "vislearning/classifier/fpclassifier/randomforest/FPCRandomForests.h"
 #include "vislearning/classifier/fpclassifier/randomforest/FPCDecisionTree.h"
 #include "vislearning/classifier/fpclassifier/logisticregression/FPCSMLR.h"
+#include "vislearning/classifier/fpclassifier/FPCGPHIK.h"
 
+//vislearning -- classifier combinations
 #include "vislearning/classifier/classifiercombination/VCPreRandomForest.h"
 
-#include "vislearning/math/kernels/genericKernel.h"
 
-#include <vector>
+//vislearning -- SVM-based classifiers (vclassifier, kernelclassifier)
+#ifdef NICE_USELIB_SVMLIGHT
+#include "vislearning/classifier/vclassifier/VCSVMLight.h"
+#include "vislearning/classifier/vclassifier/VCSVMOneClass.h"
+#include "vislearning/classifier/kernelclassifier/KCSVMLight.h"
+#endif
+
+//external stuff
+#ifdef NICE_USELIB_NICEDTSVM
+#include "nice-dtsvm/VCTreeBasedClassifier.h"
+#endif
+
+// #include "gp-hik-exp/GPHIKClassifierNICE.h"
+
+
+
+
+
+
 
 namespace OBJREC {
 
@@ -69,11 +87,21 @@ class GenericClassifierSelection
      } else if ( classifier_type == "nearest_classmean" ) {
         classifier = new VCNearestClassMean( conf, new NICE::EuclidianDistance<double>() );
 #endif
-      } else if ( classifier_type == "random_forest" ) {
+      }
+      ////////////////////////////////////////
+      //                                    //
+      //    all Feature Pool Classifiers    //
+      //                                    //
+      ////////////////////////////////////////
+      else if ( classifier_type == "GPHIK" ) {
+        FeaturePoolClassifier *fpc = new FPCGPHIK ( conf, "GPHIK" );
+        classifier = new VCFeaturePool ( conf, fpc );
+      }      
+      else if ( classifier_type == "random_forest" ) {
         FeaturePoolClassifier *fpc = new FPCRandomForests ( conf, "RandomForest" );
         classifier = new VCFeaturePool ( conf, fpc );
-
-      } else if ( classifier_type == "sparse_logistic_regression" ) {
+      }
+      else if ( classifier_type == "sparse_logistic_regression" ) {
         FeaturePoolClassifier *fpc = new FPCSMLR ( conf, "SparseLogisticRegression" );
         classifier = new VCFeaturePool ( conf, fpc );
 

+ 317 - 317
classifier/kernelclassifier/KCGPRegOneVsAll.cpp

@@ -1,4 +1,4 @@
-/** 
+/**
 * @file KCGPRegOneVsAll.cpp
 * @brief One vs. All interface for kernel classifiers
 * @author Erik Rodner
@@ -32,182 +32,182 @@ using namespace std;
 using namespace OBJREC;
 
 KCGPRegOneVsAll::KCGPRegOneVsAll( const Config *conf, Kernel *kernelFunction, const string & section )
-	: KernelClassifier ( conf, kernelFunction )
+    : KernelClassifier ( conf, kernelFunction )
 {
-	this->maxClassNo = 0;
-	this->verbose = conf->gB( section, "verbose", false );
-	this->optimizeParameters = (kernelFunction == NULL) ? false : conf->gB( section, "optimize_parameters", true );
-	this->maxIterations = conf->gI( section, "optimization_maxiterations", 500 );
-	this->numSamplesCalibration = conf->gI( section, "calibrated_probabilities_numsamples", 2000 );
-	this->calibrateProbabilities = conf->gB( section, "calibrated_probabilities", false );
-	if ( verbose && this->calibrateProbabilities )
-		cerr << "KCGPRegOneVsAll: probability calibration is turned on, this can result in massive additional load!" << endl;
-
-	// we do joint optimization, therefore single classifiers (cloned from prototype)
-	// are not allowed to do optimization themselves
-	Config confNoOptimize ( *conf );
-	confNoOptimize.sB( section, "optimize_parameters", false );
-	this->prototype = new RegGaussianProcess ( &confNoOptimize, kernelFunction, section ); 
-
-	// Do not use this option, unless you know what you are doing!
-	// This function is just necessary for hyperparameter optimization with really large
-	// kernel matrices of a kronecker structure!
-	bool approximateTraceTerm = conf->gB(section, "approximate_trace_term", false);
-	if ( approximateTraceTerm ) 
-		traceApproximation = new TraceApproximation ( conf, section );
-	else
-		traceApproximation = NULL;
-
-	// select final hyperparameters according to leave-one-out
-	useLooParameters = conf->gB(section, "use_loo_parameters", false );
-	
-	// select the criterion
-	modelselcrit = NULL;
-	if ( useLooParameters ) {
-		string modelselcrit_s = conf->gS(section, "loo_crit", "loo_pred_prob" );
-		modelselcrit = GenericGPModelSelection::selectModelSel ( conf, modelselcrit_s );
-		cerr << "KCGPRegOneVsAll: using additional model selection criterion " << modelselcrit_s << endl;
-	}
-
-	// do we want to compute the uncertainty of the estimate ?
-	computeUncertainty = conf->gB(section, "compute_uncertainty", false );
+  this->maxClassNo = 0;
+  this->verbose = conf->gB( section, "verbose", false );
+  this->optimizeParameters = (kernelFunction == NULL) ? false : conf->gB( section, "optimize_parameters", true );
+  this->maxIterations = conf->gI( section, "optimization_maxiterations", 500 );
+  this->numSamplesCalibration = conf->gI( section, "calibrated_probabilities_numsamples", 2000 );
+  this->calibrateProbabilities = conf->gB( section, "calibrated_probabilities", false );
+  if ( verbose && this->calibrateProbabilities )
+    cerr << "KCGPRegOneVsAll: probability calibration is turned on, this can result in massive additional load!" << endl;
+
+  // we do joint optimization, therefore single classifiers (cloned from prototype)
+  // are not allowed to do optimization themselves
+  Config confNoOptimize ( *conf );
+  confNoOptimize.sB( section, "optimize_parameters", false );
+  this->prototype = new RegGaussianProcess ( &confNoOptimize, kernelFunction, section );
+
+  // Do not use this option, unless you know what you are doing!
+  // This function is just necessary for hyperparameter optimization with really large
+  // kernel matrices of a kronecker structure!
+  bool approximateTraceTerm = conf->gB(section, "approximate_trace_term", false);
+  if ( approximateTraceTerm )
+    traceApproximation = new TraceApproximation ( conf, section );
+  else
+    traceApproximation = NULL;
+
+  // select final hyperparameters according to leave-one-out
+  useLooParameters = conf->gB(section, "use_loo_parameters", false );
+
+  // select the criterion
+  modelselcrit = NULL;
+  if ( useLooParameters ) {
+    string modelselcrit_s = conf->gS(section, "loo_crit", "loo_pred_prob" );
+    modelselcrit = GenericGPModelSelection::selectModelSel ( conf, modelselcrit_s );
+    cerr << "KCGPRegOneVsAll: using additional model selection criterion " << modelselcrit_s << endl;
+  }
+
+  // do we want to compute the uncertainty of the estimate ?
+  computeUncertainty = conf->gB(section, "compute_uncertainty", false );
 }
 
 KCGPRegOneVsAll::KCGPRegOneVsAll( const KCGPRegOneVsAll &vcova ): KernelClassifier(vcova)
 {
-	prototype = vcova.prototype->clone();
-	optimizeParameters = vcova.optimizeParameters;
-	verbose = vcova.verbose;
-	maxIterations = vcova.maxIterations;
-	useLooParameters = vcova.useLooParameters;
-	computeUncertainty = vcova.computeUncertainty;
-	choleskyMatrix = vcova.choleskyMatrix;
-	calibrateProbabilities = vcova.calibrateProbabilities;
-	numSamplesCalibration = vcova.numSamplesCalibration;
-	
-	for(int i = 0; i < (int)vcova.classifiers.size(); i++)
-	{
-		classifiers.push_back(pair<int, RegGaussianProcess*>(vcova.classifiers[i].first,vcova.classifiers[i].second->clone()));
-	}
-
-	if ( vcova.traceApproximation == NULL )
-		traceApproximation = NULL;
-	else
-		traceApproximation = new TraceApproximation(*vcova.traceApproximation);
-
-	if ( vcova.modelselcrit == NULL )
-		modelselcrit = NULL;
-	else
-		modelselcrit = new GPMSCLooLikelihoodRegression(*vcova.modelselcrit);
+  prototype = vcova.prototype->clone();
+  optimizeParameters = vcova.optimizeParameters;
+  verbose = vcova.verbose;
+  maxIterations = vcova.maxIterations;
+  useLooParameters = vcova.useLooParameters;
+  computeUncertainty = vcova.computeUncertainty;
+  choleskyMatrix = vcova.choleskyMatrix;
+  calibrateProbabilities = vcova.calibrateProbabilities;
+  numSamplesCalibration = vcova.numSamplesCalibration;
+
+  for (int i = 0; i < (int)vcova.classifiers.size(); i++)
+  {
+    classifiers.push_back(pair<int, RegGaussianProcess*>(vcova.classifiers[i].first, vcova.classifiers[i].second->clone()));
+  }
+
+  if ( vcova.traceApproximation == NULL )
+    traceApproximation = NULL;
+  else
+    traceApproximation = new TraceApproximation(*vcova.traceApproximation);
+
+  if ( vcova.modelselcrit == NULL )
+    modelselcrit = NULL;
+  else
+    modelselcrit = new GPMSCLooLikelihoodRegression(*vcova.modelselcrit);
 }
 
 KCGPRegOneVsAll::~KCGPRegOneVsAll()
 {
-	if ( traceApproximation != NULL )
-		delete traceApproximation;
-	if ( modelselcrit != NULL )
-		delete modelselcrit;
+  if ( traceApproximation != NULL )
+    delete traceApproximation;
+  if ( modelselcrit != NULL )
+    delete modelselcrit;
 }
 
 void KCGPRegOneVsAll::teach ( KernelData *kernelData, const NICE::Vector & y )
 {
-	maxClassNo = (int)y.Max();
-
-	set<int> classesUsed;
-	for ( uint i = 0 ; i < y.size(); i++ )
-		classesUsed.insert ( (int)y[i] );
-	
-	classifiers.clear();
-
-	VVector ySet;
-	VVector ySetZeroMean;
-	for ( set<int>::const_iterator it = classesUsed.begin();
-		it != classesUsed.end(); it++)
-	{
-		int i = *it;
-
-		NICE::Vector ySub ( y.size() );
-		NICE::Vector ySubZeroMean ( y.size() );
-		for ( size_t j = 0 ; j < ySub.size() ; j++ )
-		{
-			ySub[j] = ((int)y[j] == i) ? 1 : 0;
-			ySubZeroMean[j] = ((int)y[j] == i) ? 1 : -1;
-		}
-		ySet.push_back ( ySub );
-		ySetZeroMean.push_back ( ySubZeroMean );
-	}
-
-	// Hyperparameter optimization
-	if ( optimizeParameters ) 
-	{
-		ParameterizedKernel *kernelPara = dynamic_cast< ParameterizedKernel * > ( kernelFunction );
-		if ( kernelPara == NULL ) {
-			fthrow(Exception, "KCGPRegOneVsAll: you have to specify a parameterized kernel !");
-		}
-		GPRegressionOptimizationProblem gpopt ( kernelData, ySetZeroMean, kernelPara, verbose, modelselcrit, traceApproximation );
-
-		// the trust region classifier is better for my large collection of one classification problem :)
-		// FirstOrderRasmussen optimizer;
-		FirstOrderTrustRegion optimizer;
-		optimizer.setMaxIterations ( maxIterations );
-		optimizer.setEpsilonG ( 0.01 );
-
-		cout << "KCGPRegOneVsAll: Hyperparameter optimization ..." << endl;
-		optimizer.optimizeFirst ( gpopt );
-		cout << "KCGPRegOneVsAll: Hyperparameter optimization ...done" << endl;
-	
-		if ( useLooParameters ) 
-		{
-			cerr << "KCGPRegOneVsAll: using best loo parameters" << endl;
-			gpopt.useLooParameters();
-		}
-
-		gpopt.update();
-
-		Vector parameters;
-		kernelPara->getParameters ( parameters );
-		cout << "KCGPRegOneVsAll: Optimization finished: " << parameters << endl << endl;
-	} else {
-		kernelData->updateCholeskyFactorization();
-	}
-	
-	//for binary problems
-	if(classesUsed.size() == 2 && false)
-	{
-		set<int>::const_iterator it = classesUsed.begin();
-		int classno = *it;
-		it++;
-		int classno2 = *it;
-		const Vector & ySub = ySet[0];
-		RegGaussianProcess *classifier;
-		classifier = prototype->clone();
-		if (verbose)
-			fprintf (stderr, "KCGPRegOneVsAll: training classifier class %d <-> %d\n", classno, classno2 );
-		classifier->teach ( kernelData, ySub );
-		classifiers.push_back ( pair<int, RegGaussianProcess*> (classno, classifier) );
-		classifiers.push_back ( pair<int, RegGaussianProcess*> (classno2, classifier) );
-	}
-	else
-	{
-		int i = 0;
-		for ( set<int>::const_iterator it = classesUsed.begin(); it != classesUsed.end(); it++,i++)
-		{
-			int classno = *it;
-			const Vector & ySub = ySet[i];
-			RegGaussianProcess *classifier;
-			classifier = prototype->clone();
-	
-			if (verbose)
-				fprintf (stderr, "KCGPRegOneVsAll: training classifier class %d <-> remainder\n", classno );
-	
-			classifier->teach ( kernelData, ySub );
-
-			classifiers.push_back ( pair<int, RegGaussianProcess*> (classno, classifier) );
-		}
-	}
-
-	if ( computeUncertainty || calibrateProbabilities )
-		choleskyMatrix = kernelData->getCholeskyMatrix();
+  maxClassNo = (int)y.Max();
+
+  set<int> classesUsed;
+  for ( uint i = 0 ; i < y.size(); i++ )
+    classesUsed.insert ( (int)y[i] );
+
+  classifiers.clear();
+
+  VVector ySet;
+  VVector ySetZeroMean;
+  for ( set<int>::const_iterator it = classesUsed.begin();
+        it != classesUsed.end(); it++)
+  {
+    int i = *it;
+
+    NICE::Vector ySub ( y.size() );
+    NICE::Vector ySubZeroMean ( y.size() );
+    for ( size_t j = 0 ; j < ySub.size() ; j++ )
+    {
+      ySub[j] = ((int)y[j] == i) ? 1 : 0;
+      ySubZeroMean[j] = ((int)y[j] == i) ? 1 : -1;
+    }
+    ySet.push_back ( ySub );
+    ySetZeroMean.push_back ( ySubZeroMean );
+  }
+
+  // Hyperparameter optimization
+  if ( optimizeParameters )
+  {
+    ParameterizedKernel *kernelPara = dynamic_cast< ParameterizedKernel * > ( kernelFunction );
+    if ( kernelPara == NULL ) {
+      fthrow(Exception, "KCGPRegOneVsAll: you have to specify a parameterized kernel !");
+    }
+    GPRegressionOptimizationProblem gpopt ( kernelData, ySetZeroMean, kernelPara, verbose, modelselcrit, traceApproximation );
+
+    // the trust region classifier is better for my large collection of one classification problem :)
+    // FirstOrderRasmussen optimizer;
+    FirstOrderTrustRegion optimizer;
+    optimizer.setMaxIterations ( maxIterations );
+    optimizer.setEpsilonG ( 0.01 );
+
+    cout << "KCGPRegOneVsAll: Hyperparameter optimization ..." << endl;
+    optimizer.optimizeFirst ( gpopt );
+    cout << "KCGPRegOneVsAll: Hyperparameter optimization ...done" << endl;
+
+    if ( useLooParameters )
+    {
+      cerr << "KCGPRegOneVsAll: using best loo parameters" << endl;
+      gpopt.useLooParameters();
+    }
+
+    gpopt.update();
+
+    Vector parameters;
+    kernelPara->getParameters ( parameters );
+    cout << "KCGPRegOneVsAll: Optimization finished: " << parameters << endl << endl;
+  } else {
+    kernelData->updateCholeskyFactorization();
+  }
+
+  //for binary problems
+  if (classesUsed.size() == 2 && false)
+  {
+    set<int>::const_iterator it = classesUsed.begin();
+    int classno = *it;
+    it++;
+    int classno2 = *it;
+    const Vector & ySub = ySet[0];
+    RegGaussianProcess *classifier;
+    classifier = prototype->clone();
+    if (verbose)
+      fprintf (stderr, "KCGPRegOneVsAll: training classifier class %d <-> %d\n", classno, classno2 );
+    classifier->teach ( kernelData, ySub );
+    classifiers.push_back ( pair<int, RegGaussianProcess*> (classno, classifier) );
+    classifiers.push_back ( pair<int, RegGaussianProcess*> (classno2, classifier) );
+  }
+  else
+  {
+    int i = 0;
+    for ( set<int>::const_iterator it = classesUsed.begin(); it != classesUsed.end(); it++, i++)
+    {
+      int classno = *it;
+      const Vector & ySubZeroMean = ySetZeroMean[i];
+      RegGaussianProcess *classifier;
+      classifier = prototype->clone();
+
+      if (verbose)
+        fprintf (stderr, "KCGPRegOneVsAll: training classifier class %d <-> remainder\n", classno );
+
+      classifier->teach ( kernelData, ySubZeroMean );
+
+      classifiers.push_back ( pair<int, RegGaussianProcess*> (classno, classifier) );
+    }
+  }
+
+  if ( computeUncertainty || calibrateProbabilities )
+    choleskyMatrix = kernelData->getCholeskyMatrix();
 
 }
 
@@ -218,180 +218,180 @@ void KCGPRegOneVsAll::teach ( KernelData *kernelData, const NICE::Vector & y )
  */
 void KCGPRegOneVsAll::teach ( KernelData *kernelData, const std::vector<double> & y )
 {
-	// FIXME: Do we really need this function? (erik)
-	Vector y_nice (y);
-	teach ( kernelData, y_nice );
+  // FIXME: Do we really need this function? (erik)
+  Vector y_nice (y);
+  teach ( kernelData, y_nice );
 }
 
 
 ClassificationResult KCGPRegOneVsAll::classifyKernel ( const NICE::Vector & kernelVector, double kernelSelf ) const
 {
-	if ( classifiers.size() <= 0 ) 
-		fthrow(Exception, "The classifier was not trained with training data (use teach(...))");
-
-	FullVector scores ( maxClassNo+1 );
-	scores.set(0);
-
-	//for binary problems
-	if(classifiers.size() == 2 && false)
-	{
-		int classno = classifiers[0].first;
-		int classno2 = classifiers[1].first;
-		RegGaussianProcess *classifier = classifiers[0].second;
-		double yEstimate = classifier->predictKernel(kernelVector, kernelSelf);
-		scores[classno] = yEstimate;
-		scores[classno2] = 0;//1-yEstimate;
-		//cout << "i: " << 0 << ": " << scores[classno] << endl;
-		//cout << "i: " << 1 << ": " << scores[classno2] << endl;
-	}
-	else
-	{
+  if ( classifiers.size() <= 0 )
+    fthrow(Exception, "The classifier was not trained with training data (use teach(...))");
+
+  FullVector scores ( maxClassNo + 1 );
+  scores.set(0);
+
+  //for binary problems
+  if (classifiers.size() == 2 && false)
+  {
+    int classno = classifiers[0].first;
+    int classno2 = classifiers[1].first;
+    RegGaussianProcess *classifier = classifiers[0].second;
+    double yEstimate = classifier->predictKernel(kernelVector, kernelSelf);
+    scores[classno] = yEstimate;
+    scores[classno2] = 0;//1-yEstimate;
+    //cout << "i: " << 0 << ": " << scores[classno] << endl;
+    //cout << "i: " << 1 << ": " << scores[classno2] << endl;
+  }
+  else
+  {
 #pragma omp parallel for
-		for ( int classifierIndex = 0 ; classifierIndex < (int)classifiers.size(); classifierIndex++ )
-		{
-			int classno = classifiers[(uint)classifierIndex].first;
-			RegGaussianProcess *classifier = classifiers[(uint)classifierIndex].second;
-			double yEstimate = classifier->predictKernel(kernelVector, kernelSelf);
-			scores[classno] += yEstimate;
-			//cout << "i: " << classifierIndex << ": " << scores[classno] << endl;
-		}
-	}
-
-	double uncertainty = 0.0;
-	if ( computeUncertainty || calibrateProbabilities )
-	{
-		Vector tmp;
-		choleskySolveLargeScale ( choleskyMatrix, kernelVector, tmp );
-
-		// tmp = K^{-1} k*
-		uncertainty = kernelSelf - kernelVector.scalarProduct ( tmp );
-		
-		/*if(uncertainty < 0.0)
-// 			uncertainty = 0.0;*/
-
-		if ( calibrateProbabilities )
-		{
-			/*********************************************************************
-			 * Calibration of probabilities is based on the following
-			 * idea: 
-			 *
-			 * The scores \mu_i (or scores[i]) and the uncertainty
-			 * r.uncertainty are the mean and the variance of the predictive
-			 * distribution p(y_i | ...). So actually we do not know the correct value for
-			 * y_i and therefore just taking the maximum score ignores this uncertainty 
-			 * completely! 
-			 * What we might want to have is the probability for each class k
-			 * p_k = p( k = argmax_i y_i )
-			 *
-			 * Calculating this probability for n>2 is intractable and we
-			 * have to do monte carlo estimation which is performed in the following code
-			 *
-			 * An alternative would be to approximate p_k with 
-			 * p( mu_k >= max_{i != k} y_i ) = prod_{i != k} F_i(mu_k) 
-			 * with F_i being the cumulative distribution of the normal distribution i
-			 *
-			 * Details: Erik Rodner, "Learning with Few Examples for Visual Recognition Problems", PhD thesis
-			 *
-			 ********************************************************************/
-
-			double stddev = sqrt(uncertainty);
-			FullVector calibratedScores ( maxClassNo + 1 );
-			calibratedScores.set(0.0);
-			for ( uint i = 0 ; i < numSamplesCalibration ; i++ )
-			{
-				uint cmaxClassno = 0;
-				double cmax = - std::numeric_limits<double>::max();
-				for ( int classifierIndex = 0 ; classifierIndex < (int)classifiers.size(); classifierIndex++ )
-				{
-					int classno = classifiers[(uint)classifierIndex].first;
-					double s = randGaussDouble ( stddev ) + scores[classno];
-					if ( s > cmax )
-					{
-						cmax = s;
-						cmaxClassno = classno;
-					}
-				}
-				calibratedScores[ cmaxClassno ]++;
-			}
-			calibratedScores.normalize();
-
-			// calibrating probabilities should not affect our hard
-			// decision for a specific class
-			if ( verbose ) {
-				if ( scores.maxElement() != calibratedScores.maxElement() )
-					cerr << "Calibration of probabilities affected the hard decision, you should increase calibrated_probabilities_numsamples !!" << endl;
-			}
-
-			scores = calibratedScores;
-		}
-	}
-
-	ClassificationResult r ( scores.maxElement(), scores );
-	r.uncertainty = uncertainty;
-
-	return r;
+    for ( int classifierIndex = 0 ; classifierIndex < (int)classifiers.size(); classifierIndex++ )
+    {
+      int classno = classifiers[(uint)classifierIndex].first;
+      RegGaussianProcess *classifier = classifiers[(uint)classifierIndex].second;
+      double yEstimate = classifier->predictKernel(kernelVector, kernelSelf);
+      scores[classno] += yEstimate;
+      //cout << "i: " << classifierIndex << ": " << scores[classno] << endl;
+    }
+  }
+
+  double uncertainty = 0.0;
+  if ( computeUncertainty || calibrateProbabilities )
+  {
+    Vector tmp;
+    choleskySolveLargeScale ( choleskyMatrix, kernelVector, tmp );
+
+    // tmp = K^{-1} k*
+    uncertainty = kernelSelf - kernelVector.scalarProduct ( tmp );
+
+    /*if(uncertainty < 0.0)
+    //    uncertainty = 0.0;*/
+
+    if ( calibrateProbabilities )
+    {
+      /*********************************************************************
+       * Calibration of probabilities is based on the following
+       * idea:
+       *
+       * The scores \mu_i (or scores[i]) and the uncertainty
+       * r.uncertainty are the mean and the variance of the predictive
+       * distribution p(y_i | ...). So actually we do not know the correct value for
+       * y_i and therefore just taking the maximum score ignores this uncertainty
+       * completely!
+       * What we might want to have is the probability for each class k
+       * p_k = p( k = argmax_i y_i )
+       *
+       * Calculating this probability for n>2 is intractable and we
+       * have to do monte carlo estimation which is performed in the following code
+       *
+       * An alternative would be to approximate p_k with
+       * p( mu_k >= max_{i != k} y_i ) = prod_{i != k} F_i(mu_k)
+       * with F_i being the cumulative distribution of the normal distribution i
+       *
+       * Details: Erik Rodner, "Learning with Few Examples for Visual Recognition Problems", PhD thesis
+       *
+       ********************************************************************/
+
+      double stddev = sqrt(uncertainty);
+      FullVector calibratedScores ( maxClassNo + 1 );
+      calibratedScores.set(0.0);
+      for ( uint i = 0 ; i < numSamplesCalibration ; i++ )
+      {
+        uint cmaxClassno = 0;
+        double cmax = - std::numeric_limits<double>::max();
+        for ( int classifierIndex = 0 ; classifierIndex < (int)classifiers.size(); classifierIndex++ )
+        {
+          int classno = classifiers[(uint)classifierIndex].first;
+          double s = randGaussDouble ( stddev ) + scores[classno];
+          if ( s > cmax )
+          {
+            cmax = s;
+            cmaxClassno = classno;
+          }
+        }
+        calibratedScores[ cmaxClassno ]++;
+      }
+      calibratedScores.normalize();
+
+      // calibrating probabilities should not affect our hard
+      // decision for a specific class
+      if ( verbose ) {
+        if ( scores.maxElement() != calibratedScores.maxElement() )
+          cerr << "Calibration of probabilities affected the hard decision, you should increase calibrated_probabilities_numsamples !!" << endl;
+      }
+
+      scores = calibratedScores;
+    }
+  }
+
+  ClassificationResult r ( scores.maxElement(), scores );
+  r.uncertainty = uncertainty;
+
+  return r;
 }
 
 KCGPRegOneVsAll* KCGPRegOneVsAll::clone(void) const
 {
-	KCGPRegOneVsAll *classifier = new KCGPRegOneVsAll( *this );
-	return classifier;
+  KCGPRegOneVsAll *classifier = new KCGPRegOneVsAll( *this );
+  return classifier;
 }
 
 void KCGPRegOneVsAll::clear()
 {
-	//nothing to clear
+  //nothing to clear
 }
 
 void KCGPRegOneVsAll::restore(std::istream& ifs, int type)
 {
-	ifs.precision (numeric_limits<double>::digits10 + 1);
-	ifs >> maxClassNo;
-	ifs >> computeUncertainty;
-	ifs >> calibrateProbabilities;
-
-	if(calibrateProbabilities || computeUncertainty)
-	{
-		ifs >> choleskyMatrix;
-	}
-
-	int size;
-	ifs >> size;
-
-	for(int i = 0; i < size; i++)
-	{
-		int tmp;
-		ifs >> tmp;
-		RegGaussianProcess *classifier;
-		classifier = prototype->clone();
-		classifier->restore(ifs);
-		classifiers.push_back ( pair<int, RegGaussianProcess*> (tmp, classifier) );
-	}
-
-	KernelClassifier::restore(ifs,type);
+  ifs.precision (numeric_limits<double>::digits10 + 1);
+  ifs >> maxClassNo;
+  ifs >> computeUncertainty;
+  ifs >> calibrateProbabilities;
+
+  if (calibrateProbabilities || computeUncertainty)
+  {
+    ifs >> choleskyMatrix;
+  }
+
+  int size;
+  ifs >> size;
+
+  for (int i = 0; i < size; i++)
+  {
+    int tmp;
+    ifs >> tmp;
+    RegGaussianProcess *classifier;
+    classifier = prototype->clone();
+    classifier->restore(ifs);
+    classifiers.push_back ( pair<int, RegGaussianProcess*> (tmp, classifier) );
+  }
+
+  KernelClassifier::restore(ifs, type);
 }
 
 void KCGPRegOneVsAll::store(std::ostream& ofs, int type) const
 {
-	ofs.precision (numeric_limits<double>::digits10 + 1);
-	
-	ofs << maxClassNo << endl;
-	ofs << computeUncertainty << endl;
-	ofs << calibrateProbabilities << endl;
-
-	
-	if(calibrateProbabilities || computeUncertainty)
-	{
-		ofs << choleskyMatrix << endl;
-	}
-	
-	ofs << classifiers.size() << endl;
-	for(uint i = 0; i < classifiers.size(); i++)
-	{
-		ofs << classifiers[i].first << endl;
-		classifiers[i].second->store(ofs);
-		ofs << endl;
-	}
-	KernelClassifier::store(ofs,type);
+  ofs.precision (numeric_limits<double>::digits10 + 1);
+
+  ofs << maxClassNo << endl;
+  ofs << computeUncertainty << endl;
+  ofs << calibrateProbabilities << endl;
+
+
+  if (calibrateProbabilities || computeUncertainty)
+  {
+    ofs << choleskyMatrix << endl;
+  }
+
+  ofs << classifiers.size() << endl;
+  for (uint i = 0; i < classifiers.size(); i++)
+  {
+    ofs << classifiers[i].first << endl;
+    classifiers[i].second->store(ofs);
+    ofs << endl;
+  }
+  KernelClassifier::store(ofs, type);
 }
 

+ 2 - 2
classifier/kernelclassifier/progs/libdepend.inc

@@ -5,5 +5,5 @@ $(call PKG_DEPEND_INT,vislearning/baselib)
 $(call PKG_DEPEND_INT,vislearning/cbaselib)
 $(call PKG_DEPEND_INT,vislearning/classifier/kernelclassifier)
 $(call PKG_DEPEND_INT,vislearning/matlabAccessHighLevel)
-
-
+$(call PKG_DEPEND_EXT,MATIO)
+$(call PKG_DEPEND_EXT,HDF5)

+ 56 - 33
classifier/vclassifier/VCNearestNeighbour.cpp

@@ -57,9 +57,9 @@ ClassificationResult VCNearestNeighbour::classify ( const NICE::Vector & x ) con
     priority_queue< pair<double, int> > examples;
     LOOP_ALL(teachSet) 
     {
-	EACH(classno,y)
+      EACH(classno,y)
 
-	double distance = distancefunc->calculate ( x, y );
+      double distance = distancefunc->calculate ( x, y );
 
 	if ( NICE::isNaN(distance) )
 	{
@@ -68,16 +68,16 @@ ClassificationResult VCNearestNeighbour::classify ( const NICE::Vector & x ) con
 	    cerr << y << endl;
 	}
 
-	if ( mindists[classno] > distance )
-	    mindists[classno] = distance;
+      if ( mindists[classno] > distance )
+          mindists[classno] = distance;
 
-	if ( mindist > distance )
-	{
-	    minclass = classno;
-	    mindist  = distance;
-	}
-	if ( K > 1 ) 
-	    examples.push ( pair<double, int> ( -distance, classno ) );
+      if ( mindist > distance )
+      {
+          minclass = classno;
+          mindist  = distance;
+      }
+      if ( K > 1 ) 
+        examples.push ( pair<double, int> ( -distance, classno ) );
     }
 
     if ( mindist == 0.0 )
@@ -88,24 +88,28 @@ ClassificationResult VCNearestNeighbour::classify ( const NICE::Vector & x ) con
 		fprintf (stderr, "class %d : %f\n", i, mindists.get(i) );
 #endif
 
-    if ( K > 1 ) {
-		FullVector votes ( maxClassNo + 1 );
-		votes.set(0.0);
-		for ( int k = 0 ; k < K ; k++ )
-		{
-			const pair<double, int> & t = examples.top();
-			votes[ t.second ]++;
-			examples.pop();
-		}
-		votes.normalize();
-		return ClassificationResult ( votes.maxElement(), votes );
-    } else {
-		for ( int i = 0 ; i < mindists.size() ; i++ )
-		{
-			mindists[i] = 1.0 / (mindists[i] + 1.0);
-		}
-		mindists.normalize();
-		return ClassificationResult ( minclass, mindists );
+    if ( K > 1 )
+    {
+      FullVector votes ( maxClassNo + 1 );
+      votes.set(0.0);
+      for ( int k = 0 ; k < K ; k++ )
+      {
+        const pair<double, int> & t = examples.top();
+        votes[ t.second ]++;
+        examples.pop();
+      }
+      votes.normalize();
+      return ClassificationResult ( votes.maxElement(), votes );
+    }
+    else
+    {
+      //do we really want to do this? Only useful, if we want to obtain probability like scores      
+//       for ( int i = 0 ; i < mindists.size() ; i++ )
+//       {
+//         mindists[i] = 1.0 / (mindists[i] + 1.0);
+//       }
+      //mindists.normalize();
+      return ClassificationResult ( minclass, mindists );
     }
 }
 
@@ -114,13 +118,26 @@ void VCNearestNeighbour::teach ( const LabeledSetVector & _teachSet )
 {
     fprintf (stderr, "teach using all !\n");
     maxClassNo = _teachSet.getMaxClassno();
-    teachSet = _teachSet;
+    //NOTE this is crucial if we clear _teachSet afterwards!
+    //therefore, take care NOT to call _techSet.clear() somewhere out of this method
+    this->teachSet = _teachSet;
+    
+    std::cerr << "number of known training samples: " << this->teachSet.begin()->second.size() << std::endl;
+    
+//     //just for testing - remove everything but the first element
+//     map< int, vector<NICE::Vector *> >::iterator it = this->teachSet.begin();
+//     it++;
+//     this->teachSet.erase(it, this->teachSet.end());
+//     std::cerr << "keep " << this->teachSet.size() << " elements" << std::endl;
+    
+    
 }
 
 
 void VCNearestNeighbour::teach ( int classno, const NICE::Vector & x )
 {
-    fprintf (stderr, "teach!\n");
+    std::cerr << "VCNearestNeighbour::teach one new example" << std::endl;
+    
     for ( size_t i = 0 ; i < x.size() ; i++ )
 	if ( NICE::isNaN(x[i]) ) 
 	{
@@ -132,6 +149,14 @@ void VCNearestNeighbour::teach ( int classno, const NICE::Vector & x )
     if ( classno > maxClassNo ) maxClassNo = classno;
 
     teachSet.add ( classno, x );
+    
+    std::cerr << "adden class " << classno << " with feature " << x << std::endl;
+    int tmpCnt(0);
+    for (LabeledSetVector::const_iterator it = this->teachSet.begin(); it != this->teachSet.end(); it++)
+    {
+      tmpCnt += it->second.size();
+    }
+    std::cerr << "number of known training samples: " << tmpCnt << std::endl;
 }
 
 void VCNearestNeighbour::finishTeaching()
@@ -159,5 +184,3 @@ void VCNearestNeighbour::restore ( std::istream & is, int format )
     teachSet.restore ( is, format );
     maxClassNo = teachSet.getMaxClassno();
 }
-
-

+ 1 - 0
classifier/vclassifier/VCNearestNeighbour.h

@@ -56,6 +56,7 @@ class VCNearestNeighbour : public VecClassifier
 		void store ( std::ostream & os, int format = 0 ) const;
 
 		void restore ( std::istream & is, int format = 0 );
+    
 };
 
 

+ 296 - 0
featureLearning/FeatureLearningClusterBased.cpp

@@ -0,0 +1,296 @@
+
+#include "FeatureLearningClusterBased.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>
+
+//vislearning
+#include <vislearning/baselib/Globals.h>
+// 
+#include <vislearning/math/cluster/KMeans.h>
+#include <vislearning/math/cluster/GMM.h>
+
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+
+  //**********************************************
+  //
+  //                 PROTECTED METHODS
+  //
+  //********************************************** 
+
+void FeatureLearningClusterBased::setClusterAlgo( const std::string & _clusterAlgoString, const bool & _setForInitialTraining)
+{
+  //be careful with previously allocated memory
+  if (this->clusterAlgo != NULL)
+    delete clusterAlgo;
+  
+  if (_clusterAlgoString.compare("kmeans") == 0)
+  {
+    if ( _setForInitialTraining )
+      this->clusterAlgo = new OBJREC::KMeans(this->initialNumberOfClusters);
+    else
+      this->clusterAlgo = new OBJREC::KMeans(this->numberOfClustersForNewImage);
+  }
+  else if (_clusterAlgoString.compare("GMM") == 0) 
+  {
+    if ( _setForInitialTraining )
+      this->clusterAlgo = new OBJREC::GMM(this->conf, this->initialNumberOfClusters);
+    else
+      this->clusterAlgo = new OBJREC::GMM(this->conf, this->numberOfClustersForNewImage);      
+  }
+  else
+  {
+    std::cerr << "Unknown cluster algorithm selected, use k-means instead" << std::endl;
+    if ( _setForInitialTraining )      
+      this->clusterAlgo = new OBJREC::KMeans(this->initialNumberOfClusters);
+    else
+      this->clusterAlgo = new OBJREC::KMeans(this->numberOfClustersForNewImage);
+  }    
+}
+
+
+  //**********************************************
+  //
+  //                 PUBLIC METHODS
+  //
+  //********************************************** 
+
+
+FeatureLearningClusterBased::FeatureLearningClusterBased ( const Config *_conf,
+                               const MultiDataset *_md, const std::string & _section )
+    : FeatureLearningPrototypes ( _conf, _md, _section )
+{ 
+  
+   // define the number of clusters we want to compute for an unseen image
+  numberOfClustersForNewImage = conf->gI(section, "numberOfClustersForNewImage", 10);
+   
+  //**********************************************
+  //
+  //      SET UP VARIABLES AND METHODS
+  //             - FEATURE TYPE
+  //             - CLUSTERING ALGO
+  //             - DISTANCE FUNCTION
+  //             - ...
+  //
+  //**********************************************  
+  
+   
+  //run the training to initially compute a codebook and stuff like that
+//  this->train( _md );
+   
+  // define the clustering algorithm to be used
+  std::string clusterAlgoString = conf->gS(section, "clusterAlgo", "kmeans");  
+  this->setClusterAlgo( clusterAlgoString, false /*set cluster algo for feature learning*/ );
+}
+
+FeatureLearningClusterBased::~FeatureLearningClusterBased()
+{
+  // clean-up
+}
+
+void FeatureLearningClusterBased::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();
+  }
+  
+  //cluster features
+  std::cerr << " CLUSTER FEATURES FROM UNSEEN IMAGE" << std::endl;
+  NICE::VVector prototypesForNewImage;
+  std::vector< double > weights;
+  std::vector< int > assignment;
+  clusterAlgo->cluster ( newFeatures, prototypesForNewImage, weights, assignment);
+  
+  if ( b_evaluationWhileFeatureLearning )
+  {
+    //visualize new clusters
+    int tmpProtCnt ( 0 );    
+    for (NICE::VVector::const_iterator protIt = prototypesForNewImage.begin(); protIt != prototypesForNewImage.end(); protIt++, tmpProtCnt++)
+    {
+      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, *protIt );
+        if ( tmpDist < distToNewCluster )
+        {
+          distToNewCluster = tmpDist;
+          indexOfMostSimFeat = tmpCnt;
+        }
+      }
+      
+      int posX ( ( positions[indexOfMostSimFeat] ) [0]  );
+      int posY ( ( positions[indexOfMostSimFeat] ) [1]  );
+      
+      NICE::Circle circ ( Coord( posX, posY), 10 /* radius*/, Color(200,0,255) );
+      img.draw(circ);       
+    }
+    
+    
+    //draw features most similar to old clusters
+    tmpProtCnt = 0;
+    for (NICE::VVector::const_iterator protIt = prototypes.begin(); protIt != prototypes.end(); protIt++, tmpProtCnt++)
+    {
+      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, *protIt );
+        if ( tmpDist < distToNewCluster )
+        {
+          distToNewCluster = tmpDist;
+          indexOfMostSimFeat = tmpCnt;
+        }
+      }
+      
+      int posX ( ( positions[indexOfMostSimFeat] ) [0]  );
+      int posY ( ( positions[indexOfMostSimFeat] ) [1]  );
+      NICE::Circle circ ( Coord( posX, posY), 5 /* radius*/, Color(200,255,0 ) );
+      img.draw(circ);      
+    }
+    
+    if ( b_showResults )
+      showImage(img, "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() + "_1_oldAndNewClusters.ppm");
+      img.writePPM( destination );
+    }   
+  }
+  
+  //compute score for every cluster: #assigned features * distance to current cluster centers
+  
+  NICE::Vector distancesToCurrentClusters ( numberOfClustersForNewImage, 0.0 );
+  NICE::Vector clusterSizes ( numberOfClustersForNewImage, 0.0 ); //i.e., the number of assignments, or a derived number
+   
+  //compute "relevance" of every new cluster
+ 
+  std::cerr << " COMPUTE SIZES OF NEW CLUSTERS" << std::endl;
+  for (std::vector<int>::const_iterator assignIt = assignment.begin(); assignIt != assignment.end(); assignIt++)
+  {
+    clusterSizes[*assignIt]++;
+  }
+  clusterSizes.normalizeL1();
+  
+  std::cerr << "cluster Sizes: " << clusterSizes << std::endl;
+  
+  
+  //compute distances of new cluster centers to old cluster centers
+  std::cerr << " COMPUTE DISTANCES BETWEEN NEW AND OLD CLUSTERS" << std::endl;
+  NICE::Vector::iterator distanceIt = distancesToCurrentClusters.begin();
+  for ( NICE::VVector::const_iterator newProtIt = prototypesForNewImage.begin(); newProtIt != prototypesForNewImage.end(); newProtIt++, distanceIt++)
+  {
+    double minDist ( std::numeric_limits<double>::max() );
+    double tmpDist;
+    for ( NICE::VVector::const_iterator protIt = prototypes.begin(); protIt != prototypes.end(); protIt ++)
+    {
+        //compute distance
+        tmpDist = this->distFunction->calculate( *protIt, *newProtIt );
+        if (tmpDist < minDist)
+          minDist = tmpDist;      
+    }
+    
+    *distanceIt = minDist;
+  }
+  
+  std::cerr << "distances: " << distancesToCurrentClusters << std::endl;
+  
+  //compute final scores for the new image
+  NICE::Vector clusterScores ( numberOfClustersForNewImage, 0.0 );
+  for (uint i = 0; i < numberOfClustersForNewImage; i++)
+  {
+      clusterScores[i] = clusterSizes[i] * distancesToCurrentClusters[i];
+  }
+  
+  std::cerr << "final cluster scores for new image: " << clusterScores << std::endl;
+    
+  NICE::Vector chosenClusterCenter ( prototypesForNewImage[ clusterScores.MaxIndex()  ] );
+  
+  
+  //include the chosen information into the currently used prototypes
+  prototypes.push_back( chosenClusterCenter );
+  
+  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, chosenClusterCenter );
+      if ( tmpDist < distToNewCluster )
+      {
+        distToNewCluster = tmpDist;
+        indexOfMostSimFeat = tmpCnt;
+      }
+    }
+    
+    int posX ( ( positions[indexOfMostSimFeat] ) [0]  );
+    int posY ( ( positions[indexOfMostSimFeat] ) [1]  );
+    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)++;  
+}

+ 69 - 0
featureLearning/FeatureLearningClusterBased.h

@@ -0,0 +1,69 @@
+/**
+ * @file FeatureLearningClusterBased.h
+ * @brief compute new histogram entries by clustering new features and take centers of clusters which are relevant and novel
+ * @author Alexander Freytag
+ * @date 16-04-2013 (dd-mm-yyyy)
+*/
+#ifndef _INCLUDEFEATURELEARNINGCLUSTERBASED
+#define _INCLUDEFEATURELEARNINGCLUSTERBASED
+
+#include "FeatureLearningPrototypes.h"
+
+#include <string>
+
+
+namespace OBJREC
+{
+
+  /**
+   * @class FeatureLearningClusterBased
+   * @brief compute new histogram entries by clustering new features and take centers of clusters which are relevant and novel
+   * @author Alexander Freytag
+   * @date 16-04-2013 (dd-mm-yyyy)
+  */  
+  
+  class FeatureLearningClusterBased : public FeatureLearningPrototypes
+  {
+
+    protected:
+           
+      /************************
+       * 
+       *   protected variables
+       * 
+       **************************/       
+      
+       //! define the number of clusters we want to compute for an unseen image
+      int numberOfClustersForNewImage;      
+
+      /************************
+       * 
+       *   protected methods
+       * 
+       **************************/  
+      
+      void setClusterAlgo( const std::string & _clusterAlgoString, const bool & _setForInitialTraining);
+
+
+    public:
+
+      /** constructor
+        *  @param _conf needs a configfile
+        *  @param _md and a MultiDataset (contains images and other things)
+        */
+      FeatureLearningClusterBased ( const NICE::Config *_conf, const OBJREC::MultiDataset *_md , const std::string & _section = "featureLearning");
+
+      /** simple destructor */
+      virtual ~FeatureLearningClusterBased();
+      
+      /** this function has to be overloaded by all subclasses
+          @param imgWithNovelContent 
+      */
+      virtual void learnNewFeatures ( const std::string & filename ) ;      
+
+  };
+
+
+} // namespace
+
+#endif

+ 43 - 0
featureLearning/FeatureLearningGeneric.cpp

@@ -0,0 +1,43 @@
+/**
+* @file FeatureLearningGeneric.cpp
+* @brief abstract interface for feature learning algorithms
+* @author Alexander Freytag
+* @date 16-04-2013 (dd-mm-yyyy)
+
+*/
+#include <iostream>
+
+#include <vislearning/baselib/Preprocess.h>
+
+#include "FeatureLearningGeneric.h"
+
+using namespace OBJREC;
+using namespace std;
+using namespace NICE;
+
+FeatureLearningGeneric::FeatureLearningGeneric ( const Config *_conf, const std::string & _section )
+{
+  this->section = _section;  
+  this->conf = _conf;  
+  
+  this->cacheInitialCodebook = this->conf->gS(this->section, "cacheInitialCodebook", "");
+  this-> b_loadInitialCodebook = this->conf->gB(this->section, "loadInitialCodebook", "");
+  this-> b_saveInitialCodebook = this->conf->gB(this->section, "saveInitialCodebook", "");  
+  
+  this->b_evaluationWhileFeatureLearning = this->conf->gB( this->section, "evaluationWhileFeatureLearning", false );
+  
+  this->b_showTrainingImages = conf->gB( section, "showTrainingImages", false );  
+  this->b_showResults = conf->gB( section, "showResults", false );
+  
+  this->s_resultdir = conf->gS( section, "resultdir", "/tmp/");  
+  
+  Preprocess::Init ( _conf );
+}
+
+FeatureLearningGeneric::~FeatureLearningGeneric()
+{
+}
+
+void FeatureLearningGeneric::learnNewFeatures ( const std::string & _filename )
+{
+}

+ 130 - 0
featureLearning/FeatureLearningGeneric.h

@@ -0,0 +1,130 @@
+/**
+ * @file FeatureLearningGeneric.h
+ * @brief abstract interface for feature learning algorithms
+ * @author Alexander Freytag
+ * @date 16-04-2013 (dd-mm-yyyy)
+*/
+#ifndef _INCLUDEFEATURELEARNING
+#define _INCLUDEFEATURELEARNING
+
+#define ROADWORKS fthrow(NICE::Exception, "Feature Learning -- not yet implemented!");
+
+//STL
+#include <string>
+//
+//core
+#include <core/basics/Config.h>
+#include <core/image/ImageT.h>
+#include <core/vector/VVector.h>
+//
+//vislearning
+#include <vislearning/cbaselib/CachedExample.h>
+
+
+
+namespace OBJREC
+{
+
+  /**
+   * @class FeatureLearningGeneric
+   * @brief abstract interface for feature learning algorithms
+   * @author Alexander Freytag
+   * @date 16-04-2013 (dd-mm-yyyy)
+  */
+  class FeatureLearningGeneric
+  {
+
+    protected:   
+      
+      /************************
+       * 
+       *   protected variables
+       * 
+       **************************/       
+      
+      //! section information for parsing config files
+      std::string section;      
+      
+      //! Configuration File
+      const NICE::Config *conf;    
+      
+      //! where should an initial codebook be located, i.e., read from and written to?
+      std::string cacheInitialCodebook;
+      //! was an initial codebook already computed?
+      bool b_loadInitialCodebook;
+      //!shall the initially computed codebook be stored somewhere?
+      bool  b_saveInitialCodebook; 
+      
+      //! additional evaluation in the process of feature learning, e.g., visualize the most useful features in the current image
+      bool b_evaluationWhileFeatureLearning;
+      
+      bool b_showTrainingImages;
+      bool b_showResults;
+  
+      std::string s_resultdir;
+     
+      
+      /************************
+       * 
+       *   protected methods
+       * 
+       **************************/      
+      
+      /**
+       * @brief Load a previously computed codebook which serves as initial codebook
+       * @author Alexander Freytag
+       * @date 17-04-2013 (dd-mm-yyyy)
+       * @return bool (success of loading)
+       * @note This function has to be overloaded by all subclasses!
+       */
+      virtual bool loadInitialCodebook ( ) = 0;
+      
+      /**
+       * @brief Store the initially computed codebook
+       * @author Alexander Freytag
+       * @date 17-04-2013 (dd-mm-yyyy)
+       * @return bool (success of writing) 
+       * @note This function has to be overloaded by all subclasses!
+       */      
+      virtual bool writeInitialCodebook ( ) = 0;
+      
+
+    public:
+
+      /**
+       * @brief  simple constructor
+       * @author Alexander Freytag
+       * @date 16-04-2013 (dd-mm-yyyy)
+       * @param _conf global settings
+       * @param _section section information for parsing config files
+      */
+      FeatureLearningGeneric ( const NICE::Config *_conf, const std::string & _section = "featureLearning" );
+
+      /** simple destructor */
+      virtual ~FeatureLearningGeneric();
+
+      
+      /** 
+       * @brief  Learn new features to explain a previously unseen image with novel content
+       * @author Alexander Freytag
+       * @date 16-04-2013 (dd-mm-yyyy)
+       * @param _filename of the new image 
+       * @note This function has to be overloaded by all subclasses!          
+      */
+      virtual void learnNewFeatures ( const std::string & _filename) = 0;  
+      
+      virtual NICE::FloatImage evaluateCurrentCodebookByDistance ( const std::string & _filename , const bool & beforeComputingNewFeatures = true) = 0;
+      
+      virtual NICE::ImageT<int> evaluateCurrentCodebookByAssignments ( const std::string & _filename , const bool & beforeComputingNewFeatures = true, const bool & _binaryShowLatestPrototype = false) = 0;      
+      
+      virtual void evaluateCurrentCodebookByConfusionMatrix( NICE::Matrix & _confusionMat ) = 0; 
+      
+      virtual NICE::VVector * getCurrentCodebook() = 0;
+  
+
+  };
+
+
+} // namespace
+
+#endif

+ 707 - 0
featureLearning/FeatureLearningPrototypes.cpp

@@ -0,0 +1,707 @@
+
+#include "FeatureLearningPrototypes.h"
+
+//STL
+#include <iostream>
+
+//core
+#include <core/image/FilterT.h>
+#include <core/image/CircleT.h>
+#include <core/image/Convert.h>
+#include <core/imagedisplay/ImageDisplay.h>
+#include <core/vector/VectorT.h>
+
+//vislearning
+#include <vislearning/features/localfeatures/LFonHSG.h>
+#include <vislearning/features/localfeatures/LFColorSande.h>
+#include <vislearning/features/localfeatures/LFColorWeijer.h>
+#include <vislearning/features/localfeatures/LFReadCache.h>
+#include <vislearning/features/localfeatures/LFWriteCache.h>
+// 
+#include <vislearning/math/cluster/KMeans.h>
+#include <vislearning/math/cluster/KMedian.h>
+#include <vislearning/math/cluster/GMM.h>
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+
+  //**********************************************
+  //
+  //                 PROTECTED METHODS
+  //
+  //********************************************** 
+
+void FeatureLearningPrototypes::setClusterAlgo( const std::string & _clusterAlgoString)
+{
+  //be careful with previously allocated memory
+  if (this->clusterAlgo != NULL)
+    delete clusterAlgo;
+  
+  if (_clusterAlgoString.compare("kmeans") == 0)
+  {
+    this->clusterAlgo = new OBJREC::KMeans(this->initialNumberOfClusters);
+  }
+  else if (_clusterAlgoString.compare("kmedian") == 0)
+  {
+    this->clusterAlgo = new OBJREC::KMedian(this->initialNumberOfClusters);
+  }  
+  else if (_clusterAlgoString.compare("GMM") == 0) 
+  {
+    this->clusterAlgo = new OBJREC::GMM(this->conf, this->initialNumberOfClusters);
+  }
+  else
+  {
+    std::cerr << "Unknown cluster algorithm selected, use k-means instead" << std::endl;
+    this->clusterAlgo = new OBJREC::KMeans(this->initialNumberOfClusters);
+  }    
+}
+
+void FeatureLearningPrototypes::setFeatureExtractor( const bool & _setForTraining )
+{  
+  //be careful with previously allocated memory
+  if (this->featureExtractor != NULL)
+    delete featureExtractor;  
+  
+    //feature stuff
+  // which OpponentSIFT implementation to use {NICE, VANDESANDE}
+  std::string opSiftImpl;  
+  opSiftImpl = this->conf->gS ( "Descriptor", "implementation", "VANDESANDE" );
+  // read features?
+  bool readfeat;
+  readfeat = this->conf->gB ( "Descriptor", "read", true );
+  // write features?
+  bool writefeat;  
+  writefeat = this->conf->gB ( "Descriptor", "write", true );   
+  
+  // Welche Opponentsift Implementierung soll genutzt werden ?
+  LocalFeatureRepresentation *cSIFT = NULL;
+  LocalFeatureRepresentation *writeFeats = NULL;
+  LocalFeatureRepresentation *readFeats = NULL;
+  this->featureExtractor = NULL;
+  if ( opSiftImpl == "NICE" )
+  {
+    if ( _setForTraining )
+      cSIFT = new OBJREC::LFonHSG ( this->conf, "HSGTrain" );
+    else
+      cSIFT = new OBJREC::LFonHSG ( this->conf, "HSGTest" );
+  }
+  else if ( opSiftImpl == "VANDESANDE" )
+  {
+    if ( _setForTraining )
+      cSIFT = new OBJREC::LFColorSande ( this->conf, "LFColorSandeTrain" );
+    else
+      cSIFT = new OBJREC::LFColorSande ( this->conf, "LFColorSandeTest" );
+  }
+  else
+  {
+    fthrow ( Exception, "feattype: %s not yet supported" << opSiftImpl );
+  }
+
+  this->featureExtractor = cSIFT;
+  
+  if ( writefeat )
+  {
+    // write the features to a file, if there isn't any to read
+    writeFeats = new LFWriteCache ( this->conf, cSIFT );
+    this->featureExtractor = writeFeats;
+  }
+
+  if ( readfeat )
+  {
+    // read the features from a file
+    if ( writefeat )
+    {
+      readFeats = new LFReadCache ( this->conf, writeFeats, -1 );
+    }
+    else
+    {
+      readFeats = new LFReadCache ( this->conf, cSIFT, -1 );
+    }
+    this->featureExtractor = readFeats; 
+  }  
+  
+  //only set feature stuff to NULL, deletion of the underlying object is done in the destructor
+  if ( cSIFT != NULL )
+    cSIFT = NULL;
+  if ( writeFeats != NULL )
+    writeFeats = NULL;
+  if ( readFeats != NULL )
+    readFeats  = NULL ;   
+}
+
+void FeatureLearningPrototypes::extractFeaturesFromTrainingImages( const OBJREC::MultiDataset *_md, NICE::VVector & examplesTraining )
+{
+  examplesTraining.clear();
+  
+  int numberOfTrainImage ( 0 );
+  
+  const LabeledSet *trainFiles = (*_md)["train"]; 
+  
+  //run over all training images
+  LOOP_ALL_S( *trainFiles )
+  {
+      EACH_INFO( classno, info );
+      std::string filename = info.img();
+            
+      NICE::ColorImage img( filename );
+      if ( b_showTrainingImages )
+      {
+        showImage( img, "Input" );    
+      }
+      
+      //variables to store feature informatio
+      NICE::VVector features;
+      NICE::VVector cfeatures;
+      NICE::VVector positions;
+
+      //compute features
+      Globals::setCurrentImgFN ( filename );
+      if (featureExtractor == NULL)
+        std::cerr << "feature Extractor is NULL" << std::endl;
+      else
+        featureExtractor->extractFeatures ( img, features, positions );
+            
+      //store feature information in larger data structure
+      for ( NICE::VVector::iterator i = features.begin();
+            i != features.end();
+            i++)
+      {              
+        //normalization :)
+        i->normalizeL1();
+
+        examplesTraining.push_back(*i);
+      }
+      
+      //don't waste memory
+      features.clear();
+      positions.clear();      
+      numberOfTrainImage++;
+  }//Loop over all training images    
+}
+
+void FeatureLearningPrototypes::train ( const OBJREC::MultiDataset *_md )
+{  
+  bool loadSuccess = this->loadInitialCodebook();
+  
+  if ( !loadSuccess )
+  {
+    //**********************************************
+    //
+    //     EXTRACT FEATURES FROM TRAINING IMAGES
+    //
+    //**********************************************  
+    
+    std::cerr << " EXTRACT FEATURES FROM TRAINING IMAGES" << std::endl;
+    
+    NICE::VVector examplesTraining;  
+    this->extractFeaturesFromTrainingImages( _md, examplesTraining  );
+    
+    //**********************************************
+    //
+    //    CLUSTER FEATURES FROM TRAINING IMAGES
+    //
+    //    THIS GIVES US AN INITIAL CODEBOOK
+    //
+    //**********************************************  
+    std::cerr << " CLUSTER FEATURES FROM TRAINING IMAGES" << std::endl;
+    //go, go, go...  
+    prototypes.clear();
+    std::vector< double > weights;
+    std::vector< int > assignment;
+    clusterAlgo->cluster ( examplesTraining, prototypes, weights, assignment);
+    weights.clear();
+    assignment.clear();  
+    
+    //normalization
+    for (NICE::VVector::iterator protoIt = prototypes.begin(); protoIt != prototypes.end(); protoIt++)
+    {
+      protoIt->normalizeL1();
+    }
+  }
+  
+  this->writeInitialCodebook();
+}
+
+bool FeatureLearningPrototypes::loadInitialCodebook ( )
+{
+  if ( b_loadInitialCodebook  )
+  {
+    std::cerr << " INITIAL CODEBOOK ALREADY COMPUTED - RE-USE IT" << std::endl;    
+    std::cerr << " // WARNING - WE DO NOT VERIFY WHETHER THIS IS THE CORRECT CODEBOOK FOR THIS TRAINING SET!!!!" << std::endl;    
+    
+    prototypes.clear();
+    
+    try
+    {
+      prototypes.read(cacheInitialCodebook);
+    }
+    catch (...)
+    {
+      std::cerr << "Error while loading initial codebook from " << cacheInitialCodebook << std::endl;
+      return false;
+    }  
+    return true;
+  }
+  else
+    return false;
+}
+
+bool FeatureLearningPrototypes::writeInitialCodebook ( )
+{      
+  if (  b_saveInitialCodebook )
+  {
+    std::cerr << " SAVE INITIAL CODEBOOK " << std::endl;
+    
+    try 
+    {
+      prototypes.write( cacheInitialCodebook );
+    }
+    catch (...)
+    {
+      std::cerr << "Error while saving initial codebook" << std::endl;
+      return false;
+    }    
+    return true;
+  } 
+  else
+    return false;
+}
+
+
+void FeatureLearningPrototypes::evaluateCurrentCodebookForGivenFeatures(  const NICE::VVector & _features,
+                                                                          const NICE::VVector & _positions,
+                                                                          NICE::FloatImage & _noveltyImageGaussFiltered,
+                                                                          NICE::FloatImage * _noveltyImage                                                                        )
+{
+  bool wasNoveltyImageGiven ( true );
+  if ( _noveltyImage == NULL )
+  {
+    _noveltyImage = new FloatImage ( _noveltyImageGaussFiltered.width(), _noveltyImageGaussFiltered.height() );
+    wasNoveltyImageGiven = false;
+  }
+  
+  _noveltyImageGaussFiltered.set( 0.0 );
+  _noveltyImage->set( 0.0 );
+     
+  
+  NICE::VVector::const_iterator posIt = _positions.begin();
+  for ( NICE::VVector::const_iterator i = _features.begin();
+        i != _features.end();
+        i++, posIt++)
+  {              
+    
+    //loop over codebook representatives
+    double minDist ( std::numeric_limits<double>::max() );
+    for (NICE::VVector::const_iterator it =  prototypes.begin(); it != prototypes.end(); it++)
+    {
+      //compute distance
+      double tmpDist ( this->distFunction->calculate(*i,*it) );
+      if (tmpDist < minDist)
+        minDist = tmpDist;
+    }
+
+    //take minimum distance and store in in a float image    
+    (*_noveltyImage) ( (*posIt)[0], (*posIt)[1]  ) = minDist;
+  } 
+
+  
+  //gauss-filtering for nicer visualization
+  float sigma ( 3.0 );
+  FilterT<float, float, float> filter;
+  filter.filterGaussSigmaApproximate ( *_noveltyImage, sigma, & _noveltyImageGaussFiltered );
+    
+  if ( ! wasNoveltyImageGiven )
+    delete _noveltyImage;
+}
+
+  //**********************************************
+  //
+  //                 PUBLIC METHODS
+  //
+  //********************************************** 
+
+
+FeatureLearningPrototypes::FeatureLearningPrototypes ( const Config *_conf,
+                               const MultiDataset *_md, const std::string & _section )
+    : FeatureLearningGeneric ( _conf, _section )
+{ 
+  
+  // define the initial number of clusters our codebook shall contain
+  initialNumberOfClusters = conf->gI(section, "initialNumberOfClusters", 10);
+  
+  // define the clustering algorithm to be used
+  std::string clusterAlgoString = conf->gS(section, "clusterAlgo", "kmeans");
+  
+  // define the distance function to be used
+  std::string distFunctionString = conf->gS(section, "distFunction", "euclidian");    
+  
+  
+  //**********************************************
+  //
+  //      SET UP VARIABLES AND METHODS
+  //             - FEATURE TYPE
+  //             - CLUSTERING ALGO
+  //             - DISTANCE FUNCTION
+  //             - ...
+  //
+  //**********************************************  
+  
+  std::cerr << " SET UP VARIABLES AND METHODS " << std::endl;
+
+  //feature extraction for initial codebook
+  this->featureExtractor = NULL;
+  this->setFeatureExtractor( true /* set for training */ );  
+  
+  //clustering algorithm
+  this->clusterAlgo = NULL;
+  this->setClusterAlgo( clusterAlgoString );
+  
+  if (distFunctionString.compare("euclidian") == 0)
+  {
+    distFunction = new NICE::EuclidianDistance<double>();
+  }
+  else
+  {
+    std::cerr << "Unknown vector distance selected, use euclidian instead" << std::endl;
+    distFunction = new NICE::EuclidianDistance<double>();
+  }    
+  
+  //run the training to initially compute a codebook and stuff like that
+  this->train( _md );  
+    
+  //so far, we have not seen any new image
+  this->newImageCounter = 0;
+  
+  //TODO stupid
+  this->maxValForVisualization = conf->gD( section, "stupidMaxValForVisualization", 0.005 ) ;
+  
+  
+  //feature extraction for unseen images
+  this->setFeatureExtractor( false /* set for training */ );    
+}
+
+FeatureLearningPrototypes::~FeatureLearningPrototypes()
+{
+  // clean-up
+  if ( clusterAlgo != NULL )
+    delete clusterAlgo;
+  if ( distFunction != NULL )
+    delete distFunction;
+  if ( featureExtractor != NULL )
+    delete featureExtractor; 
+}
+
+NICE::FloatImage FeatureLearningPrototypes::evaluateCurrentCodebookByDistance ( const std::string & _filename , const bool & beforeComputingNewFeatures )
+{
+  std::cerr << " VISUALIZATION -----    maxValForVisualization: " << maxValForVisualization << std::endl;
+  
+    NICE::ColorImage img( _filename );
+    if ( b_showTrainingImages )
+    {
+      showImage( img, "Input" );    
+    }
+    
+    int xsize ( img.width() );
+    int ysize ( img.height() );
+    
+    //variables to store feature information
+    NICE::VVector features;
+    NICE::VVector cfeatures;
+    NICE::VVector positions;
+
+    //compute features
+    Globals::setCurrentImgFN ( _filename );
+    featureExtractor->extractFeatures ( img, features, positions );
+    
+    //normalization
+    for ( NICE::VVector::iterator i = features.begin();
+          i != features.end();
+          i++)
+    {              
+      //normalization :)
+      i->normalizeL1();
+    }
+    
+    FloatImage noveltyImage ( xsize, ysize );
+    FloatImage noveltyImageGaussFiltered ( xsize, ysize );
+    
+    this->evaluateCurrentCodebookForGivenFeatures( features, positions, noveltyImageGaussFiltered, &noveltyImage );
+    
+    double maxDist ( noveltyImage.max() );
+    double maxFiltered ( noveltyImageGaussFiltered.max() );
+
+    std::cerr << "maximum distance of Training images: " << maxDist << std::endl;  
+    std::cerr << "maximum distance of Training images after filtering: " << maxFiltered << std::endl;      
+    if ( beforeComputingNewFeatures )
+      this->oldMaxDist = maxFiltered;
+
+    
+    //convert float to RGB
+    NICE::ColorImage noveltyImageRGB ( xsize, ysize  );
+    if ( beforeComputingNewFeatures )
+    {
+      imageToPseudoColorWithRangeSpecification( noveltyImageGaussFiltered, noveltyImageRGB, 0 /* min */, maxValForVisualization /* maxFiltered*/ /* max */ );
+      std::cerr << "set max value to: " << noveltyImageGaussFiltered.max() << std::endl;
+    }
+    else
+    {
+      imageToPseudoColorWithRangeSpecification( noveltyImageGaussFiltered, noveltyImageRGB, 0 /* min */, maxValForVisualization /*this->oldMaxDist*/ /* max */ );
+      std::cerr << "set max value to: " << this->oldMaxDist << std::endl;
+    }
+    
+    
+    
+    if ( b_showResults )
+      showImage(noveltyImageRGB, "Novelty Image");  
+    else 
+    {
+      std::vector< std::string > list2;
+      StringTools::split ( _filename, '/', list2 );      
+
+      std::string destination ( s_resultdir + NICE::intToString(this->newImageCounter -1 ) + "_" + list2.back() + "_3_updatedNoveltyMap.ppm");
+      if ( beforeComputingNewFeatures )
+        destination  =  s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_0_initialNoveltyMap.ppm";
+
+      noveltyImageRGB.writePPM( destination );
+    }
+        
+    // now look where the closest features for the current cluster indices are
+    int tmpProtCnt ( 0 );
+    for (NICE::VVector::const_iterator protIt = prototypes.begin(); protIt != prototypes.end(); protIt++, tmpProtCnt++)
+    {
+      double distToCurrentCluster ( std::numeric_limits<double>::max() );
+      int indexOfMostSimFeat( 0 );
+      double tmpDist;
+      int featureCnt ( 0 );
+      
+      for ( NICE::VVector::iterator i = features.begin();
+            i != features.end();
+            i++, featureCnt++)
+      {
+        tmpDist = this->distFunction->calculate( *i, *protIt );
+        if ( tmpDist < distToCurrentCluster )
+        {
+          distToCurrentCluster = tmpDist;
+          indexOfMostSimFeat = featureCnt;
+        }
+      }
+      
+      int posX ( ( positions[indexOfMostSimFeat] ) [0]  );
+      int posY ( ( positions[indexOfMostSimFeat] ) [1]  );
+      
+      //position (for OpponentSIFT of van de Sande): x y scale orientation cornerness
+      
+      /*What is the interpretation of scale?
+
+      The scale parameter was implemented to correspond with the Gaussian filter sigma at which points were detected. Therefore, the
+      scale is not directly interpretable as the size of the region described in terms of number of pixels. However, it is linearly
+      related the radius of the circular area described. To capture the area of the Gaussian originally used, we have a 3x 
+      magnification factor. But, remember that SIFT has 4x4 cells, and this is a measure for a single cell. So, because we are 
+      working with a radius, multiply by 2. Due to the square shape of the region, we need to extend the outer radius even further 
+      by sqrt(2), otherwise the corners of the outer cells are cut off by our circle. So, the largest outer radius is 
+      Round(scale * 3 * 2 * sqrt(2)). The area from which the SIFT descriptor is computed is a square which fits within a circle 
+      of this radius. Also, due to the Gaussian weighting applied within SIFT, the area that really matters is much, much smaller: 
+      the outer parts get a low weight. 
+
+      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 
+      21x21patch. However, the square area which fits inside this circle is smaller: about 15x15. The corners of this 15x15square 
+      touch the outer circle. */
+      
+      /*Why is the direction (angle) field always 0?
+
+
+      Estimating the dominant orientation of a descriptor is useful in matching scenarios. However, in an object/scene categorization
+      setting, the additional invariance reduces accuracy. Being able to discriminate between dominant directions of up and right 
+      is very useful here, and rotated down images are quite rare in an object categorization setting. Therefore, orientation 
+      estimation is disabled in the color descriptor software. The subsequent rotation of the descriptor to achieve 
+      rotation-invariance is still possible by supplying your own regions and angles for an image (through --loadRegions). However, 
+      by default, no such rotation is performed, since the default angle is 0. */      
+      
+      
+      //adapt the pseudo color transformation as done in Convert.cpp
+        size_t seg = ( size_t ) ( tmpProtCnt/(float)prototypes.size() * 6.0 );
+        double y   = ( 6 * tmpProtCnt/(float)prototypes.size() - seg );
+
+        Color circleColor;
+        switch ( seg ) {
+          case 0:
+            circleColor = Color( 0,0,(int)round(y*255) );
+            break;
+          case 1:
+            circleColor = Color( 0,(int)round(y*255),255 );
+            break;
+          case 2:
+            circleColor = Color( 0,255,(int)round((1-y)*255) );
+            break;
+          case 3:
+            circleColor = Color( (int)round(y*255),255,0 );
+            break;
+          case 4:
+            circleColor = Color( 255,(int)round((1-y)*255),0 );
+            break;
+          case 5:
+            circleColor = Color( 255,(int)round(y*255),(int)round(y*255) );
+            break;
+          default:
+            circleColor = Color( 255,255,255 );
+            break;
+        }      
+      
+      NICE::Circle circ ( Coord( posX, posY), (int) round(2*3*sqrt(2)*( positions[indexOfMostSimFeat] )[2]) /* radius*/, circleColor );
+      img.draw(circ);  
+    }
+        
+   if ( b_showResults )
+      showImage(img, "Current image and most similar features for current prototypes"); 
+   else
+   {
+      std::vector< std::string > list2;
+      StringTools::split ( _filename, '/', list2 );      
+
+      std::string destination ( s_resultdir + NICE::intToString(this->newImageCounter-1) + "_" + list2.back() + "_3_updatedCurrentCluster.ppm");
+      if ( beforeComputingNewFeatures )
+        destination  =  s_resultdir + NICE::intToString(this->newImageCounter) + "_" + list2.back() + "_0_initialCurrentCluster.ppm";
+      
+      img.writePPM( destination );
+   }
+   
+   return noveltyImageGaussFiltered;
+}
+
+NICE::ImageT< int > FeatureLearningPrototypes::evaluateCurrentCodebookByAssignments(const std::string& _filename, const bool& beforeComputingNewFeatures, const bool & _binaryShowLatestPrototype)
+{
+  std::cerr << "evaluateCurrentCodebookByAssignments" << std::endl;
+  NICE::ColorImage img( _filename );
+  
+  int xsize ( img.width() );
+  int ysize ( img.height() );
+  
+  //variables to store feature information
+  NICE::VVector features;
+  NICE::VVector cfeatures;
+  NICE::VVector positions;
+
+  //compute features
+  Globals::setCurrentImgFN ( _filename );
+  featureExtractor->extractFeatures ( img, features, positions );
+  
+  //normalization
+  for ( NICE::VVector::iterator i = features.begin();
+        i != features.end();
+        i++)
+  {              
+    //normalization :)
+    i->normalizeL1();
+  }
+  
+  //this is the image we will return finally
+  NICE::ImageT< int > clusterImage ( xsize, ysize );
+  clusterImage.set ( 0 );
+  
+  // after iterating over all features from the new image, this vector contains
+  // distances to the most similar feature for every prototype
+  NICE::Vector minDistances ( this->prototypes.size() );
+  
+  NICE::VVector::const_iterator posIt = positions.begin();
+  for ( NICE::VVector::const_iterator i = features.begin();
+        i != features.end();
+        i++, posIt++ )
+  {              
+    
+    //loop over codebook representatives
+    double minDist ( std::numeric_limits<double>::max() );
+    int indexOfNearestPrototype ( 0 );
+    int prototypeCounter ( 0 );
+    for (NICE::VVector::const_iterator it =  this->prototypes.begin(); it != this->prototypes.end(); it++, prototypeCounter++)
+    {
+      //compute distance
+      double tmpDist ( this->distFunction->calculate(*i,*it) );
+      //check what the closest prototype is
+      if (tmpDist < minDist)
+      {
+        minDist = tmpDist;
+        indexOfNearestPrototype = prototypeCounter;
+      }
+      
+      //check whether we found a feature for the current prototype which is more similar then the previous best one
+      if ( minDistances[ prototypeCounter ] > tmpDist )
+        minDistances[ prototypeCounter ] = tmpDist;      
+    }
+    
+
+    
+    
+    //take minimum distance and store in in a float image    
+    // for nice visualization, we plot the cluster index into a square of size 3 x 3
+    //TODO currently hard coded!!!
+    int noProtoTypes ( this->prototypes.size() -1 );
+    
+    for ( int tmpY = (*posIt)[1]  - 1; tmpY < (*posIt)[1]  + 1; tmpY++)
+    {
+      for ( int tmpX = (*posIt)[0]  - 1; tmpX < (*posIt)[0]  + 1; tmpX++)
+      {
+        if ( _binaryShowLatestPrototype )
+        {
+          //just a binary image - 1 if newest prototype is nearest - 0 if not
+          if  ( indexOfNearestPrototype == noProtoTypes)
+            clusterImage ( tmpX, tmpY ) = 1;
+          else
+            clusterImage ( tmpX, tmpY ) = 0;
+        }
+        else
+          //as many different values as current prototypes available
+          clusterImage ( tmpX, tmpY ) = indexOfNearestPrototype;  
+      }
+    }
+  } 
+  
+  std::cerr << "Codebook evaluation by assignments... min distances in image for every prototype: " << std::endl << "    " << minDistances << std::endl;
+  
+  //show how many clusters we have
+  if ( !_binaryShowLatestPrototype )  
+  {
+    int tmpCnt ( 0 );
+    for (NICE::VVector::const_iterator protoIt = prototypes.begin(); protoIt != prototypes.end(); protoIt++, tmpCnt++)
+    {
+      for ( int tmpY = 1 + 2 - 2; tmpY < (2  + 2); tmpY++)
+        {
+          for ( int tmpX = 1 + 4*tmpCnt ; tmpX < (1 + 4*tmpCnt  + 3); tmpX++)
+          {
+            //Take care, this might go "over" the image
+            clusterImage ( tmpX, tmpY ) = (Ipp8u) tmpCnt;
+          }
+        }   
+    }
+  }
+  
+  return clusterImage;
+}
+
+void FeatureLearningPrototypes::evaluateCurrentCodebookByConfusionMatrix( NICE::Matrix & _confusionMat )
+{
+  _confusionMat.resize ( this->prototypes.size(), this->prototypes.size() );
+  _confusionMat.set( 0.0 );
+  
+  double tmpDist ( 0.0 );
+  NICE::VVector::const_iterator protoItJ = prototypes.begin();
+  for ( int j = 0; j < prototypes.size(); j++, protoItJ++)
+  {
+    NICE::VVector::const_iterator protoItI = protoItJ; 
+    for ( int i = j; i < prototypes.size(); i++, protoItI++)
+    {
+      tmpDist = this->distFunction->calculate( *protoItJ, *protoItI );
+      
+      //assuming symmetric distances
+      _confusionMat ( i, j ) = tmpDist;
+//       if ( i != j )
+//         _confusionMat ( j, i ) = tmpDist;  
+    }
+  }
+}
+
+NICE::VVector * FeatureLearningPrototypes::getCurrentCodebook()
+{
+  return &(this->prototypes);
+}
+

+ 127 - 0
featureLearning/FeatureLearningPrototypes.h

@@ -0,0 +1,127 @@
+/**
+ * @file FeatureLearningPrototypes.h
+ * @brief compute new histogram entries somehow, represent clusters only based on representatives, no additional information like dimensionwise variances...
+ * @author Alexander Freytag
+ * @date 17-04-2013 (dd-mm-yyyy)
+*/
+#ifndef _INCLUDEFEATURELEARNINGPROTOTYPES
+#define _INCLUDEFEATURELEARNINGPROTOTYPES
+
+#include "FeatureLearningGeneric.h"
+
+
+#include <core/vector/Distance.h>
+#include <core/vector/VVector.h>
+
+#include <vislearning/cbaselib/MultiDataset.h>
+// 
+#include <vislearning/features/localfeatures/GenericLocalFeatureSelection.h>
+#include <vislearning/features/simplefeatures/CodebookPrototypes.h>
+// 
+#include <vislearning/math/cluster/ClusterAlgorithm.h>
+
+
+
+
+namespace OBJREC
+{
+
+  /**
+   * @class FeatureLearningPrototypes
+   * @brief compute new histogram entries somehow, represent clusters only based on representatives, no additional information like dimensionwise variances...
+   * @author Alexander Freytag
+   * @date 17-04-2013 (dd-mm-yyyy)
+  */  
+  
+  class FeatureLearningPrototypes : public FeatureLearningGeneric
+  {
+
+    protected:
+      
+      /************************
+       * 
+       *   protected variables
+       * 
+       **************************/       
+           
+      bool showTrainingImages;
+      
+      //! define the initial number of clusters our codebook shall contain
+      int initialNumberOfClusters;       
+      
+      OBJREC::ClusterAlgorithm * clusterAlgo;      
+  
+      NICE::VectorDistance<double> * distFunction;
+
+      LocalFeatureRepresentation * featureExtractor;
+      
+      //! The currently known "cluster" centers, which are used for BoW histogram computation 
+//       NICE::VVector prototypes;     
+      OBJREC::CodebookPrototypes prototypes;   
+            
+      int newImageCounter;
+      //just needed for visualisation
+      double oldMaxDist;
+      
+      //TODO stupid!!!
+      double maxValForVisualization;
+      
+      //! just for temporary debugging
+      int i_posXOfNewPrototype;
+      int i_posYOfNewPrototype;      
+            
+      
+      /************************
+       * 
+       *   protected methods
+       * 
+       **************************/
+            
+      void setClusterAlgo( const std::string & _clusterAlgoString);
+      void setFeatureExtractor( const bool & _setForTraining = false);
+      
+      void extractFeaturesFromTrainingImages(  const OBJREC::MultiDataset *_md,  NICE::VVector & examplesTraining  ); 
+      
+      void train ( const OBJREC::MultiDataset *_md ); 
+      
+      virtual bool loadInitialCodebook ( );
+      virtual bool writeInitialCodebook ( );      
+      
+      virtual void evaluateCurrentCodebookForGivenFeatures (  const NICE::VVector & _features,
+                                                              const NICE::VVector & _positions,
+                                                              NICE::FloatImage & _noveltyImageGaussFiltered,
+                                                              NICE::FloatImage * _noveltyImage = NULL                                                              
+                                                            );
+
+    public:
+
+      /** constructor
+        * @param _conf needs a configfile
+        * @param _md and a MultiDataset (contains images and other things)
+        * @param _section section information for parsing config files
+        */
+      FeatureLearningPrototypes ( const NICE::Config *_conf, const OBJREC::MultiDataset *_md , const std::string & _section = "featureLearning");
+
+      /** simple destructor */
+      virtual ~FeatureLearningPrototypes();
+      
+      /** this function has to be overloaded by all subclasses
+          @param imgWithNovelContent 
+      */
+      virtual void learnNewFeatures ( const std::string & _filename ) = 0 ;
+      
+      virtual NICE::FloatImage evaluateCurrentCodebookByDistance ( const std::string & _filename , const bool & beforeComputingNewFeatures = true );
+      
+      virtual NICE::ImageT<int> evaluateCurrentCodebookByAssignments ( const std::string & _filename , const bool & beforeComputingNewFeatures = true, const bool & _binaryShowLatestPrototype = false);            
+      
+      virtual void evaluateCurrentCodebookByConfusionMatrix( NICE::Matrix & _confusionMat ); 
+      
+      virtual NICE::VVector * getCurrentCodebook();
+      
+
+  };
+
+
+} // namespace
+
+#endif

+ 324 - 0
featureLearning/FeatureLearningRegionBased.cpp

@@ -0,0 +1,324 @@
+
+#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)++;  
+}

+ 73 - 0
featureLearning/FeatureLearningRegionBased.h

@@ -0,0 +1,73 @@
+/**
+ * @file FeatureLearningRegionBased.h
+ * @brief compute new histogram entries by extracting features from (moderately large) regions which have high novelty scores
+ * @author Alexander Freytag
+ * @date 17-04-2013 (dd-mm-yyyy)
+*/
+#ifndef _INCLUDEFEATURELEARNINGREGIONBASED
+#define _INCLUDEFEATURELEARNINGREGIONBASED
+
+#include "FeatureLearningPrototypes.h"
+
+#include "segmentation/RegionSegmentationMethod.h"
+
+
+namespace OBJREC
+{
+
+  /**
+   * @class FeatureLearningRegionBased
+   * @briefcompute new histogram entries by extracting features from (moderately large) regions which have high novelty scores
+   * @author Alexander Freytag
+   * @date 17-04-2013 (dd-mm-yyyy)
+  */  
+  
+  class FeatureLearningRegionBased : public FeatureLearningPrototypes
+  {
+
+    protected:
+
+      /************************
+       * 
+       *   protected variables
+       * 
+       **************************/  
+      
+      //! low level Segmentation method
+      RegionSegmentationMethod *segmentationAlgo;      
+      
+      //! boolean whether to reuse segmentation results for single images in different runs
+      bool reuseSegmentation;      
+      
+      //! determine a grid on which we extract local features
+      int i_gridSize;
+
+      /************************
+       * 
+       *   protected methods
+       * 
+       **************************/      
+
+
+    public:
+
+      /** constructor
+        *  @param _conf needs a configfile
+        *  @param _md and a MultiDataset (contains images and other things)
+        */
+      FeatureLearningRegionBased ( const NICE::Config *_conf, const OBJREC::MultiDataset *_md , const std::string & _section = "featureLearning");
+
+      /** simple destructor */
+      virtual ~FeatureLearningRegionBased();
+      
+      /** this function has to be overloaded by all subclasses
+          @param imgWithNovelContent 
+      */
+      virtual void learnNewFeatures ( const std::string & filename );
+      
+  };
+
+
+} // namespace
+
+#endif

+ 8 - 0
featureLearning/Makefile

@@ -0,0 +1,8 @@
+#TARGETS_FROM:=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM)
+#$(info recursivly going up: $(TARGETS_FROM) ($(shell pwd)))
+
+all:
+
+%:
+	$(MAKE) TARGETS_FROM=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM) -C .. $@
+

+ 103 - 0
featureLearning/Makefile.inc

@@ -0,0 +1,103 @@
+# LIBRARY-DIRECTORY-MAKEFILE
+# conventions:
+# - all subdirectories containing a "Makefile.inc" are considered sublibraries
+#   exception: "progs/" and "tests/" subdirectories!
+# - all ".C", ".cpp" and ".c" files in the current directory are linked to a
+#   library
+# - the library depends on all sublibraries 
+# - the library name is created with $(LIBNAME), i.e. it will be somehow
+#   related to the directory name and with the extension .a
+#   (e.g. lib1/sublib -> lib1_sublib.a)
+# - the library will be added to the default build list ALL_LIBRARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+ifeq "$(SUBDIR)" "./"
+SUBDIR:=
+endif
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# you can specify libraries needed by the individual objects or by the whole
+# directory. the object specific additional libraries are only considered
+# when compiling the specific object files
+# TODO: update documentation...
+
+-include $(SUBDIR)libdepend.inc
+
+$(foreach d,$(filter-out %progs %tests,$(SUBDIRS_OF_$(SUBDIR))),$(eval $(call PKG_DEPEND_INT,$(d))))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+	  $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+LIBRARY_BASENAME:=$(call LIBNAME,$(SUBDIR))
+ifneq "$(SUBDIR)" ""
+ALL_LIBRARIES+=$(LIBDIR)$(LIBRARY_BASENAME).$(LINK_FILE_EXTENSION)
+endif
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. the current library depends on all sublibraries.
+# all other dependencies have to be added manually by specifying, that the
+# current .pc file depends on some other .pc file. binaries depending on
+# libraries should exclusivelly use the .pc files as well.
+
+ifeq "$(SKIP_BUILD_$(OBJDIR))" "1"
+$(LIBDIR)$(LIBRARY_BASENAME).a:
+else
+$(LIBDIR)$(LIBRARY_BASENAME).a:$(OBJS) \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).a,.$(LINK_FILE_EXTENSION))
+endif
+
+$(PKGDIR)$(LIBRARY_BASENAME).pc: \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).pc,.pc)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 6 - 0
featureLearning/libdepend.inc

@@ -0,0 +1,6 @@
+$(call PKG_DEPEND_INT,core/)
+$(call PKG_DEPEND_INT,vislearning/baselib/)
+$(call PKG_DEPEND_INT,vislearning/cbaselib/)
+$(call PKG_DEPEND_INT,vislearning/features/)
+$(call PKG_DEPEND_INT,vislearning/math/)
+$(call PKG_DEPEND_INT,segmentation/)

+ 8 - 0
featureLearning/progs/Makefile

@@ -0,0 +1,8 @@
+#TARGETS_FROM:=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM)
+#$(info recursivly going up: $(TARGETS_FROM) ($(shell pwd)))
+
+all:
+
+%:
+	$(MAKE) TARGETS_FROM=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM) -C .. $@
+

+ 88 - 0
featureLearning/progs/Makefile.inc

@@ -0,0 +1,88 @@
+# BINARY-DIRECTORY-MAKEFILE
+# conventions:
+# - there are no subdirectories, they are ignored!
+# - all ".C", ".cpp" and ".c" files in the current directory are considered
+#   independent binaries, and linked as such.
+# - the binaries depend on the library of the parent directory
+# - the binary names are created with $(BINNAME), i.e. it will be more or less
+#   the name of the .o file
+# - all binaries will be added to the default build list ALL_BINARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+#SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+#include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# include the libdepend.inc file, which gives additional dependencies for the
+# libraries and binaries. additionally, an automatic dependency from the library
+# of the parent directory is added (commented out in the code below).
+
+-include $(SUBDIR)libdepend.inc
+
+PARENTDIR:=$(patsubst %/,%,$(dir $(patsubst %/,%,$(SUBDIR))))
+$(eval $(call PKG_DEPEND_INT,$(PARENTDIR)))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+      $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+BINARIES:=$(patsubst %.o,$(BINDIR)%,$(filter-out moc_%,$(notdir $(OBJS))))
+ALL_BINARIES+=$(BINARIES)
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. each binary depends on the corresponding .o file and
+# on the libraries specified by the INTLIBS/EXTLIBS. these dependencies can be
+# specified manually or they are automatically stored in a .bd file.
+
+$(foreach head,$(wildcard $(SUBDIR)*.h),$(eval $(shell grep -q Q_OBJECT $(head) && echo $(head) | sed -e's@^@/@;s@.*/\(.*\)\.h$$@$(BINDIR)\1:$(OBJDIR)moc_\1.o@')))
+-include $(OBJS:%.o=%.bd)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 6 - 0
featureLearning/progs/libdepend.inc

@@ -0,0 +1,6 @@
+$(call PKG_DEPEND_INT,vislearning/baselib/)
+$(call PKG_DEPEND_INT,vislearning/cbaselib/)
+$(call PKG_DEPEND_INT,vislearning/features/)
+$(call PKG_DEPEND_INT,vislearning/math/)
+$(call PKG_DEPEND_INT,vislearning/noveltyDetection/)
+$(call PKG_DEPEND_INT,segmentation/)

+ 346 - 0
featureLearning/progs/testFeatureLearning.cpp

@@ -0,0 +1,346 @@
+/**
+* @file testFeatureLearning.cpp
+* @brief test the feature learning routines to incrementally increase / adapt the codebook currently used
+* @author Alexander Freytag
+* @date 11-04-2013
+*/
+
+//STL
+#include <iostream>
+#include <limits>
+
+//core
+#include <core/basics/Config.h>
+#include <core/basics/ResourceStatistics.h>
+#include <core/image/Convert.h>
+#include <core/vector/VectorT.h>
+
+//vislearning
+#include <vislearning/baselib/Globals.h>
+#include <vislearning/baselib/ICETools.h>
+#include <vislearning/cbaselib/MultiDataset.h>
+#include <vislearning/cbaselib/Example.h>
+// 
+#include "vislearning/featureLearning/FeatureLearningGeneric.h"
+#include "vislearning/featureLearning/FeatureLearningClusterBased.h"
+#include "vislearning/featureLearning/FeatureLearningRegionBased.h"
+//
+#include "vislearning/noveltyDetection/NDCodebookLevelImagePooling.h"
+
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+
+
+/**
+ test feature learning routines
+*/
+int main( int argc, char **argv )
+{
+  std::set_terminate( __gnu_cxx::__verbose_terminate_handler );
+
+  Config * conf = new Config ( argc, argv );
+  
+  bool showTrainingImages = conf->gB( "featureLearning", "showTrainingImages", false );
+  bool showTestImages = conf->gB( "featureLearning", "showTestImages", false );
+  bool showResults = conf->gB( "featureLearning", "showResults", false );
+  
+  ResourceStatistics rs;
+  std::string resultdir;
+  resultdir = conf->gS( "featureLearning", "resultdir", "/tmp/");
+  
+  
+  NICE::ImageT<int> noveltyScale ( 20, 100 );
+  for (int j = 0; j < 100; j++)
+  {
+    for (int i = 0; i < 20; i++)
+      noveltyScale(i,j) = 99-j;
+  }
+  
+  NICE::ColorImage noveltyScaleRGB (noveltyScale.width(), noveltyScale.height() );
+  imageToPseudoColor( noveltyScale, noveltyScaleRGB );
+  
+  std::string destinationNoveltyScale ( resultdir + "_" + "_noveltyScale.ppm");
+  noveltyScaleRGB.writePPM( destinationNoveltyScale );   
+  
+  
+  
+  //**********************************************
+  //
+  //      READ INITIAL TRAINING SET TO COMPUTE
+  //             AN INITIAL CODEBOOK
+  //
+  //**********************************************
+  
+  std::cerr << " READ INITIAL TRAINING SET TO COMPUTE AN INITIAL CODEBOOK" << std::endl;
+  
+  MultiDataset md( conf );
+  const LabeledSet *trainFiles = md["train"];
+  
+  //**********************************************
+  //
+  //      SET UP THE FEATURE LEARNING ALGO
+  //
+  //********************************************** 
+  
+  OBJREC::FeatureLearningGeneric * featureLearning;
+  
+  std::string featureLearningMethod = conf->gS( "featureLearning", "featureLearningMethod", "clusterBased" );
+  
+  if (featureLearningMethod.compare("clusterBased") == 0)
+  {
+    featureLearning = new OBJREC::FeatureLearningClusterBased( conf, &md );
+  }
+  else if (featureLearningMethod.compare("regionBased") == 0) 
+  {
+    featureLearning = new OBJREC::FeatureLearningRegionBased( conf, &md );
+  }
+  else
+  {
+    std::cerr << "Unknown feature learning algorithm selected, use cluster based instead" << std::endl;
+    featureLearning = new OBJREC::FeatureLearningClusterBased( conf, &md );
+  }    
+  
+  //**********************************************
+  //
+  //      SET UP THE NOVELTY DECTION ALGO
+  //
+  //**********************************************   
+  
+  OBJREC::NDCodebookLevelImagePooling * novDetector;
+  novDetector = new OBJREC::NDCodebookLevelImagePooling( conf, &md, "featureLearning" );
+    
+  //evaluate how well the training images are covered with our initial codebook
+  //that is, compute these nice "novelty maps" per feature
+  
+  //NOTE we skip this currently
+  LOOP_ALL_S( *trainFiles )
+  {
+      EACH_INFO( classno, info );
+      std::string filename = info.img();
+//       
+//       featureLearning->evaluateCurrentCodebook( filename , true /* beforeComputingNewFeatures */);       
+      
+      NICE::ImageT< int > imgClusterAssignments;
+      imgClusterAssignments = featureLearning->evaluateCurrentCodebookByAssignments(filename , false /* beforeComputingNewFeatures */, false /* _binaryShowLatestPrototype*/ );
+      
+      std::cerr << "now do image To pseude color and show the initial cluster assignments" << std::endl;
+      NICE::ColorImage imgClusterAssignmentsRGB (imgClusterAssignments.width(), imgClusterAssignments.height() );
+      imageToPseudoColor( imgClusterAssignments, imgClusterAssignmentsRGB );      
+      
+      if ( showResults )
+        showImage(imgClusterAssignmentsRGB, "cluster Assignments" ) ;
+      else
+      {
+        std::vector< std::string > list2;
+        StringTools::split ( filename, '/', list2 );        
+        std::string destination ( resultdir + NICE::intToString(0) + "_" + list2.back() + "_00_initialClusterAssignments.ppm");
+        imgClusterAssignmentsRGB.writePPM( destination );        
+      }
+  }
+  
+  //**********************************************
+  //
+  //        EVALUATE INITIAL CLUSTER
+  //
+  //       COMPUTE A NICE CONFUSION MATRIX
+  //          FOR OUR INITIAL CODEBOOK
+  //
+  //**********************************************  
+  NICE::Matrix confusionMatInitial;
+  featureLearning->evaluateCurrentCodebookByConfusionMatrix( confusionMatInitial );
+  std::cerr << "initial Confusion matrix: " << std::endl << confusionMatInitial << std::endl;
+  
+  //set the initially computed codebook to the novelty detection mechanism
+  //TODO this should be done, but currently we do not care about
+//   novDetector->setCodebook( featureLearning->getCurrentCodebook() );
+  
+
+  //**********************************************
+  //
+  //        FOR-LOOP OVER UNSEEN IMAGES
+  //
+  //       EXTRACT FEATURES, CLUSTER THEM, TAKE
+  //       MOST "VALUABLE" CLUSTERS AS NEW 
+  //    REPRESENTATIVES IN AN INCREASED CODEBOK
+  //
+  //**********************************************
+  const LabeledSet *testFiles = md["test"];
+    
+  std::cerr << "start looping over all files" << std::endl;
+  int imageCnt ( 0 );
+  LOOP_ALL_S( *testFiles )
+  {
+      EACH_INFO( classno, info );
+      std::string filename = info.img();
+      
+      NICE::ColorImage orig( filename );
+      
+      NICE::ImageT< int > imgClusterAssignments;
+      imgClusterAssignments = featureLearning->evaluateCurrentCodebookByAssignments(filename , false /* beforeComputingNewFeatures */, false /* _binaryShowLatestPrototype*/ );      
+      
+      NICE::ColorImage imgClusterAssignmentsRGB (imgClusterAssignments.width(), imgClusterAssignments.height() );
+      imageToPseudoColor( imgClusterAssignments, imgClusterAssignmentsRGB );       
+      
+      NICE::FloatImage noveltyImageBefore;
+      noveltyImageBefore = featureLearning->evaluateCurrentCodebookByDistance( filename , true /* beforeComputingNewFeatures */ );
+      
+      NICE::ColorImage noveltyImageBeforeRGB (noveltyImageBefore.width(), noveltyImageBefore.height() );
+      imageToPseudoColor( noveltyImageBefore, noveltyImageBeforeRGB );        
+      
+      if ( showResults )
+        showImage(imgClusterAssignmentsRGB, "cluster Assignments" ) ;
+      else
+      {
+        std::vector< std::string > list2;
+        StringTools::split ( filename, '/', list2 );        
+        std::string destination ( resultdir + NICE::intToString(0) + "_" + list2.back() + "_00_initialClusterAssignments.ppm");
+        imgClusterAssignmentsRGB.writePPM( destination );        
+        
+        std::string destinationNovelty ( resultdir + NICE::intToString(0) + "_" + list2.back() + "_01_initialClusterDistances.ppm");
+        noveltyImageBeforeRGB.writePPM( destinationNovelty );          
+      }      
+      
+      //**********************************************
+      //
+      //             IS THIS IMAGE NOVEL?
+      //
+      //          IF NOT, GO TO THE NEXT ONE
+      //
+      //**********************************************       
+      
+      bool b_isImageNovel ( novDetector->evaluateNoveltyOfImage( noveltyImageBefore ) );
+      
+      if ( ! b_isImageNovel )
+      {
+        std::cerr << " --- NOT NOVEL --- " << std::endl << std::endl;
+        continue;
+      }
+      else
+      {
+        std::cerr << " --- NOVEL --- " << std::endl;
+      }
+      
+      while ( b_isImageNovel ) 
+      {
+              
+        //**********************************************
+        //
+        //       LEARN NEW FEATURE FOR A NOVEL IMAGE
+        //
+        //**********************************************       
+        
+        featureLearning->learnNewFeatures( filename );
+        
+        //and update the codebook pointer within our novelty detection algorithm
+        //TODO this should be done, but currently we do not care about
+  //       novDetector->setCodebook( featureLearning->getCurrentCodebook() );      
+        
+        //**********************************************
+        //
+        //       EVALUATE HOW WELL THE CURRENT IMAGE
+        //            CAN BE EXPLAINED AFTER 
+        //           COMPUTING A NEW FEATURE
+        //
+        //       SHOULD WE REPEAT THIS UNTIL THE IMAGE
+        //       IS NOT CLASSIFIED AS "NOVEL" ANYMORE?
+        //
+        //**********************************************       
+        
+        NICE::FloatImage noveltyImageAfter;
+        noveltyImageAfter = featureLearning->evaluateCurrentCodebookByDistance( filename , false /* beforeComputingNewFeatures */ );
+        
+        NICE::FloatImage noveltyImageDifference ( noveltyImageAfter.width(), noveltyImageAfter.height());
+        for ( uint y = 0 ; y < ( uint ) noveltyImageAfter.height() ; y++ )
+        {
+          for ( uint x = 0 ; x < ( uint ) noveltyImageAfter.width(); x++ )
+          {
+            noveltyImageDifference(x,y) = fabs ( noveltyImageBefore(x,y) - noveltyImageAfter(x,y) );
+          }
+        }
+        
+        std::cerr << "min diff: " << noveltyImageDifference.min() << " and max diff: " << noveltyImageDifference.max() << std::endl;
+        
+        NICE::ColorImage noveltyImageDifferenceRGB (noveltyImageAfter.width(), noveltyImageAfter.height() );
+        imageToPseudoColor( noveltyImageDifference, noveltyImageDifferenceRGB );      
+        
+        std::vector< std::string > list2;
+        StringTools::split ( filename, '/', list2 );      
+
+        if ( showResults )
+        {
+          showImage( noveltyImageDifferenceRGB, "Difference of novelty images" );
+        }
+        else
+        {          
+          std::string destination ( resultdir + NICE::intToString(imageCnt) + "_" + list2.back() + "_02_initialLoopClusterAssignments.ppm");  
+          imgClusterAssignmentsRGB.writePPM( destination );    
+
+          std::string destinationNoveltyDifference ( resultdir + NICE::intToString(imageCnt) + "_" + list2.back() + "_03_noveltyDifferences.ppm");  
+          noveltyImageDifferenceRGB.writePPM( destinationNoveltyDifference );                        
+        }
+
+        NICE::ImageT< int > imgClusterAssignmentsBinary;
+        imgClusterAssignmentsBinary = featureLearning->evaluateCurrentCodebookByAssignments(filename , true, true /* _binaryShowLatestPrototype*/ );      
+        
+        NICE::ImageT< int > imgClusterAssignments;
+        imgClusterAssignments = featureLearning->evaluateCurrentCodebookByAssignments(filename , true, false /* _binaryShowLatestPrototype*/ );
+
+        
+        NICE::ColorImage imgClusterAssignmentsBinaryRGB (imgClusterAssignmentsBinary.width(), imgClusterAssignmentsBinary.height() );
+        imageToPseudoColor( imgClusterAssignmentsBinary, imgClusterAssignmentsBinaryRGB );   
+        
+        NICE::ColorImage imgClusterAssignmentsRGB (imgClusterAssignments.width(), imgClusterAssignments.height() );
+        imageToPseudoColor( imgClusterAssignments, imgClusterAssignmentsRGB );           
+        
+        if ( showResults )
+        {
+          showImage(imgClusterAssignmentsBinaryRGB, "cluster Assignments Binary (latest prototype)" ) ;      
+          showImage(imgClusterAssignmentsRGB, "cluster Assignments" ) ;
+        }
+        else
+        {
+            std::string destination ( resultdir + NICE::intToString(imageCnt) + "_" + list2.back() + "_5_clusterAssignments.ppm");
+            std::string destinationBinary ( resultdir + NICE::intToString(imageCnt) + "_" + list2.back() + "_6_clusterAssignmentsBinary.ppm");
+            
+            imgClusterAssignmentsRGB.writePPM( destination );
+            imgClusterAssignmentsBinaryRGB.writePPM( destinationBinary );
+        }      
+        
+        //check, whether the image will still be seen as novel or not
+        // i.e., are we able to "explain" the image with the lately computed codebook entry?
+        b_isImageNovel = novDetector->evaluateNoveltyOfImage( noveltyImageAfter ) ;
+        
+        if ( ! b_isImageNovel )
+        {
+          std::cerr << " --- NOT NOVEL ANYMORE --- " << std::endl << std::endl;
+        }
+        else
+        {
+          std::cerr << " --- STILL NOVEL --- " << std::endl;
+          noveltyImageBefore = noveltyImageAfter;
+        }        
+        
+        //artifial break for the moment
+        break;
+      }
+
+      
+      imageCnt++;
+  } //Loop over all test images
+  
+  
+  //don't waste memory
+  std::cerr << "don't waste memory - cleaning up" << std::endl;
+//   if (trainFiles != NULL)
+//     delete trainFiles;
+  if (featureLearning != NULL)
+    delete featureLearning;
+  if (novDetector != NULL)
+    delete novDetector;
+  if (conf != NULL)
+    delete conf;
+  
+   return 0;
+}

+ 158 - 58
features/localfeatures/GenericLFSelection.h

@@ -1,5 +1,5 @@
 /** 
-* @file GenericLocalFeatureSelection.h
+* @file GenericLFSelection.h
 * @brief This class provides a generic chooser function for different descriptors, which are derived from LocalFeatureRepresentation.
 * @date 26.10.2011
 */
@@ -19,79 +19,179 @@
 #include "vislearning/features/localfeatures/LFColorSande.h"
 #include "vislearning/features/localfeatures/LFonHSG.h"
 
-/** NOTE: This class only returns Descriptors, which NOT need any given positions. All Descriptors calculate there own positions, on DIFFERENT ways. **/
-
 
 namespace OBJREC {
 
+  /** @class GenericLFSelection
+ * @brief Select a specific LF-Type (local feature representation). LFs compute Descriptors, which DO NOT need given positions, but calculate them ON THEIR OWN!
+ * All Descriptor-Methods calculate there own positions previously, and on DIFFERENT ways.
+ */
 class GenericLFSelection
 {
     public:
+      
+      //! enum specifying for which step the feature extractor shall be used (this influences the config section which will be used)
+      enum UsageForTrainOrTest { NOTSPECIFIED = 0,
+             TRAINING,
+             TESTING
+      };
 
       /** LocalFeature Selector
        * @brief This methode switches between the different LocalFeature-Types. One has to set the "localfeature_type" on a valid value and the methode returns a LocalFeatureRepresentation derived Object.
-       * @param[in] Config* - A pointer to the given configfile, which must contain "section" - "localfeature_type"
-       * @param[in] string  - This string defines the value for "section" in the configfile.
+       * @param[in] conf - A pointer to the given configfile, which must contain "section" - "localfeature_type"
+       * @param[in] section - This string defines the value for "section" in the configfile.
+       * @param[in] useForTrainOrTest - Specify whether we use the LFRep for Training, Testing, or for both - this influences the choice of the config section that is handed over to the LFRep-method
        * @return LocalFeatureRepresentation* - The LocalFeatureRepresentation which contains the selected LocalFeature-Type.
        */
       static
-      LocalFeatureRepresentation *selectLocalFeatureRep ( const NICE::Config *conf, std::string section = "features" )
+      LocalFeatureRepresentation *selectLocalFeatureRep ( const NICE::Config *conf, std::string section = "features", const UsageForTrainOrTest & useForTrainOrTest = NOTSPECIFIED )
       {
-	  // return Value
-	  LocalFeatureRepresentation *lfrep = NULL;
-	
-	  // string which defines the localfeature_type (for Ex. Sande, ...)
-	  std::string localfeature_type = conf->gS(section, "localfeature_type", "");
-	
-	  if ( localfeature_type == "mikolajczyk" )
-	  {
-	    lfrep = new LFMikolajczyk ( conf );
-	  }
-	  else if ( localfeature_type == "color" )
-	  {
-	    lfrep = new LFColorSande ( conf );
-	  }
-	  else if ( ( localfeature_type == "sift" ) || ( localfeature_type == "siftpp" ) ) 
-	  {
-            lfrep = new LFSiftPP ( conf );
-	  }
-	  else if ( ( localfeature_type == "generic_local" ) || ( localfeature_type == "generic" ) )
-	  {
-            int numFeatures = conf->gI(section, "localfeature_count");
-	    lfrep = new LFGenericLocal ( conf, numFeatures );
-	  }
-	  else if ( ( localfeature_type == "grey" ) || ( localfeature_type == "patches" ) )
-	  {
-	    int numFeatures = conf->gI(section, "localfeature_count");
-	    lfrep = new LFPatches ( conf, numFeatures );
-	  } 
-	  else if( ( localfeature_type == "onHSG" ) )
-	  {
-	    lfrep = new LFonHSG( conf);
-	  }
-	  else 
-	  {
-		  lfrep = NULL;
-	  }
+        // return Value
+        LocalFeatureRepresentation *lfrep = NULL;
+      
+        // string which defines the localfeature_type (for Ex. Sande, ...)
+        std::string localfeature_type = conf->gS(section, "localfeature_type", "");
+      
+        if ( localfeature_type == "mikolajczyk" )
+        {
+          lfrep = new LFMikolajczyk ( conf );
+        }
+        else if ( localfeature_type == "VANDESANDE" ) //previously: "color"
+        {
+          if ( useForTrainOrTest == TRAINING )
+          {
+            lfrep = new LFColorSande ( conf, "LFColorSandeTrain" );
+          }
+          else if ( useForTrainOrTest == TESTING )
+          {
+            lfrep = new LFColorSande ( conf, "LFColorSandeTest" );
+          }
+          else //not specified whether for training or testing, so we do not care about
+          {
+            lfrep = new LFColorSande ( conf );            
+          }          
+        }
+        else if ( ( localfeature_type == "sift" ) || ( localfeature_type == "siftpp" ) ) 
+        {
+                lfrep = new LFSiftPP ( conf );
+        }
+        else if ( ( localfeature_type == "generic_local" ) || ( localfeature_type == "generic" ) )
+        {
+                int numFeatures = conf->gI(section, "localfeature_count");
+          lfrep = new LFGenericLocal ( conf, numFeatures );
+        }
+        else if ( ( localfeature_type == "grey" ) || ( localfeature_type == "patches" ) )
+        {
+          int numFeatures = conf->gI(section, "localfeature_count");
+          lfrep = new LFPatches ( conf, numFeatures );
+        } 
+        else if( ( localfeature_type == "onHSG" ) )
+        {
+          if ( useForTrainOrTest == TRAINING )
+          {
+            lfrep = new OBJREC::LFonHSG ( conf, "HSGTrain" );
+          }
+          else if ( useForTrainOrTest == TESTING )
+          {
+            lfrep = new OBJREC::LFonHSG ( conf, "HSGTest" );
+          }
+          else //not specified whether for training or testing, so we do not care about
+          {
+            lfrep = new OBJREC::LFonHSG( conf);
+          }           
+          
+        }
+        else 
+        {
+          lfrep = NULL;
+        }
+
+//         if ( conf->gB(section, "localfeature_cache_read", false) )
+//         {
+//           int numFeatures = conf->gI(section, "localfeature_count", -1);
+//           LocalFeatureRepresentation *lfrep_read = new LFReadCache ( conf, lfrep, numFeatures );
+//           lfrep = lfrep_read;
+//         }
+// 
+//         // no correct localfeature_type was given
+//         if ( lfrep == NULL )
+//           fthrow(NICE::Exception, "Local feature type not found: " << localfeature_type );
+// 
+//         if ( conf->gB(section, "localfeature_cache_write", false) )
+//         {
+//           LocalFeatureRepresentation *lfrep_write = new LFWriteCache ( conf, lfrep );
+//           lfrep = lfrep_write;
+//         }
+
+        // read features?
+        bool readfeat;
+        readfeat = conf->gB ( section, "localfeature_cache_read", true );
+        // write features?
+        bool writefeat;  
+        writefeat = conf->gB ( section, "localfeature_cache_write", true );   
 
-	  if ( conf->gB(section, "localfeature_cache_read", false) )
-	  {
-		  int numFeatures = conf->gI(section, "localfeature_count", -1);
-		  LocalFeatureRepresentation *lfrep_read = new LFReadCache ( conf, lfrep, numFeatures );
-		  lfrep = lfrep_read;
-	  }
+        LocalFeatureRepresentation *writeFeats = NULL;
+        LocalFeatureRepresentation *readFeats = NULL;
+        if ( writefeat )
+        {
+          // write the features to a file, if there isn't any to read
+          
+          if ( useForTrainOrTest == TRAINING )
+          {    
+            writeFeats = new LFWriteCache ( conf, lfrep, "cacheTrain" );
+            lfrep = writeFeats;
+          }
+          else if ( useForTrainOrTest == TESTING )
+          {
+            writeFeats = new LFWriteCache ( conf, lfrep, "cacheTest" );
+            lfrep = writeFeats;
+          }
+          else //not specified whether for training or testing, so we do not care about
+          {
+            writeFeats = new LFWriteCache ( conf, lfrep );
+            lfrep = writeFeats;
+          }              
 
-	  // no correct localfeature_type was given
-	  if ( lfrep == NULL )
-		  fthrow(NICE::Exception, "Local feature type not found: " << localfeature_type );
+        }
 
-	  if ( conf->gB(section, "localfeature_cache_save", false) )
-	  {
-		  LocalFeatureRepresentation *lfrep_save = new LFWriteCache ( conf, lfrep );
-		  lfrep = lfrep_save;
-	  }
-		  
-	  return lfrep;
+        if ( readfeat )
+        {
+          int numFeatures = conf->gI(section, "localfeature_count", -1);
+          // read the features from a file
+          if ( writefeat )
+          {
+            if ( useForTrainOrTest == TRAINING )
+            {
+              readFeats = new LFReadCache ( conf, writeFeats, numFeatures, "cacheTrain" );
+            }
+            else if ( useForTrainOrTest == TESTING )
+            {
+              readFeats = new LFReadCache ( conf, writeFeats, numFeatures, "cacheTest" );
+            }
+            else //not specified whether for training or testing, so we do not care about
+            {
+              readFeats = new LFReadCache ( conf, writeFeats, numFeatures, "cache" );
+            }                         
+          }
+          else
+          {
+            if ( useForTrainOrTest == TRAINING )
+            {
+              readFeats = new LFReadCache (conf, lfrep, numFeatures, "cacheTrain" );                        
+            }
+            else if ( useForTrainOrTest == TESTING )
+            {
+              readFeats = new LFReadCache (conf, lfrep, numFeatures, "cacheTest" );
+            }
+            else //not specified whether for training or testing, so we do not care about
+            {
+              readFeats = new LFReadCache (conf, lfrep, numFeatures, "cache" );
+            }
+          }
+          lfrep = readFeats; 
+        }  
+          
+        return lfrep;
       }
 };
 

+ 4 - 0
features/localfeatures/GenericLocalFeatureSelection.h

@@ -21,6 +21,10 @@
 
 namespace OBJREC {
 
+  /** @class GenericLocalFeatureSelection
+ * @brief Select a specific LocalFeature-Type. LocalFeatures compute Descriptors, which DO need given positions (no internal position calculation)!
+ *
+ */  
 class GenericLocalFeatureSelection
 {
   public:

+ 16 - 14
features/localfeatures/IDRandomSampling.h

@@ -18,25 +18,27 @@
 namespace OBJREC
 {
 
-/** random interest point sampling */
-class IDRandomSampling: public InterestDetector
-{
+  /** @class IDRandomSampling
+ * @brief random interest point sampling
+ */
+  class IDRandomSampling: public InterestDetector
+  {
 
-protected:
-	int numSamples;
-	double minScale;
+  protected:
+    int numSamples;
+    double minScale;
 
-public:
+  public:
 
-	IDRandomSampling(const NICE::Config *conf, int numSamples);
+    IDRandomSampling(const NICE::Config *conf, int numSamples);
 
-	virtual ~IDRandomSampling();
-	int getInterests(const NICE::Image & img,
-			std::vector<NICE::Vector> & positions) const;
-	int getInterests(const ImagePyramid & imp,
-			std::vector<NICE::Vector> & positions) const;
+    virtual ~IDRandomSampling();
+    int getInterests(const NICE::Image & img,
+        std::vector<NICE::Vector> & positions) const;
+    int getInterests(const ImagePyramid & imp,
+        std::vector<NICE::Vector> & positions) const;
 
-};
+  };
 
 } // namespace
 

+ 7 - 3
features/localfeatures/LFColorSande.cpp

@@ -30,9 +30,12 @@ using namespace NICE;
 
 LFColorSande::LFColorSande ( const Config *conf, std::string section )
 {
+  std::cerr << "LF COLOR SANDE SECTION ====================== :" << section << ":"<<std::endl;
+  
   c_binaryExecutable = conf->gS ( section, "binaryExecutable", "/home/bachi/libs/van_de_sande/x86_64-linux-gcc/colorDescriptor" );
   c_params = conf->gS ( section, "params", "--descriptor opponentsift" );
   scales = conf->gS ( section, "scales", "1+1.5+3.0+4.5+6" );
+  std::cerr << "scales: " << scales << std::endl;
 
   descriptor_size = conf->gI ( section, "descriptor_size", -1 );
 
@@ -42,7 +45,7 @@ LFColorSande::LFColorSande ( const Config *conf, std::string section )
   std::ostringstream temp;
   temp << g;
   gridsize = temp.str();
-
+  
   if ( descriptor_size <= 0 )
   {
     fprintf ( stderr, "LFColorSande::LFColorSande: No descriptor size found in config -> self test\n" );
@@ -57,11 +60,11 @@ LFColorSande::LFColorSande ( const Config *conf, std::string section )
 
     fprintf ( stderr, "LFColorSande::LFColorSande Self Test features:%d dimension:%d\n", ( int ) features.size(), descriptor_size );
   }
-
+  
   if ( descriptor_size != conf->gI ( "features", "descriptor_size", descriptor_size ) )
   {
     cerr << "Warning: LFColorSande: descriptor sizes do not match !!!" << endl;
-  }
+  }  
 }
 
 LFColorSande::~LFColorSande()
@@ -205,6 +208,7 @@ int LFColorSande::extractFeatures ( const NICE::ColorImage & img, VVector & feat
   while ( ! feof ( f ) )
   {
     // <CIRCLE 119 307 1.26134 0 0.00014763>; 0 0 6 2 0 6 25 7 9 4 4 0 0 4 20 36 78 4 5 0 0
+    //<CIRCLE x y scale orientation cornerness>
     if ( fgets ( buffer, buffersize, f ) == NULL )
       break;
 

+ 49 - 308
features/localfeatures/LFColorWeijer.cpp

@@ -2,6 +2,7 @@
 
 #include <fstream>
 #include <iostream>
+#include <exception>
 #include "vislearning/baselib/ColorSpace.h"
 
 using namespace OBJREC;
@@ -30,49 +31,12 @@ const int colors[11][3] =
 LFColorWeijer::LFColorWeijer( const Config *c )
 {
   conf = c;
-
-  bin[0] = conf->gI( "LFColorWeijer", "binL", 10 );
-  bin[1] = conf->gI( "LFColorWeijer", "bina", 20 );
-  bin[2] = conf->gI( "LFColorWeijer", "binb", 20 );
-
-  maxv[0] =  100.0;
-  maxv[1] =   80.0;
-  maxv[2] =   50.0;
-
-  minv[0] =    0.0;
-  minv[1] = -105.0;
-  minv[2] = -200.0;
-
-  tfile = conf->gS( "LFColorWeijer", "table", "/home/dbv/bilder/colorWeijer/color.txt" );
-
-  for ( int i = 0; i < 3; i++ )
-  {
-    interval[i] = ( maxv[i] - minv[i] ) / ( double )bin[i];
-  }
-
-  ifstream test( tfile.c_str() );
-
-  if ( test )
-  {
-    restore();
-  }
-  else
-  {
-    train();
-  }
+  tfile = conf->gS( "LFColorWeijer", "table", "/home/dbv/bilder/colorWeijer/w2c.txt");
+  restore();
 }
 
 LFColorWeijer::~LFColorWeijer()
 {
-  for ( uint i = 0; i < hist.size(); i++ )
-  {
-    for ( uint j = 0; j < hist[i].size(); j++ )
-    {
-      hist[i][j].clear();
-    }
-    hist[i].clear();
-  }
-  hist.clear();
 }
 
 int LFColorWeijer::getDescSize() const
@@ -80,105 +44,45 @@ int LFColorWeijer::getDescSize() const
   return LASTCOLOR;
 }
 
-void LFColorWeijer::store()
+void LFColorWeijer::restore()
 {
-  ofstream fout( tfile.c_str(), ios_base::app );
-
-  fout << hist.size() << " " << hist[0].size() << " " << hist[0][0].size() << " " << hist[0][0][0].size() << endl;
-
-  for ( uint i = 0; i < hist.size(); i++ )
+  ifstream fin( tfile.c_str() );
+  if(!fin.is_open())
   {
-    for ( uint i0 = 0; i0 < hist[i].size(); i0++ )
-    {
-      for ( uint i1 = 0; i1 < hist[i][i0].size(); i1++ )
-      {
-        for ( uint i2 = 0; i2 < hist[i][i0][i1].size(); i2++ )
-        {
-          fout << hist[i][i0][i1][i2] << " ";
-        }
-      }
-    }
+    fthrow(Exception,"ColorWeijer: could not find lookup table file.");
   }
-}
-
-void LFColorWeijer::smooth()
-{
-  int size0 = ( int )hist.size();
-  int size1 = ( int )hist[0].size();
-  int size2 = ( int )hist[0][0].size();
-  int size3 = ( int )hist[0][0][0].size();
-  for ( int i0 = 0; i0 < size1; i0++ )
+  
+  while(!fin.eof())
   {
-    for ( int i1 = 0; i1 < size2; i1++ )
+    double rd,gd,bd;
+    int r,g,b;
+    fin >> rd;
+    fin >> gd;
+    fin >> bd;
+        
+    r = rd/8;
+    g = gd/8;
+    b = bd/8;
+
+    for(int i = 0; i < 11; i++)
     {
-      for ( int i2 = 0; i2 < size3; i2++ )
-      {
-        double maxval = 0.0;
-        for ( int i = 0; i < size0; i++ )
-        {
-          maxval = std::max( maxval, hist[i][i0][i1][i2] );
-        }
-        if ( maxval == 0.0 )
-        {
-          for ( int i = 0; i < size0; i++ )
-          {
-            int anz = 0;
-            for ( int a0 = std::max( i0 - 1, 0 ); a0 <= std::min( i0 + 1, size1 - 1 ); a0++ )
-            {
-              for ( int a1 = std::max( i1 - 1, 0 ); a1 <= std::min( i1 + 1, size2 - 1 ); a1++ )
-              {
-                for ( int a2 = std::max( i2 - 1, 0 ); a2 <= std::min( i2 + 1, size3 - 1 ); a2++ )
-                {
-                  anz++;
-                  hist[i][i0][i1][i2] += hist[i][a0][a1][a2];
-                }
-              }
-            }
-            hist[i][i0][i1][i2] /= anz;
-          }
-        }
-      }
+      fin >> hist[r][g][b][i];
     }
   }
-}
-
-void LFColorWeijer::restore()
-{
-  int size0, size1, size2, size3;
-  ifstream fin( tfile.c_str() );
-  fin >> size0;
-  fin >> size1;
-  fin >> size2;
-  fin >> size3;
-  hist.clear();
-
-  for ( int i = 0; i < size0; i++ )
+    /*
+  for(int r = 0; r < 32; r++)
   {
-    vector<vector<vector<double> > > v2;
-
-    for ( int i0 = 0; i0 < size1; i0++ )
+    for(int g = 0; g < 32; g++)
     {
-      vector<vector<double> > v1;
-
-      for ( int i1 = 0; i1 < size2; i1++ )
+      for(int b = 0; b < 32; b++)
       {
-        vector<double> v0;
-
-        for ( int i2 = 0; i2 < size3; i2++ )
+        for(int i = 0; i < 11; i++)
         {
-          double val;
-          fin >> val;
-          v0.push_back( val );
+          fin >> hist[r][g][b][i];
         }
-
-        v1.push_back( v0 );
       }
-
-      v2.push_back( v1 );
     }
-
-    hist.push_back( v2 );
-  }
+  }  */
 }
 
 int LFColorWeijer::getDescriptors( const NICE::Image & img, VVector & positions, VVector & features ) const
@@ -189,41 +93,25 @@ int LFColorWeijer::getDescriptors( const NICE::Image & img, VVector & positions,
 
 int LFColorWeijer::getDescriptors( const NICE::ColorImage & img, VVector & positions, VVector & features ) const
 {
-  // in Lab umwandeln
-  for ( int i = 0; i < ( int )positions.size(); i++ )
-  {
-    vector<double> vals;
-    vector<int> b;
-    int x = positions[i][0];
-    int y = positions[i][1];
-
-    double R, G, B, X, Y, Z;
-    vector<double> lab( 3, 0.0 );
-
-    R = ( double )img.getPixel( x, y, 0 ) / 255.0;
-    G = ( double )img.getPixel( x, y, 1 ) / 255.0;
-    B = ( double )img.getPixel( x, y, 2 ) / 255.0;
-
-    ColorConversion::ccRGBtoXYZ( R, G, B, &X, &Y, &Z, 0 );
-    ColorConversion::ccXYZtoCIE_Lab( X, Y, Z, &lab[0], &lab[1], &lab[2], 0 );
-
-    for ( int i = 0; i < 3; i++ )
-    {
-      int val = ( int )(( lab[i] - minv[i] ) / interval[i] );
-      val = std::min( val, bin[i] - 1 );
-      val = std::max( val, 0 );
-      b.push_back( val );
-    }
-
-    Vector feat( hist.size() );
+  int width = ( int )img.width();
+  int height = ( int )img.height();
 
-    for ( uint i = 0; i < hist.size(); i++ )
+  for ( int j = 0; j < ( int )positions.size(); j++ )
+  {
+    int x = positions[j][0];
+    int y = positions[j][1];
+    int r = img(x,y,0)/8;
+    int g = img(x,y,1)/8;
+    int b = img(x,y,2)/8;
+      
+    Vector feat( 11 );
+    for ( uint i = 0; i < 11; i++ )
     {
-      feat[i] = hist[i][b[0]][b[1]][b[2]];
+      feat[i] = hist[r][g][b][i];
     }
     features.push_back( feat );
   }
-
+ 
   return 1;
 }
 
@@ -232,20 +120,6 @@ void LFColorWeijer::visualizeFeatures( NICE::Image & mark, const VVector & posit
 
 }
 
-void LFColorWeijer::add( vector<vector<vector<double> > > &dest, vector<vector<vector<double> > > &src )
-{
-  for ( uint i0 = 0; i0 < src.size(); i0++ )
-  {
-    for ( uint i1 = 0; i1 < src[i0].size(); i1++ )
-    {
-      for ( uint i2 = 0; i2 < src[i0][i1].size(); i2++ )
-      {
-        dest[i0][i1][i2] += src[i0][i1][i2];
-      }
-    }
-  }
-}
-
 int LFColorWeijer::findColor( string &fn )
 {
   if ( fn.find( "black" ) != string::npos )
@@ -274,130 +148,6 @@ int LFColorWeijer::findColor( string &fn )
   return -1;
 }
 
-vector<vector<vector<double > > > LFColorWeijer::createTable()
-{
-  vector<vector<vector<double> > > h;
-  for ( int i0 = 0; i0 < bin[0]; i0++ )
-  {
-    vector<vector< double > > vec;
-    for ( int i1 = 0; i1 < bin[1]; i1++ )
-    {
-      vector<double> v;
-      for ( int i2 = 0; i2 < bin[2]; i2++ )
-      {
-        v.push_back( 0.0 );
-      }
-      vec.push_back( v );
-    }
-    h.push_back( vec );
-  }
-  return h;
-}
-
-void LFColorWeijer::normalize( vector<vector<vector<double> > > &tab )
-{
-  double sum = 0.0;
-
-  for ( uint i0 = 0; i0 < tab.size(); i0++ )
-  {
-    for ( uint i1 = 0; i1 < tab[i0].size(); i1++ )
-    {
-      for ( uint i2 = 0; i2 < tab[i0][i1].size(); i2++ )
-      {
-        sum += tab[i0][i1][i2];
-      }
-    }
-  }
-
-  for ( uint i0 = 0; i0 < tab.size(); i0++ )
-  {
-    for ( uint i1 = 0; i1 < tab[i0].size(); i1++ )
-    {
-      for ( uint i2 = 0; i2 < tab[i0][i1].size(); i2++ )
-      {
-        tab[i0][i1][i2] /= sum;
-      }
-    }
-  }
-
-  return;
-}
-
-void LFColorWeijer::createHist( const ColorImage &cimg, vector<vector<vector<double> > > &hist, Image &mask )
-{
-  // in Lab umwandeln
-  NICE::MultiChannelImageT<double> genimg, imglab;
-
-  ColorSpace::ColorImagetoMultiChannelImage( cimg, genimg );
-  ColorSpace::convert( imglab, genimg, ColorSpace::COLORSPACE_LAB, ColorSpace::COLORSPACE_RGB );
-
-  for ( int y = 0; y < cimg.height(); y++ )
-  {
-    for ( int x = 0; x < cimg.width(); x++ )
-    {
-      if ( mask.getPixel( x, y ) == 0 )
-        continue;
-      vector<int> b;
-      for ( int i = 0; i < 3; i++ )
-      {
-        int val = ( int )(( imglab.get( x, y, i ) - minv[i] ) / interval[i] );
-        val = std::min( val, bin[i] - 1 );
-        b.push_back( val );
-      }
-      hist[b[0]][b[1]][b[2]]++;
-    }
-  }
-}
-
-void LFColorWeijer::train()
-{
-  cout << "train Starts" << endl;
-  for ( int i = 0; i < LASTCOLOR; i++ )
-  {
-    vector<vector<vector<double> > > h = createTable();
-    hist.push_back( h );
-  }
-
-  string dir = conf->gS( "LFColorWeijer", "table", "/home/dbv/bilder/colorWeijer/ebay/" );
-  string images = conf->gS( "LFColorWeijer", "table", "test_images.txt" );
-  string mask = conf->gS( "LFColorWeijer", "table", "mask_images.txt" );
-
-  string imagesfn;
-  string maskfn;
-
-  ifstream finimg(( dir + images ).c_str() );
-  ifstream finmask(( dir + mask ).c_str() );
-  cout << dir + images << endl;
-  cout << dir + mask << endl;
-  // lese bilder und masken ein
-  while ( finimg >> imagesfn && finmask >> maskfn )
-  {
-    Image mimg( dir + maskfn );
-    cout << dir + maskfn << endl;
-    ColorImage cimg( dir + imagesfn );
-
-    int col = findColor( imagesfn );
-    vector<vector<vector<double> > > tab = createTable();
-
-    createHist( cimg, tab, mimg ); // erzeuge Lab Histogramm des Bildes
-
-    normalize( tab );
-
-    add( hist[col], tab );
-  }
-  finimg.close();
-  finmask.close();
-
-  // normalisiere alle lookuptables
-  for ( uint i = 0; i < hist.size(); i++ )
-  {
-    normalize( hist[i] );
-  }
-
-  smooth();
-  store();
-}
-
 void LFColorWeijer::visualizeFeatures( NICE::ColorImage & out, const VVector & features, const VVector & position ) const
 {
   for ( int i = 0; i < ( int )position.size(); i++ )
@@ -477,28 +227,19 @@ void LFColorWeijer::getFeats( const ColorImage &img, MultiChannelImageT<double>
 {
   int width = ( int )img.width();
   int height = ( int )img.height();
-  feats.reInit( width, height, hist.size());
-
-  NICE::MultiChannelImageT<double> genimg, imglab;
-
-  ColorSpace::ColorImagetoMultiChannelImage( img, genimg );
-  ColorSpace::convert( imglab, genimg, ColorSpace::COLORSPACE_LAB, ColorSpace::COLORSPACE_RGB );
+  feats.reInit( width, height, 11);
 
   for ( int y = 0; y < height; y++ )
   {
     for ( int x = 0; x < width; x++ )
     {
-      for ( uint i = 0; i < hist.size(); i++ )
+      int r = img(x,y,0)/8;
+      int g = img(x,y,1)/8;
+      int b = img(x,y,2)/8;
+      
+      for ( uint i = 0; i < 11; i++ )
       {
-        vector<double> b( 3, 0.0 );
-        for ( int j = 0; j < 3; j++ )
-        {
-          int val = ( int )(( imglab.get( x, y, j ) - minv[j] ) / interval[j] );
-          val = std::min( val, bin[j] - 1 );
-          val = std::max( val, 0 );
-          b[j] = val;
-        }
-        feats.set( x, y, hist[i][b[0]][b[1]][b[2]], i );
+        feats.set( x, y, hist[r][g][b][i], i );
       }
     }
   }

+ 4 - 60
features/localfeatures/LFColorWeijer.h

@@ -41,24 +41,12 @@ class LFColorWeijer : public LocalFeature
       LASTCOLOR
     };
 
-    //! bins for L*, a* and b* chanel of L*a*b*
-    int bin[3];
+    //! lookup table
+    double hist[32][32][32][11];
 
-    //! upper limits for L*, a* and b* chanel of L*a*b*
-    double maxv[3];
-
-    //! lower limits for L*, a* and b* chanel of L*a*b*
-    double minv[3];
-
-    //! quantization interval for L*, a* and b* chanel of L*a*b* depending on bin, maxv and minv
-    double interval[3];
-
-    //! destination of the computed lookuptable
+    //! destination of the precomputed lookuptable
     std::string tfile;
-
-    //! lookuptable for the probabilities (4d: colors, L-channel, a-channel, b-channel)
-    std::vector<std::vector<std::vector<std::vector<double> > > > hist;
-
+    
     //! configuration file
     const NICE::Config *conf;
 
@@ -123,34 +111,11 @@ class LFColorWeijer : public LocalFeature
      */
     void visualizeFeatures ( const NICE::ColorImage & cimg, NICE::ColorImage & out ) const;
 
-    /**
-     * save parameters
-     */
-    void store();
-
-
     /**
      * load parameters
      */
     void restore();
 
-    /**
-     * smooths the look up table
-     */
-    void smooth();
-
-    /**
-     * normalizes the sum of a 3d histogram to 1
-     * @param tab 3d histogram
-     */
-    void normalize ( std::vector<std::vector<std::vector<double> > > &tab );
-
-    /**
-     * creates a new and empty table
-     * @return table of the size bin[0]xbin[1]xbin[2]
-     */
-    std::vector<std::vector<std::vector<double > > > createTable();
-
     /**
      * finds a colorname in a given string
      * @param fn input string
@@ -158,27 +123,6 @@ class LFColorWeijer : public LocalFeature
      */
     int findColor ( std::string &fn );
 
-    /**
-     * creates a new Histogram for input image depending on the image mask
-     * @param cimg input image
-     * @param hist histogram
-     * @param mask which pixel should be consider
-     */
-    void createHist ( const NICE::ColorImage &cimg, std::vector<std::vector<std::vector<double> > > &hist, NICE::Image &mask );
-
-    /**
-     * train the lookuptable
-     */
-    void train();
-
-
-    /**
-     * add a 3d table to a 3d table elementwise
-     * @param dest destination table
-     * @param src source table
-     */
-    void add ( std::vector<std::vector<std::vector<double> > > &dest, std::vector<std::vector<std::vector<double> > > &src );
-
     /**
      * transform each pixel of an image
      * @param img input image

+ 29 - 27
features/localfeatures/LFGenericLocal.h

@@ -1,9 +1,8 @@
 /** 
 * @file LFGenericLocal.h
-* @brief generic local features
+* @brief generic local features ( Random Sampling of POIs and SIFT as descriptor)
 * @author Erik Rodner
 * @date 02/05/2008
-
 */
 #ifndef LFGENERICLOCALINCLUDE
 #define LFGENERICLOCALINCLUDE
@@ -21,33 +20,36 @@
 
 namespace OBJREC {
 
-/** generic local features */
-class LFGenericLocal : public LocalFeatureRepresentation
-{
+  /** generic local features */
+  /** @class LFGenericLocal
+ * @brief Generic local features ( actually: Random Sampling of POIs followed by SIFT as descriptor)
+ */  
+  class LFGenericLocal : public LocalFeatureRepresentation
+  {
+
+      protected:
+    LocalFeature *lf;
+    InterestDetector *id;
+
+      public:
+    
+    /** simple constructor */
+    LFGenericLocal( const NICE::Config *conf, int numFeatures );
+        
+    /** simple destructor */
+    virtual ~LFGenericLocal();
+      
+    int getDescSize () const;
 
-    protected:
-	LocalFeature *lf;
-	InterestDetector *id;
+    int extractFeatures ( const NICE::Image & img, 
+              NICE::VVector & features, 
+              NICE::VVector & positions) const;
+              
+    void visualizeFeatures ( NICE::Image & mark,
+          const NICE::VVector & positions,
+          size_t color ) const;
 
-    public:
-  
-	/** simple constructor */
-	LFGenericLocal( const NICE::Config *conf, int numFeatures );
-      
-	/** simple destructor */
-	virtual ~LFGenericLocal();
-     
-	int getDescSize () const;
-
-	int extractFeatures ( const NICE::Image & img, 
-			      NICE::VVector & features, 
-			      NICE::VVector & positions) const;
-			      
-	void visualizeFeatures ( NICE::Image & mark,
-				 const NICE::VVector & positions,
-				 size_t color ) const;
-
-};
+  };
 
 
 } // namespace

+ 5 - 4
features/localfeatures/LFReadCache.cpp

@@ -20,14 +20,15 @@ using namespace NICE;
 
 LFReadCache::LFReadCache ( const Config *conf,
                            const LocalFeatureRepresentation *_lfrep,
-                           int _numFeatures ) : lfrep ( _lfrep )
+                           int _numFeatures,
+                           const std::string & _section ) : lfrep ( _lfrep )
 {
   //srand(time(NULL));
   numFeatures = _numFeatures;
-  cachedir = conf->gS ( "cache", "root" );
-  cachemode = Globals::getCacheMode ( conf->gS ( "cache", "mode", "cat" ) );
+  cachedir = conf->gS ( _section, "root" );
+  cachemode = Globals::getCacheMode ( conf->gS ( _section, "mode", "cat" ) );
 
-  std::string descFormat_s = conf->gS ( "cache", "descriptor_format", "binary_double" );
+  std::string descFormat_s = conf->gS ( _section, "descriptor_format", "binary_double" );
   if ( descFormat_s == "binary_double" )
     descFormat = VVector::FILEFORMAT_BINARY_DOUBLE;
   else if ( descFormat_s == "binary_uchar" )

+ 69 - 63
features/localfeatures/LFReadCache.h

@@ -1,7 +1,7 @@
 /** 
 * @file LFReadCache.h
 * @brief read local features from file
-* @author Erik Rodner
+* @author Erik Rodner, Alexander Freytag
 * @date 02/14/2008
 
 */
@@ -19,68 +19,74 @@
 
 namespace OBJREC {
 
-/** read local features from file */
-class LFReadCache : public LocalFeatureRepresentation
-{
-
-    protected:
-		int   numFeatures;
-		const LocalFeatureRepresentation *lfrep;
-		std::string cachedir;
-
-		int descFormat;
-		int cachemode;
-
-		template <class ImageClass>
-		int extractFeaturesTemplate ( const ImageClass & img, 
-				  NICE::VVector & features, 
-				  NICE::VVector & positions) const;
-
-    public:
-  
-	/** constructor 
-	 * @param conf Configuration
-	 * @param lfrep a LocalFeatureRepresentation (i.e. LFColorSande)
-	 * @param _numfeatures how many features should be returned (-1 for all)
-	 */
-	LFReadCache( const NICE::Config *conf, 
-		     const LocalFeatureRepresentation *lfrep,
-		     int _numFeatures = -1 );
-      
-	/** simple destructor */
-	virtual ~LFReadCache();
-
-	int getDescSize () const;
-
-	/**
-	 * extract features for gray images
-	 * @param img input image
-	 * @param features output features
-	 * @param positions position of the features
-	 * @return 
-	 */
-	int extractFeatures ( const NICE::Image & img, 
-			      NICE::VVector & features, 
-			      NICE::VVector & positions ) const;
-	
-	/**
-	 * extract features for color images
-	 * @param img input image
-	 * @param features output features
-	 * @param positions position of the features
-	 * @return 
-	 */
-	int extractFeatures ( const NICE::ColorImage & img, 
-			      NICE::VVector & features, 
-			      NICE::VVector & positions ) const;
-
-	void visualize ( NICE::Image & img, 
-		 const NICE::Vector & feature ) const;
-
-	void visualizeFeatures ( NICE::Image & mark,
-				 const NICE::VVector & positions,
-				 size_t color ) const;
-};
+  /** @class LFReadCache
+  * @brief Read local features from file
+  *
+  */   
+  class LFReadCache : public LocalFeatureRepresentation
+  {
+
+      protected:
+      int   numFeatures;
+      const LocalFeatureRepresentation *lfrep;
+      std::string cachedir;
+
+      int descFormat;
+      int cachemode;
+
+      template <class ImageClass>
+      int extractFeaturesTemplate ( const ImageClass & img, 
+            NICE::VVector & features, 
+            NICE::VVector & positions) const;
+
+      public:
+    
+    /** standard constructor 
+    * @param conf Configuration
+    * @param lfrep a LocalFeatureRepresentation (i.e. LFColorSande)
+    * @param _numfeatures how many features should be returned (-1 for all)
+    * @param _section specify the block in the config object we read 
+    */
+    LFReadCache( const NICE::Config *conf, 
+          const LocalFeatureRepresentation *lfrep,
+          int _numFeatures = -1,
+          const std::string & _section = "cache"          
+               );
+        
+    /** simple destructor */
+    virtual ~LFReadCache();
+
+    int getDescSize () const;
+
+    /**
+    * extract features for gray images
+    * @param img input image
+    * @param features output features
+    * @param positions position of the features
+    * @return 
+    */
+    int extractFeatures ( const NICE::Image & img, 
+              NICE::VVector & features, 
+              NICE::VVector & positions ) const;
+    
+    /**
+    * extract features for color images
+    * @param img input image
+    * @param features output features
+    * @param positions position of the features
+    * @return 
+    */
+    int extractFeatures ( const NICE::ColorImage & img, 
+              NICE::VVector & features, 
+              NICE::VVector & positions ) const;
+
+    void visualize ( NICE::Image & img, 
+      const NICE::Vector & feature ) const;
+
+    void visualizeFeatures ( NICE::Image & mark,
+          const NICE::VVector & positions,
+          size_t color ) const;
+  };
 
 } // namespace
 

+ 2 - 0
features/localfeatures/LFReadCache.tcc

@@ -40,7 +40,9 @@ int LFReadCache::extractFeaturesTemplate ( const ImageClass & img,
     if ( lfrep == NULL )
       fthrow ( NICE::Exception, "LocalFeatureRepresentation not available, recovering is impossible!" );
 
+    std::cerr << "extract features with lfrep used in ReadCache" << std::endl;
     lfrep->extractFeatures ( img, features, positions );
+    std::cerr << "features extracted" << std::endl;
 
     features.save ( filename_desc, descFormat );
     positions.save ( filename_pos, NICE::VVector::FILEFORMAT_LINE );

+ 5 - 4
features/localfeatures/LFWriteCache.cpp

@@ -29,12 +29,13 @@ using namespace NICE;
 
 
 LFWriteCache::LFWriteCache ( const Config *conf,
-                             const LocalFeatureRepresentation *_lfrep ) : lfrep ( _lfrep )
+                             const LocalFeatureRepresentation *_lfrep,
+                             const std::string & _section ) : lfrep ( _lfrep )
 {
-  cachedir = conf->gS ( "cache", "root" );
-  cachemode = Globals::getCacheMode ( conf->gS ( "cache", "mode", "cat" ) );
+  cachedir = conf->gS ( _section, "root" );
+  cachemode = Globals::getCacheMode ( conf->gS ( _section, "mode", "cat" ) );
 
-  std::string descFormat_s = conf->gS ( "cache", "descriptor_format", "binary_double" );
+  std::string descFormat_s = conf->gS ( _section, "descriptor_format", "binary_double" );
   if ( descFormat_s == "binary_double" )
     descFormat = VVector::FILEFORMAT_BINARY_DOUBLE;
   else if ( descFormat_s == "binary_uchar" )

+ 55 - 50
features/localfeatures/LFWriteCache.h

@@ -1,7 +1,7 @@
 /** 
 * @file LFWriteCache.h
-* @brief write local features to file
-* @author Erik Rodner
+* @brief Write local features to file (whenever a descriptor is computed, it will be checked whether a corresponding file already exists. If not, we save the descriptor)
+* @author Erik Rodner, Alexander Freytag
 * @date 02/14/2008
 
 */
@@ -18,59 +18,64 @@
 
 namespace OBJREC {
 
-/** write local features to file */
-class LFWriteCache : public LocalFeatureRepresentation
-{
+  /** @class LFWriteCache
+  * @brief Write local features to file (whenever a descriptor is computed, it will be checked whether a corresponding file already exists. If not, we save the descriptor)
+  *
+  */  
+  class LFWriteCache : public LocalFeatureRepresentation
+  {
 
-    protected:
-	const LocalFeatureRepresentation *lfrep;
+      protected:
+        const LocalFeatureRepresentation *lfrep;
 
-	std::string cachedir;
+        std::string cachedir;
 
-	int descFormat;
-	int cachemode;
+        int descFormat;
+        int cachemode;
 
 
-    public:
-  
-		/** simple constructor */
-		LFWriteCache( const NICE::Config *conf, 
-				const LocalFeatureRepresentation *lfrep ); 
-		
-		/** simple destructor */
-		virtual ~LFWriteCache();
-	
-		int getDescSize () const;
-	
-		/**
-		* extract features for gray images
-		* @param img input image
-		* @param features output features
-		* @param positions position of the features
-		* @return 
-		*/
-		int extractFeatures ( const NICE::Image & img, 
-					NICE::VVector & features, 
-					NICE::VVector & positions ) const;
-		
-		/**
-		* extract features for color images
-		* @param img input image
-		* @param features output features
-		* @param positions position of the features
-		* @return 
-		*/
-		int extractFeatures ( const NICE::ColorImage & img, 
-					NICE::VVector & features, 
-					NICE::VVector & positions ) const;
-	
-		void visualize ( NICE::Image & img, 
-			const NICE::Vector & feature ) const;
-	
-		void visualizeFeatures ( NICE::Image & mark,
-					const NICE::VVector & positions,
-					size_t color ) const;
-};
+      public:
+    
+        /** simple constructor */
+        LFWriteCache( const NICE::Config *conf, 
+            const LocalFeatureRepresentation *lfrep,
+            const std::string & _section = "cache"
+                    ); 
+        
+        /** simple destructor */
+        virtual ~LFWriteCache();
+      
+        int getDescSize () const;
+      
+        /**
+        * extract features for gray images
+        * @param img input image
+        * @param features output features
+        * @param positions position of the features
+        * @return 
+        */
+        int extractFeatures ( const NICE::Image & img, 
+              NICE::VVector & features, 
+              NICE::VVector & positions ) const;
+        
+        /**
+        * extract features for color images
+        * @param img input image
+        * @param features output features
+        * @param positions position of the features
+        * @return 
+        */
+        int extractFeatures ( const NICE::ColorImage & img, 
+              NICE::VVector & features, 
+              NICE::VVector & positions ) const;
+      
+        void visualize ( NICE::Image & img, 
+          const NICE::Vector & feature ) const;
+      
+        void visualizeFeatures ( NICE::Image & mark,
+              const NICE::VVector & positions,
+              size_t color ) const;
+  };
 
 
 } // namespace

+ 27 - 24
features/localfeatures/LocalFeature.h

@@ -1,7 +1,7 @@
 /** 
 * @file LocalFeature.h
-* @brief local feature interface
-* @author Erik Rodner
+* @brief Abstract class for Local Features ( ONLY DESCRIPTORS, NO DETECTORS )
+* @author Erik Rodner, Alexander Freytag
 * @date 02/05/2008
 
 */
@@ -17,31 +17,34 @@
 
 namespace OBJREC {
 
-/** local feature interface */
-class LocalFeature
-{
+    /** @class LocalFeature
+  * @brief Abstract class for Local Features ( ONLY DESCRIPTORS, NO DETECTORS )
+  *
+  */
+  class LocalFeature
+  {
 
-    protected:
+      protected:
 
-    public:
-  
-	/** simple constructor */
-	LocalFeature();
-      
-	/** simple destructor */
-	virtual ~LocalFeature();
-
-	virtual int getDescSize() const = 0;
-
-	virtual int getDescriptors ( const NICE::Image & img, NICE::VVector & positions, NICE::VVector & descriptors) const = 0;
-	
-	virtual int getDescriptors ( const NICE::ColorImage & img, NICE::VVector & positions, NICE::VVector & descriptors) const;
-	
-	virtual void visualizeFeatures ( NICE::Image & mark,
-				 const NICE::VVector & positions,
-				 size_t color ) const;
+      public:
     
-};
+    /** simple constructor */
+    LocalFeature();
+        
+    /** simple destructor */
+    virtual ~LocalFeature();
+
+    virtual int getDescSize() const = 0;
+
+    virtual int getDescriptors ( const NICE::Image & img, NICE::VVector & positions, NICE::VVector & descriptors) const = 0;
+    
+    virtual int getDescriptors ( const NICE::ColorImage & img, NICE::VVector & positions, NICE::VVector & descriptors) const;
+    
+    virtual void visualizeFeatures ( NICE::Image & mark,
+          const NICE::VVector & positions,
+          size_t color ) const;
+      
+  };
 
 
 } // namespace

+ 14 - 12
features/localfeatures/LocalFeatureLFInterface.cpp

@@ -10,34 +10,36 @@ using namespace NICE;
 
 LocalFeatureLFInterface::LocalFeatureLFInterface( const Config *conf, LocalFeatureRepresentation *_lfpres )
 {
-	lfpres = _lfpres;
+  lfpres = _lfpres;
 }
 
 LocalFeatureLFInterface::~LocalFeatureLFInterface()
 {
-	delete lfpres;
+  delete lfpres;
 }
 
 
 int LocalFeatureLFInterface::getDescriptors ( const NICE::Image & img, VVector & positions, VVector & descriptors ) const
 {
-	lfpres->extractFeatures(img, descriptors, positions);
-	assert(descriptors.size() == positions.size());
-    return 0;
+  //TODO do we want to ignore the positions of lfrep and use the given ones, or do we indeed want to compute positions on our own? If so, why do we use the Interface to LocalFeature, and not directly LocalFeatureRepresentation?    
+  lfpres->extractFeatures(img, descriptors, positions);
+  assert(descriptors.size() == positions.size());
+  return 0;
 }
 
 int LocalFeatureLFInterface::getDescriptors ( const NICE::ColorImage & img, VVector & positions, VVector & descriptors) const
 {
-	lfpres->extractFeatures(img, descriptors, positions);
-	assert(descriptors.size() == positions.size());
-	return 0;
+  //TODO do we want to ignore the positions of lfrep and use the given ones, or do we indeed want to compute positions on our own? If so, why do we use the Interface to LocalFeature, and not directly LocalFeatureRepresentation?
+  lfpres->extractFeatures(img, descriptors, positions);
+  assert(descriptors.size() == positions.size());
+  return 0;
 }
 
 void LocalFeatureLFInterface::visualizeFeatures ( NICE::Image & mark,
-				 const VVector & positions,
-				 size_t color ) const
+        const VVector & positions,
+        size_t color ) const
 {
-	//cerr << "LocalFeatureLFInterface::visualizeFeatures(...) not yet implemented" << endl;
-	lfpres->visualizeFeatures(mark, positions, color);
+  //cerr << "LocalFeatureLFInterface::visualizeFeatures(...) not yet implemented" << endl;
+  lfpres->visualizeFeatures(mark, positions, color);
 }
 

+ 44 - 41
features/localfeatures/LocalFeatureLFInterface.h

@@ -1,6 +1,6 @@
 /** 
 * @file LocalFeatureLFInterface.h
-* @brief interface to LF
+* @brief Interface to use a LocalFeature (Descriptor only) with routines of LocalFeatureRepresentations (Detector + Descriptor)
 * @author Björn Fröhlich
 * @date 09/07/2010
 
@@ -19,50 +19,53 @@
 
 namespace OBJREC {
 
-/** local feature with LF */
-class LocalFeatureLFInterface : public LocalFeature
-{
 
-    protected:
-		LocalFeatureRepresentation *lfpres;
+  /** @class LocalFeatureLFInterface
+  * @brief Interface to use a LocalFeature (Descriptor only) with routines of LocalFeatureRepresentations (Detector + Descriptor)
+  *
+  */  
+  class LocalFeatureLFInterface : public LocalFeature
+  {
 
-    public:
-  
-	/** simple constructor */
-		LocalFeatureLFInterface ( const NICE::Config *conf, LocalFeatureRepresentation *_lfpres );
-      
-	/** simple destructor */
+      protected:
+      LocalFeatureRepresentation *lfpres;
+
+      public:
+    
+    /** simple constructor */
+      LocalFeatureLFInterface ( const NICE::Config *conf, LocalFeatureRepresentation *_lfpres );
+        
+    /** simple destructor */
 
-	virtual ~LocalFeatureLFInterface();
-	
-	/**
-	 * returns the size of each the SIFT-Feature
-	 * @return 128
-	 */
-	int getDescSize() const { return lfpres->getDescSize(); };
-	
-	/** 
-	 * get the descriptor
-	 * @param img input image
-	 * @param positions positions for the SIFT features
-	 * @param descriptors output
-	 * @return 0
-	 */
-	int getDescriptors ( const NICE::Image & img, NICE::VVector & positions, NICE::VVector & descriptors ) const;
-	
-	/** 
-	 * get the descriptor
-	 * @param img input color image
-	 * @param positions positions for the SIFT features
-	 * @param descriptors output
-	 * @return 0
-	 */
-	int getDescriptors ( const NICE::ColorImage & img, NICE::VVector & positions, NICE::VVector & descriptors) const;
-				     
-	void visualizeFeatures ( NICE::Image & mark, const NICE::VVector & positions, size_t color ) const;
+    virtual ~LocalFeatureLFInterface();
+    
+    /**
+    * @brief returns the size of each the SIFT-Feature
+    */
+    int getDescSize() const { return lfpres->getDescSize(); };
+    
+    /** 
+    * @brief get the descriptor
+    * @param img input image
+    * @param positions positions for local features
+    * @param descriptors output
+    * @return 0
+    */
+    int getDescriptors ( const NICE::Image & img, NICE::VVector & positions, NICE::VVector & descriptors ) const;
+    
+    /** 
+    * @brief get the descriptor
+    * @param img input color image
+    * @param positions positions for the SIFT features
+    * @param descriptors output
+    * @return 0
+    */
+    int getDescriptors ( const NICE::ColorImage & img, NICE::VVector & positions, NICE::VVector & descriptors) const;
+              
+    void visualizeFeatures ( NICE::Image & mark, const NICE::VVector & positions, size_t color ) const;
 
-     
-};
+      
+  };
 
 
 } // namespace

+ 8 - 2
features/localfeatures/LocalFeatureRepresentation.h

@@ -1,7 +1,7 @@
 /** 
 * @file LocalFeatureRepresentation.h
-* @brief absract class for the representation of an image with local feature descriptors
-* @author Erik Rodner
+* @brief Absract class for Local Feature Representations (Detector + Descriptor)
+* @author Erik Rodner, Alexander Freytag
 * @date 11/19/2007
 
 */
@@ -21,6 +21,12 @@
 namespace OBJREC {
 
 /** absract class for the representation of an image with local feature descriptors */
+/** NOTE: This class returns Descriptors, which DO NOT need any given positions. All Descriptors calculate there own positions, on DIFFERENT ways. **/
+
+  /** @class LocalFeatureRepresentation
+ * @brief Absract class for Local Feature Representations (Detector + Descriptor)
+ *
+ */
 class LocalFeatureRepresentation
 {
 

+ 1 - 1
features/localfeatures/libdepend.inc

@@ -3,4 +3,4 @@ $(call PKG_DEPEND_EXT,OPENMP)
 $(call PKG_DEPEND_INT,core)
 $(call PKG_DEPEND_INT,vislearning/baselib)
 $(call PKG_DEPEND_INT,vislearning/image)
-$(call PKG_DEPEND_INT,vislearning/features/fbase)
+$(call PKG_DEPEND_INT,vislearning/features/fbase)

+ 38 - 4
features/localfeatures/progs/testColorWeijer.cpp

@@ -5,24 +5,58 @@
 #include "core/imagedisplay/ImageDisplay.h"
 #include <iostream>
 #include "vislearning/features/localfeatures/LFColorWeijer.h"
+#include <getopt.h>
 
 using namespace std;
 using namespace NICE;
 using namespace OBJREC;
 
-int main(int argc, char **argv)
+
+/**
+ * @brief Printing main menu.
+ * @author Alexander Freytag
+ * @date 13-02-2013
+ * 
+ * @return void
+ **/
+void print_main_menu()
+{
+  std::cerr << "=====================================================================================" << std::endl;
+  std::cerr << "||This is a small programm demonstrating the computation of 11-dim color features.  ||" << std::endl;
+  std::cerr << "=====================================================================================" << std::endl;  
+  
+  std::cout << std::endl << "Input options:" << std::endl;
+  std::cout << "   -i <filename>  the name of the image which shall be transformed"<< std::endl;
+  return;
+}
+
+
+//post-process active learning segmentation results, such that the given images are normalized to be visualized in the same range
+int main( int argc, char* argv[] )
 {
-  if (argc < 1)
+  
+  int rc;
+  if (argc<2)
   {
-    cerr << "Bitte Bild angeben" << endl;
+    print_main_menu();
     return -1;
   }
+  
+  std::string filename("");
+  while ((rc=getopt(argc,argv,"i:h"))>=0)
+  {
+    switch(rc)
+    {
+      case 'i': filename = optarg; break;
+      default: print_main_menu();
+    }
+  }   
 
   Config *conf = new Config();
   LFColorWeijer lfc(conf);
 
   //! testen
-  ColorImage cimg(argv[1]);
+  ColorImage cimg(filename);
   ColorImage out;
   lfc.visualizeFeatures (cimg, out);
 

+ 142 - 0
features/simplefeatures/BoWFeatureConverter.cpp

@@ -0,0 +1,142 @@
+/** 
+* @file BoWFeatureConverter.cpp
+* @brief Convert a set of features into a Bag of visual Words histogram (either by Vector Quantization, or Hard / Soft Assignment)
+* @author Alexander Freytag
+* @date 11-06-2013 (dd-mm-yyyy)
+*/
+#include <iostream>
+#include <fstream>
+
+#include "vislearning/features/simplefeatures/BoWFeatureConverter.h"
+
+using namespace OBJREC;
+
+using namespace std;
+using namespace NICE;
+
+
+
+BoWFeatureConverter::BoWFeatureConverter( 
+    const Config *conf, 
+    const Codebook *_codebook, const std::string _section )
+    : codebook(_codebook)
+{
+  this->s_section = _section;
+  this->p_conf = conf;
+  
+  std::string normalizationMethod = conf->gS( _section, "normalizationMethod", "sum" );
+  
+  if ( normalizationMethod == "sum" )
+    this->n_normalizationMethod = NORMALIZE_SUM;
+  else if ( normalizationMethod == "binzero" )
+    this->n_normalizationMethod = NORMALIZE_BINZERO;
+  else if ( normalizationMethod == "raw" )
+    this->n_normalizationMethod = NORMALIZE_RAW;
+  else if ( normalizationMethod == "thresh" )
+    this->n_normalizationMethod = NORMALIZE_THRESH;
+  else
+  {
+    //default: L1 normalization
+    this->n_normalizationMethod = NORMALIZE_SUM;    
+  }
+  
+  std::string n_quantizationMethod = conf->gS( _section, "n_quantizationMethod", "VQ" );
+  
+  if ( normalizationMethod == "VQ" )
+    this->n_quantizationMethod = VECTOR_QUANTIZATION;
+  else if ( normalizationMethod == "VA" )
+    this->n_quantizationMethod = VECTOR_ASSIGNMENT;
+  else
+  {
+    //default: standard vector quantization
+    this->n_quantizationMethod = VECTOR_QUANTIZATION;    
+  }  
+}
+
+BoWFeatureConverter::~BoWFeatureConverter()
+{
+}
+
+void BoWFeatureConverter::calcHistogram ( const NICE::VVector & features,
+          NICE::Vector & histogram , const bool & b_resetHistogram )
+{
+  if ( b_resetHistogram || (histogram.size() != this->codebook->getCodebookSize() ) )
+  {
+    histogram.resize( this->codebook->getCodebookSize() );
+    histogram.set(0);
+  }
+
+  int cluster_index = 0;
+  double weight = 0;
+  double distance = 0.0;
+  if ( this->n_quantizationMethod == VECTOR_QUANTIZATION )
+  {
+    for ( NICE::VVector::const_iterator featIt  = features.begin();
+            featIt != features.end();
+            featIt++ )
+    {
+      const NICE::Vector & x = *featIt;
+      this->codebook->voteVQ ( x, cluster_index, weight, distance );
+      histogram[ cluster_index ] ++;
+    }    
+  }
+  else // VECTOR_ASSIGNMENT (hard or soft can be set directly in the codebook-object)
+  {
+    
+    NICE::Vector assignment (this->codebook->getCodebookSize() );;
+    for ( NICE::VVector::const_iterator featIt  = features.begin();
+            featIt != features.end();
+            featIt++ )
+    { 
+      assignment.set(0);
+      const NICE::Vector & x = *featIt;
+      this->codebook->voteVA ( x, assignment );
+      histogram += assignment;
+    }      
+  }
+
+}
+
+void BoWFeatureConverter::normalizeHistogram ( NICE::Vector & histogram )
+{
+    if ( n_normalizationMethod == NORMALIZE_RAW ) {
+    // do nothing
+    } else if ( n_normalizationMethod == NORMALIZE_BINZERO ) {
+    for ( size_t i = 0 ; i < histogram.size() ; i++ )
+      if ( histogram[i] > 0 ) histogram[i] = 1.0; 
+    } else if ( n_normalizationMethod == NORMALIZE_SUM  ) {
+    double sum = 0.0;
+    for ( size_t i = 0 ; i < histogram.size() ; i++ )
+    {
+      assert ( histogram[i] >= 0.0 );
+      sum += histogram[i];
+    }
+
+    if ( sum < 1e-5 ) {
+      fprintf (stderr, "BoWFeatureConverter::normalizeHistogram: WARNING histogram is zero !!\n");
+      return;
+    }
+
+    for ( size_t i = 0 ; i < histogram.size() ; i++ )
+      histogram[i] /= sum;
+    } else if ( n_normalizationMethod == NORMALIZE_THRESH ) {
+    const NICE::Vector & thresholds = codebook->getThresholds();
+
+    if ( thresholds.size() <= 0 ) {
+      fprintf (stderr, "BoWFeatureConverter:: This is maybe an OLD codebook ! \n");
+      exit(-1);
+    }
+    for ( size_t i = 0 ; i < histogram.size() ; i++ )
+      histogram[i] = (histogram[i] > thresholds[i]) ? 1.0 : 0.0; 
+    }
+}
+
+int BoWFeatureConverter::getNormalizationMethod () const
+{
+    return n_normalizationMethod;
+}
+
+void BoWFeatureConverter::setNormalizationMethod ( int normalizationMethod )
+{
+    n_normalizationMethod = normalizationMethod;
+}

+ 101 - 0
features/simplefeatures/BoWFeatureConverter.h

@@ -0,0 +1,101 @@
+/** 
+* @file BoWFeatureConverter.h
+* @brief Convert a set of features into a Bag of visual Words histogram (either by Vector Quantization, or Hard / Soft Assignment)
+* @author Alexander Freytag
+* @date 11-06-2013 (dd-mm-yyyy)
+*/
+#ifndef BOWFEATURECONVERTERINCLUDE
+#define BOWFEATURECONVERTERINCLUDE
+
+#include "core/vector/VectorT.h"
+#include "core/vector/VVector.h"
+#include "core/vector/MatrixT.h"
+
+#include "core/basics/Config.h"
+
+#include "Codebook.h"
+
+
+namespace OBJREC {
+
+
+  /**
+   * @class BoWFeatureConverter
+   * @brief Convert a set of features into a Bag of visual Words histogram (either by Vector Quantization, or Hard / Soft Assignment)
+   * @author Alexander Freytag
+   * @date 11-06-2013 (dd-mm-yyyy)
+  */   
+  class BoWFeatureConverter 
+  {
+
+    protected:
+      //! normalization method used (enum type)
+      int n_normalizationMethod;
+      
+      //! quantization method used (enum type)
+      int n_quantizationMethod;
+
+      //! pointer to our codebook
+      const Codebook *codebook;
+      
+      //! the section name if we want to read something from the config file lateron
+      std::string s_section;
+      
+      //! the config file to specify parameter settings
+      const NICE::Config * p_conf;
+
+
+
+    public:
+      //! enum type used for normalization method
+      enum {
+        NORMALIZE_RAW = 0,
+        NORMALIZE_BINZERO,
+        NORMALIZE_SUM,
+        NORMALIZE_THRESH
+      };
+      
+      //! enum type used to specify feature -> clusters (vector quant. , or vector assignment (either hard or soft) )
+      enum {
+        VECTOR_QUANTIZATION = 0,
+        VECTOR_ASSIGNMENT
+      };
+         
+
+      /**
+      * @brief standard constructor 
+      *
+      * @param conf pointer to a Config object with some parameter settings (currently not used)
+      * @param codebook pointer to the codebook (keep the pointer!)
+      */
+      BoWFeatureConverter( const NICE::Config *conf,
+          const Codebook *codebook, const std::string _section = "BoWFeatureConverter" );
+          
+      /** simple destructor */
+      virtual ~BoWFeatureConverter();
+      
+      void calcHistogram ( const NICE::VVector & features,
+              NICE::Vector & histogram, const bool & b_resetHistogram = true );
+
+      void normalizeHistogram ( NICE::Vector & histogram );
+
+      /**
+      * @brief set the type of the normalization method (see the enum of the class)
+      *
+      * @param normalizationMethod see enum type
+      */
+      void setNormalizationMethod ( int normalizationMethod );
+
+      /**
+      * @brief get the currently used normalization method
+      *
+      * @return see enum type
+      */
+      int getNormalizationMethod () const;
+      
+  };
+
+
+} // namespace
+
+#endif

+ 106 - 28
features/simplefeatures/Codebook.cpp

@@ -1,9 +1,8 @@
 /** 
 * @file Codebook.cpp
 * @brief feature codebook
-* @author Erik Rodner
-* @date 02/15/2008
-
+* @author Erik Rodner, Alexander Freytag
+* @date 05-06-2013 (dd-mm-yyyy ) (original: 02/15/2008)
 */
 #include <iostream>
 
@@ -14,33 +13,71 @@ using namespace OBJREC;
 using namespace std;
 using namespace NICE;
 
-void Codebook::vote ( const NICE::Vector & feature, 
-			NICE::Vector & histogram, 
-			int & codebookEntry,
-			double & weight,
-			double & distance ) const
+Codebook::Codebook ( )
+{
+  this->i_noOfNearestClustersToConsidere = 1;
+}
+
+Codebook::Codebook ( const int & _noOfNearestClustersToConsidere )
+{
+  this->i_noOfNearestClustersToConsidere = _noOfNearestClustersToConsidere;
+}
+
+Codebook::Codebook( NICE::Config * _conf, const std::string & _section)
+{
+  this->p_conf = _conf;
+  this->s_section = _section;
+  
+  this->i_noOfNearestClustersToConsidere = this->p_conf->gI( _section, "noOfNearestClustersToConsidere", 1);
+}
+
+
+Codebook::~Codebook ( )
+{
+  //NOTE the config does not need to be deleted, it is just a pointer to an external data structure  
+}
+
+void Codebook::voteVQ (const NICE::Vector &feature, NICE::Vector &histogram, int &codebookEntry, double &weight, double &distance) const
+{
+    this->voteVQ ( feature, codebookEntry, weight, distance );
+    //VQ, but we directly increase the corresponding entry without setting histogram to zero before (useful if we work on multiple images)
+    histogram[codebookEntry] += weight;  
+}
+
+void Codebook::voteVQ ( const NICE::Vector & feature, NICE::SparseVector & histogram, int &codebookEntry, double &weight, double &distance ) const
 {
-    vote ( feature, codebookEntry, weight, distance );
-    histogram[codebookEntry] += weight;
+    this->voteVQ ( feature, codebookEntry, weight, distance );
+    
+    //is this cluster already non-zero in the histogram?
+    NICE::SparseVector::iterator entryIt = histogram.find( codebookEntry ) ;
+    if ( entryIt  == histogram.end() )
+    {
+      //entry does not exist
+      histogram.insert ( histogram.begin(), pair<int, double> ( codebookEntry, weight ) );
+    }
+    else
+    {
+      //entry already exists, so we increase the weight
+      entryIt->second += weight;
+    }
 }
 
-void Codebook::vote ( const NICE::Vector & feature, SparseVector & votes ) const
+bool Codebook::allowsMultipleVoting () const
 {
-    int codebookEntry;
-    double weight;
-    double distance;
-    vote ( feature, codebookEntry, weight, distance );
-    votes.insert ( votes.begin(), pair<int, double> ( codebookEntry, weight ) );
+  if ( this->i_noOfNearestClustersToConsidere > 1 )
+    return true;
+  else
+    return false;
 }
-	
+
 void Codebook::reinit ( int numCodebookEntries )
 {
-    thresholds.resize ( numCodebookEntries );
-	thresholds.set(0.0);
-    informativeMeasure.resize ( numCodebookEntries );
-	informativeMeasure.set(0.0);
-    classnos.resize ( numCodebookEntries );
-	classnos.resize(0);
+  thresholds.resize ( numCodebookEntries );
+  thresholds.set(0.0);
+  informativeMeasure.resize ( numCodebookEntries );
+  informativeMeasure.set(0.0);
+  classnos.resize ( numCodebookEntries );
+  classnos.resize(0);
 }
 
 void Codebook::clear ()
@@ -54,20 +91,61 @@ void Codebook::restore ( istream & is, int format )
 {
    is >> thresholds;
    is >> informativeMeasure;
-   is >> classnos;
+//    is >> classnos;
+   
+   //TODO use a flag for compatibility with old systems?
+/*   try
+   {
+     
+     is >> i_noOfNearestClustersToConsidere;
+     is >> s_section;
+
+     this->p_conf->restore( is, format );
+   }
+   catch( ... )
+   {
+     std::cerr << "something went wrong while Loading the codebook - use default values instead" << std::endl;
+     //TODO use suitable default values
+   }  */ 
 }
 
 void Codebook::store ( ostream & os, int format ) const
 {
-    os << thresholds << endl;
-    os << informativeMeasure << endl;
-    os << classnos << endl;
+    os << this->thresholds << endl;
+    os << this->informativeMeasure << endl;
+    os << this->classnos << endl;
+//     os << this->i_noOfNearestClustersToConsidere << endl;
+//     os << this->s_section << endl;
+//     
+//     this->p_conf->store( os, format );
 }
 
 void Codebook::copy ( const Codebook *codebook )
 {
-    reinit ( codebook->thresholds.size() );
+    this->reinit ( codebook->thresholds.size() );
     thresholds = codebook->thresholds;
     informativeMeasure = codebook->informativeMeasure;
     classnos = codebook->classnos;
+    this->p_conf = codebook->p_conf;
+    this->setNoOfNearestClustersToConsidere ( codebook->getNoOfNearestClustersToConsidere() );
 }
+
+void Codebook::setNoOfNearestClustersToConsidere ( const int & _noOfNearestClustersToConsidere )
+{
+  this->i_noOfNearestClustersToConsidere = _noOfNearestClustersToConsidere;
+}
+
+int Codebook::getNoOfNearestClustersToConsidere ( ) const
+{
+  return this->i_noOfNearestClustersToConsidere;
+}
+
+void Codebook::setHardAssignment( const bool & _hardAssignment )
+{
+  this->b_hardAssignment = _hardAssignment;
+}
+
+bool Codebook::getHardAssignment ( ) const
+{
+  return this->b_hardAssignment;
+}

+ 160 - 64
features/simplefeatures/Codebook.h

@@ -1,83 +1,179 @@
 /**
 * @file Codebook.h
 * @brief feature codebook
-* @author Erik Rodner
-* @date 02/15/2008
-
+* @author Erik Rodner, Alexander Freytag
+* @date 05-06-2013 (dd-mm-yyyy ) (original: 02/15/2008)
 */
 #ifndef CODEBOOKINCLUDE
 #define CODEBOOKINCLUDE
 
-#include "core/vector/VectorT.h"
-#include "core/vector/MatrixT.h"
-#include "core/image/ImageT.h"
-#include "core/imagedisplay/ImageDisplay.h"
 
 #include <string>
 
+#include <core/basics/Config.h>
 #include "core/basics/Persistent.h"
+//
+#include "core/image/ImageT.h"
+#include "core/imagedisplay/ImageDisplay.h"
+//
+#include "core/vector/VectorT.h"
+#include "core/vector/MatrixT.h"
 #include "core/vector/SparseVectorT.h"
 
 
 namespace OBJREC {
 
-/** feature codebook */
-class Codebook : public NICE::Persistent
-{
-protected:
-    NICE::Vector thresholds;
-    NICE::Vector informativeMeasure;
-    NICE::VectorT<int> classnos;
-
-public:
-
-    /** simple destructor */
-    virtual ~Codebook() {};
-
-    virtual void vote ( const NICE::Vector & feature, int & codebookEntry,
-                        double & weight, double & distance ) const = 0;
-
-    virtual void vote ( const NICE::Vector & feature, NICE::Vector & histogram, int & codebookEntry,
-                        double & weight, double & distance ) const;
-
-    virtual void vote ( const NICE::Vector & feature, NICE::SparseVector & votes ) const;
-
-    virtual bool allowsMultipleVoting () {
-        return false;
-    };
-    virtual void add ( const Codebook *codebook ) = 0;
-    virtual void copy ( const Codebook *codebook );
-    virtual Codebook *clone () const = 0;
-
-    size_t getCodebookSize() const {
-        return informativeMeasure.size();
-    };
-    void reinit ( int numCodebookEntries );
-
-    const NICE::Vector & getThresholds () const {
-        return thresholds;
-    };
-    const NICE::Vector & getInformativeMeasure () const {
-        return informativeMeasure;
-    };
-    const NICE::VectorT<int> & getClassNos () const {
-        return classnos;
-    };
-
-    void setThresholds ( const NICE::Vector & _thresholds ) {
-        thresholds = _thresholds;
-    };
-    void setInformativeMeasure ( const NICE::Vector & _informativeMeasure ) {
-        informativeMeasure = _informativeMeasure;
-    };
-    void setClassNos ( const NICE::VectorT<int> & _classnos ) {
-        classnos = _classnos;
-    };
-
-    virtual void clear ();
-    virtual void restore ( std::istream & is, int format );
-    virtual void store ( std::ostream & os, int format ) const;
-};
+  /** feature codebook */
+  class Codebook : virtual public NICE::Persistent
+  {
+    protected:
+        NICE::Vector thresholds;
+        NICE::Vector informativeMeasure;
+        NICE::VectorT<int> classnos;
+        
+        /** if Soft Assignment or Hard Assignment instead of Vector Quantization, how many entries are allowed to be non-zero?*/
+        int i_noOfNearestClustersToConsidere;
+        
+        NICE::Config * p_conf;
+        std::string s_section;
+        
+        /** hard or soft assignment? */
+        bool b_hardAssignment;
+
+    public:
+
+        /**
+         * @brief simple constructor
+         */
+        Codebook ( );      
+      
+        /**
+         * @brief standard constructor
+         */
+        Codebook ( const int & _noOfNearestClustersToConsidere);
+
+         /**
+         * @brief recommended constructor
+         */
+        Codebook( NICE::Config * _conf, const std::string & _section);
+
+        /** simple destructor */
+        virtual ~Codebook();
+        
+
+        //vote for a single feature vector
+        /**
+         * @brief Vector Quantization for a single vector
+         * @date 11-06-2013 (dd-mm-yyyy)
+         * @author Erik Rodner, Alexander Freytag
+         * @param feature the feature that shall be quantized
+         * @param codebookEntry the corresponding cluster index for the quantized feature
+         * @param weight the weight of the nearest cluster
+         * @param distance the distance to its nearest cluster
+         */        
+        virtual void voteVQ ( const NICE::Vector & feature, int & codebookEntry,
+                            double & weight, double & distance ) const = 0;
+                            
+        /**
+         * @brief Vector Quantization for a single vector, directly increases the corresponding entry in histogram 
+         * @date 11-06-2013 (dd-mm-yyyy)
+         * @author Erik Rodner, Alexander Freytag
+         * @param feature the feature that shall be quantized
+         * @param histogram a BoW-histogram already given (does not need to be empty before) - the corresponding entry for feature will be increased
+         * @param codebookEntry  the corresponding cluster index for the quantized feature
+         * @param weight the weight of the nearest cluster
+         * @param distance the distance to its nearest cluster
+         */        
+        virtual void voteVQ (const NICE::Vector &feature, NICE::Vector &histogram, int & codebookEntry, double & weight, double & distance ) const; 
+        
+        /**
+         * @brief Vector Quantization for a single vector, directly increases the corresponding entry in histogram 
+         * @date 11-06-2013 (dd-mm-yyyy)
+         * @author Erik Rodner, Alexander Freytag
+         * @param feature the feature that shall be quantized
+         * @param histogram a BoW-histogram already given (does not need to be empty before) - the corresponding entry for feature will be increased
+         * @param codebookEntry the corresponding cluster index for the quantized feature
+         * @param weight the weight of the nearest cluster
+         * @param distance the distance to its nearest cluster
+         */        
+        virtual void voteVQ (const NICE::Vector &feature, NICE::SparseVector &histogram, int &codebookEntry, double &weight, double &distance ) const;         
+
+        
+        /**
+         * @brief Hard or Soft Assignment into NICE::Vector for a single vector
+         * @date 11-06-2013 (dd-mm-yyyy)
+         * @author Alexander Freytag
+         * @param feature the feature that shall be quantized
+         * @param votes BoW histogram adding non-zero entries at the k nearest clusters (hard or soft),  (does not need to be empty before)
+         */    
+        virtual void voteVA ( const NICE::Vector & feature, NICE::Vector & votes ) const = 0;
+
+        /**
+         * @brief Hard or Soft Assignment into NICE::SparseVector for a single vector 
+         * @date 11-06-2013 (dd-mm-yyyy)
+         * @author Erik Rodner, Alexander Freytag
+         * @param feature the feature that shall be quantized
+         * @param votes BoW histogram adding non-zero entries for the k nearest clusters (hard or soft),  (does not need to be empty before)
+         */                              
+        virtual void voteVA ( const NICE::Vector & feature, NICE::SparseVector & votes ) const = 0;
+        
+        
+        //for backward-compatibility
+        virtual void   vote (const NICE::Vector &feature, NICE::Vector &histogram, int &codebookEntry , double &weight , double &distance ) const { this->voteVQ ( feature, histogram, codebookEntry, weight, distance ); };
+        
+        virtual void   vote (const NICE::Vector &feature, NICE::SparseVector &histogram ) const {
+          int codebookEntry;
+          double weight, distance;
+          this->voteVQ ( feature, histogram, codebookEntry, weight, distance );          
+        };        
+   
+        
+        
+       
+        virtual void add ( const Codebook *codebook ) = 0;
+        virtual void copy ( const Codebook *codebook );
+        virtual Codebook *clone () const = 0;
+
+        size_t getCodebookSize() const {
+            return informativeMeasure.size();
+        };
+        void reinit ( int numCodebookEntries );
+
+        const NICE::Vector & getThresholds () const {
+            return thresholds;
+        };
+        const NICE::Vector & getInformativeMeasure () const {
+            return informativeMeasure;
+        };
+        const NICE::VectorT<int> & getClassNos () const {
+            return classnos;
+        };
+
+        void setThresholds ( const NICE::Vector & _thresholds ) {
+            thresholds = _thresholds;
+        };
+        void setInformativeMeasure ( const NICE::Vector & _informativeMeasure ) {
+            informativeMeasure = _informativeMeasure;
+        };
+        void setClassNos ( const NICE::VectorT<int> & _classnos ) {
+            classnos = _classnos;
+        };
+        
+        void setHardAssignment( const bool & _hardAssignment );
+        bool getHardAssignment ( ) const ;
+        
+        /** 
+         * @brief false, if only a single entry for soft or hard assignment can be larger than zero (=> effectively vector quantization)
+         */
+        virtual bool allowsMultipleVoting () const ;
+        
+        void setNoOfNearestClustersToConsidere ( const int & _noOfNearestClustersToConsidere );
+        int getNoOfNearestClustersToConsidere ( ) const ;
+
+        virtual void clear ();
+        virtual void restore ( std::istream & is, int format );
+        virtual void store ( std::ostream & os, int format ) const;
+  };
 
 
 } // namespace

+ 107 - 59
features/simplefeatures/CodebookPrototypes.cpp

@@ -1,15 +1,16 @@
 /** 
 * @file CodebookPrototypes.cpp
 * @brief feature CodebookPrototypes
-* @author Erik Rodner
-* @date 02/15/2008
-
+* @author Erik Rodner, Alexander Freytag
+* @date 05-06-2013 (dd-mm-yyyy ) (original: 02/15/2008)
 */
-#include <core/image/Convert.h>
-
 #include <iostream>
 #include <assert.h>
 
+#include <core/image/Convert.h>
+
+#include "vislearning/math/distances/genericDistance.h"
+
 #include "CodebookPrototypes.h"
 
 using namespace OBJREC;
@@ -20,6 +21,9 @@ using namespace NICE;
 
 CodebookPrototypes::CodebookPrototypes()
 {
+  this->clear();
+  this->distanceType = "euclidean";
+  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);   
 }
 
 CodebookPrototypes::CodebookPrototypes( const std::string & filename )
@@ -27,15 +31,27 @@ CodebookPrototypes::CodebookPrototypes( const std::string & filename )
     Codebook::read(filename);
 }
 
-CodebookPrototypes::CodebookPrototypes( const VVector & vv )
+CodebookPrototypes::CodebookPrototypes( const NICE::VVector & vv )
 {
-    for ( const_iterator i = vv.begin(); i != vv.end(); i++ )
-	push_back (*i);
-    reinit ( vv.size() );
+  this->append ( vv, true /* _copyData*/ ); 
+
+  reinit ( vv.size() );
+  
+  this->distanceType = "euclidean";
+  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);     
+}
+
+CodebookPrototypes::CodebookPrototypes( NICE::Config * _conf, const std::string & _section) : Codebook ( _conf, _section )
+{    
+  this->distanceType = _conf->gS( _section, "distanceType", "euclidean" );
+  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);  
+  
+  this->clear();
 }
 
 CodebookPrototypes::~CodebookPrototypes()
 {
+  //NOTE the config does not need to be deleted, it is just a pointer to an external data structure
 }
 
 void CodebookPrototypes::copy ( const Codebook *codebook )
@@ -45,9 +61,12 @@ void CodebookPrototypes::copy ( const Codebook *codebook )
     const CodebookPrototypes *codebookp = dynamic_cast<const CodebookPrototypes *> ( codebook );
     assert ( codebookp != NULL );
     insert ( begin(), codebookp->begin(), codebookp->end() );
+    
+  this->distanceType = this->p_conf->gS( this->s_section, "distanceType", "euclidean" );
+  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);      
 }
 
-void CodebookPrototypes::vote ( const NICE::Vector & feature, int & codebookEntry, double & weight, double & distance ) const
+void CodebookPrototypes::voteVQ ( const NICE::Vector & feature, int & codebookEntry, double & weight, double & distance ) const
 {
     const double *xp = feature.getDataPointer();
     size_t k = 0;
@@ -55,34 +74,50 @@ void CodebookPrototypes::vote ( const NICE::Vector & feature, int & codebookEntr
     size_t my_cluster = 0;
     
     int len = feature.size();
-    for ( vector<Vector>::const_iterator i = begin();
-					 i != end();
-					 i++,k++ )
+    // iterate over all cluster centers
+    for ( std::vector<NICE::Vector>::const_iterator i = this->begin();
+            i != this->end();
+            i++,k++ )
     {
 
-	const NICE::Vector & cluster = *i;
-	//slow ICE variant
-	//double distance = (x - cluster).Length();
-	double distance = 0.0;
-	const double *clusterp = cluster.getDataPointer();
-	for ( int i = 0 ; i < len ; i++ )
-	{
-	    double h = clusterp[i] - xp[i];
-	    distance += h*h;
-	}
-
-	if ( distance < mindist )
-	{
-	    my_cluster = k;
-	    mindist = distance;
-	}
+      const NICE::Vector & cluster = *i;
+      //slow ICE variant
+      //double distance = (x - cluster).Length();
+      
+//       const double *clusterp = cluster.getDataPointer();
+      double distance = this->distancefunction->calculate(*i, feature);
+      
+      //old version without distance function
+//       for ( int i = 0 ; i < len ; i++ )
+//       {
+//           double h = clusterp[i] - xp[i];
+//           distance += h*h;
+//       }
+
+      if ( distance < mindist )
+      {
+          my_cluster = k;
+          mindist = distance;
+      }
     }
 
     codebookEntry = my_cluster;
     weight = 1.0;
     distance = mindist;
 }
-	
+
+void CodebookPrototypes::voteVA ( const NICE::Vector & feature, NICE::Vector & votes ) const
+{
+  votes.set( 0.0 );
+  //TODO
+}
+
+void CodebookPrototypes::voteVA ( const NICE::Vector & feature, NICE::SparseVector & votes ) const
+{
+  votes.clear(); 
+  //TODO
+}
+
 void CodebookPrototypes::add ( const Codebook *codebook )
 {
     informativeMeasure.append ( codebook->getInformativeMeasure() );
@@ -93,9 +128,10 @@ void CodebookPrototypes::add ( const Codebook *codebook )
     assert ( codebookp != NULL );
     insert ( begin(), codebookp->begin(), codebookp->end() );
 }
-	
+
 Codebook *CodebookPrototypes::clone () const
 {
+  //TODO !
     return (new CodebookPrototypes());
 }
 
@@ -109,6 +145,8 @@ void CodebookPrototypes::restore ( istream & is, int format )
 {
     Codebook::restore ( is, format );
     VVector::restore ( is, format );
+    
+    std::cerr << "initial Codebook : " << std::endl; VVector::print ( std::cerr );
 }
 
 void CodebookPrototypes::store ( ostream & os, int format ) const
@@ -119,47 +157,57 @@ void CodebookPrototypes::store ( ostream & os, int format ) const
 
 void CodebookPrototypes::displayCodebook ( int xsize, int ysize ) const
 {
-    NICE::Image bigimg ( xsize * 5 , ysize * size() );
+    NICE::Image bigimg ( xsize * 5 , ysize * this->size() );
     bigimg.set(0);
 
     NICE::Image img_s (xsize, ysize);
-    for ( int k = 0 ; k < (int)size() ; k++ )
+    for ( int k = 0 ; k < (int)this->size() ; k++ )
     {
-	NICE::Vector vimg = *(begin() + k);
+	NICE::Vector vimg = *(this->begin() + k);
 	NICE::Image img ((int)sqrt((double)vimg.size()), (int)sqrt((double)vimg.size()));
 	int i = 0;
 	double max = - numeric_limits<double>::max();
 	double min = numeric_limits<double>::min();
 	for ( int y = 0 ; y < img.height() ; y++ )
+	{
 	    for ( int x = 0 ; x < img.width() ; x++,i++ )
 	    {
-		if ( max < vimg[i] ) max = vimg[i];
-		if ( min > vimg[i] ) min = vimg[i];
-	    }
-
-	i = 0;
-	for ( int y = 0 ; y < img.height() ; y++ )
-	    for ( int x = 0 ; x < img.width() ; x++,i++ )
-	    {
-		img.setPixel( x, y, (int)((vimg[i] - min)*255/(max-min)) );
+		if ( max < vimg[i] ) 
+		  max = vimg[i];
+		if ( min > vimg[i] ) 
+		  min = vimg[i];
 	    }
-
-	
-	NICE::scale ( img, &img_s );
-
-	for ( int y = 0 ; y < ysize ; y++ )
-	    for ( int x = 0 ; x < xsize ; x++ )
-		bigimg.setPixel(x, y+k*ysize, img_s.getPixel(x,y) );
-
-	{
-	    std::ostringstream os;
-	    os << "no: " << k;
-	    if ( (int)informativeMeasure.size() > k ) 
-		os << " " << informativeMeasure[k];
-	    // refactor-nice.pl: check this substitution
-	    // old: Text ( os.str().c_str(), xsize+1, k*ysize + 1, 255, 0, bigimg );
-	    // REFACTOR-FIXME Unable to map this statement
 	}
+
+      i = 0;
+      for ( int y = 0 ; y < img.height() ; y++ )
+      {
+          for ( int x = 0 ; x < img.width() ; x++,i++ )
+          {
+            img.setPixel( x, y, (int)((vimg[i] - min)*255/(max-min)) );
+          }
+      }
+
+      
+      NICE::scale ( img, &img_s );
+
+      for ( int y = 0 ; y < ysize ; y++ )
+      {
+          for ( int x = 0 ; x < xsize ; x++ )
+          {
+            bigimg.setPixel(x, y+k*ysize, img_s.getPixel(x,y) );
+          }
+      }
+
+      {
+          std::ostringstream os;
+          os << "no: " << k;
+          if ( (int)informativeMeasure.size() > k ) 
+          os << " " << informativeMeasure[k];
+          // refactor-nice.pl: check this substitution
+          // old: Text ( os.str().c_str(), xsize+1, k*ysize + 1, 255, 0, bigimg );
+          // REFACTOR-FIXME Unable to map this statement
+      }
     }
 
     bigimg.write ("/tmp/display.bmp");

+ 60 - 31
features/simplefeatures/CodebookPrototypes.h

@@ -1,9 +1,8 @@
 /** 
 * @file CodebookPrototypes.h
 * @brief feature CodebookPrototypes
-* @author Erik Rodner
-* @date 02/15/2008
-
+* @author Erik Rodner, Alexander Freytag
+* @date 05-06-2013 (dd-mm-yyyy ) (original: 02/15/2008)
 */
 #ifndef CodebookPrototypesINCLUDE
 #define CodebookPrototypesINCLUDE
@@ -15,42 +14,72 @@
 #include <string>
 
 #include "core/vector/VVector.h"
+#include <core/vector/Distance.h>
+
 #include "Codebook.h"
 
 
 namespace OBJREC {
 
-/** feature CodebookPrototypes */
-class CodebookPrototypes : public Codebook, public NICE::VVector
-{
-
-    protected:
-
-    public:
-  
-	/** simple constructor */
-	CodebookPrototypes();
-	
-	CodebookPrototypes( const std::string & filename );
-	
-	CodebookPrototypes( const NICE::VVector & vv );
-	
-	CodebookPrototypes( const CodebookPrototypes *cs );
-      
-	/** simple destructor */
-	virtual ~CodebookPrototypes();
+  /** feature CodebookPrototypes */
+  class CodebookPrototypes : public Codebook, public NICE::VVector
+  {
+
+      protected:
+        
+        //! specify which distance to use for calculating assignments
+        std::string distanceType;
+        
+        //! the actual distance metric
+        NICE::VectorDistance<double> *distancefunction;         
+
+      public:
     
-	void vote ( const NICE::Vector & feature, int & codebookEntry, double & weight, double & distance ) const;
-	void add ( const Codebook *codebook );
-	void copy ( const Codebook *codebook );
-	Codebook *clone () const;
+        /** simple constructor */
+        CodebookPrototypes();
+        
+        /** constructor reading the codebook from a file*/
+        CodebookPrototypes( const std::string & filename );
+        
+        /** constructor taking the given VVector as new codebook prototypes*/
+        CodebookPrototypes( const NICE::VVector & vv );
+        
+        /** copy constructor*/
+        CodebookPrototypes( const CodebookPrototypes *cs );
+        
+        /** recommended constructor*/
+        CodebookPrototypes( NICE::Config * _conf, const std::string & _section);
+            
+        /** simple destructor */
+        virtual ~CodebookPrototypes();
+        
+        //vote for a single feature vector
+        /**
+         * @brief Vector Quantization for a single vector
+         */        
+        void voteVQ ( const NICE::Vector & feature, int & codebookEntry, double & weight, double & distance ) const;
+
+        /**
+         * @brief Hard or Soft Assignment into NICE::Vector for a single vector
+         */        
+        virtual void voteVA ( const NICE::Vector & feature, NICE::Vector & votes ) const;
+
+        /**
+         * @brief Hard or Soft Assignment into NICE::SparseVector for a single vector
+         */                            
+        virtual void voteVA ( const NICE::Vector & feature, NICE::SparseVector & votes ) const;        
+         
+        
+        void add ( const Codebook *codebook );
+        void copy ( const Codebook *codebook );
+        Codebook *clone () const;
 
-	void clear ();
-	void restore ( std::istream & is, int format );
-	void store ( std::ostream & os, int format ) const;
+        void clear ();
+        void restore ( std::istream & is, int format );
+        void store ( std::ostream & os, int format ) const;
 
-	void displayCodebook (int xsize, int ysize) const;
-};
+        void displayCodebook (int xsize, int ysize) const;
+  };
 
 
 } // namespace

+ 20 - 20
math/cluster/ClusterAlgorithm.h

@@ -16,27 +16,27 @@
 
 namespace OBJREC {
 
-/** Interface for Cluster-Algorithms */
-class ClusterAlgorithm
-{
-
-    protected:
-
-    public:
-  
-	/** simple constructor */
-	ClusterAlgorithm();
+  /** Interface for Cluster-Algorithms */
+  class ClusterAlgorithm
+  {
+
+      protected:
+
+      public:
+    
+    /** simple constructor */
+    ClusterAlgorithm();
+        
+    /** simple destructor */
+    virtual ~ClusterAlgorithm();
+
+    virtual void cluster ( 
+            const NICE::VVector & features,
+            NICE::VVector & prototypes,
+            std::vector<double> & weights,
+            std::vector<int>    & assignment ) = 0;
       
-	/** simple destructor */
-	virtual ~ClusterAlgorithm();
-
-	virtual void cluster ( 
-		       const NICE::VVector & features,
-		       NICE::VVector & prototypes,
-		       std::vector<double> & weights,
-		       std::vector<int>    & assignment ) = 0;
-     
-};
+  };
 
 
 } // namespace

+ 6 - 6
math/cluster/GMM.cpp

@@ -9,7 +9,7 @@
 
 #include "vislearning/math/cluster/KMeans.h"
 
-#define DEBUGGMM
+// #define DEBUGGMM
 
 using namespace OBJREC;
 using namespace NICE;
@@ -175,16 +175,16 @@ inline NICE::Vector diagInverse ( const NICE::Vector &sparse_mat )
 void GMM::initEMkMeans ( const VVector &DataSet )
 {
   /*init GMM with k-Means*/
-  KMeans k ( gaussians );
-  VVector means;
-  vector<double> weights;
-  vector<int> assignment;
+  OBJREC::KMeans k ( gaussians );
+  NICE::VVector means;
+  std::vector<double> weights;
+  std::vector<int> assignment;
   k.cluster ( DataSet, means, weights, assignment );
 
   int nData = DataSet.size();
   this->dim = DataSet[0].size();
   cdimval = dim * log ( 2 * 3.14159 );
-  vector<int> pop ( gaussians, 0 );
+  std::vector<int> pop ( gaussians, 0 );
   priors.resize ( gaussians );
   mu = VVector ( gaussians, dim );
   log_det_sigma.clear();

+ 0 - 1
math/cluster/GMM.h

@@ -104,7 +104,6 @@ class GMM : public ClusterAlgorithm
      * standard destructor
      */
     ~GMM() {
-      std::cerr << "dadada" << std::endl;
     };
 
     /**

+ 15 - 13
math/cluster/GSCluster.cpp

@@ -23,23 +23,25 @@ using namespace NICE;
 
 
 
-GSCluster::GSCluster( const Config *conf ) : GenerateSignature ( conf )
+GSCluster::GSCluster( const Config *conf, const std::string & _section ) : GenerateSignature ( conf )
 {
-    c_no_clusters = conf->gI("GSCluster", "clusters", 20);
-    // refactor-nice.pl: check this substitution
-    // old: string cluster_method = conf->gS("GSCluster", "cluster_method", "kmeans");
     std::string cluster_method = conf->gS("GSCluster", "cluster_method", "kmeans");
     if ( cluster_method == "kmeans" )
     {
-	clualg = new KMeans ( c_no_clusters );
-    } else if ( cluster_method == "spectral" ) {
-	double alpha = conf->gD("GSCluster", "spectral_alpha", 1.0);
-	clualg = new SpectralCluster ( c_no_clusters, alpha );
-    } else if ( cluster_method == "kmeans_matlab" ) {
-	clualg = new KMeansMatlab ( conf, c_no_clusters );
-    } else {
-	fprintf (stderr, "FATAL ERROR GSCluster: cluster method %s unknown !\n", cluster_method.c_str());
-	exit(-1);
+      clualg = new OBJREC::KMeans ( conf );
+    }
+    else if ( cluster_method == "spectral" )
+    {
+      clualg = new SpectralCluster ( conf );
+    }
+    else if ( cluster_method == "kmeans_matlab" )
+    {
+      clualg = new KMeansMatlab ( conf );
+    }
+    else
+    {
+      fprintf (stderr, "FATAL ERROR GSCluster: cluster method %s unknown !\n", cluster_method.c_str());
+      exit(-1);
     }
 }
 

+ 25 - 16
math/cluster/GSCluster.h

@@ -17,26 +17,35 @@
 
 namespace OBJREC {
 
-/** Generate Signature by Clustering Local Features */
-class GSCluster : public GenerateSignature
-{
+    /** 
+     * @class GSCluster
+     * @brief Generate Signature by Clustering Local Features (image-specific codebook!).
+     * The class can be used for the EMD kernel, but not for usual BoV approaches.
+     * @author Erik Rodner
+     */
+    class GSCluster : public GenerateSignature
+    {
 
-    protected:
-	int c_no_clusters;
+        protected:
+          int c_no_clusters;
 
-	ClusterAlgorithm *clualg;
+          ClusterAlgorithm *clualg;
 
-    public:
-  
-	/** simple constructor */
-	GSCluster( const NICE::Config *conf );
+        public:
       
-	/** simple destructor */
-	virtual ~GSCluster();
-     
-	void signature ( const NICE::VVector & features,
-			 NICE::Vector & signature );
-};
+          /** standard  constructor
+           * @param conf config file specifying all relevant variable settings.  You should specify in "section" the string "cluster_method"
+           * @param _section name of the section within the configfile where the settings can be found. Default: GSCluster
+           * @param[in] 
+           */
+          GSCluster( const NICE::Config *conf, const std::string & _section = "GSCluster" );
+              
+          /** simple destructor */
+          virtual ~GSCluster();
+            
+          void signature ( const NICE::VVector & features,
+              NICE::Vector & signature );
+    };
 
 
 } // namespace

+ 94 - 0
math/cluster/GenericClusterAlgorithmSelection.h

@@ -0,0 +1,94 @@
+/** 
+* @file GenericClusterAlgorithmSelection.h
+* @brief This class provides a generic chooser function for different clustering techniques
+* @date 14-06-2013 (dd-mm-yyyy)
+* @author Alexander Freytag
+*/
+
+#ifndef _NICE_GENERICCLUSTERALGORITHMSELECTION_INCLUDE
+#define _NICE_GENERICCLUSTERALGORITHMSELECTION_INCLUDE
+
+#include <iostream>
+
+//abstract base class
+#include "vislearning/math/cluster/ClusterAlgorithm.h"
+//derived specializations
+#include "vislearning/math/cluster/GMM.h"
+#include "vislearning/math/cluster/KMeans.h"
+#include "vislearning/math/cluster/KMeansHeuristic.h"
+#include "vislearning/math/cluster/KMeansMatlab.h"
+#include "vislearning/math/cluster/KMedian.h"
+#include "vislearning/math/cluster/RandomClustering.h"
+#include "vislearning/math/cluster/SpectralCluster.h"
+
+namespace OBJREC {
+
+  /** @class GenericClusterAlgorithmSelection
+  * @brief This class provides a generic chooser function for different clustering techniques
+  * The abstract base class is ClusterAlgorithm
+  * @date 14-06-2013 (dd-mm-yyyy)
+  * @author Alexander Freytag
+  */
+  class GenericClusterAlgorithmSelection
+  {
+      public:
+
+        /** 
+        * @brief This methode switches between the different clustering techniques. 
+        * @param[in] conf - A pointer to the given configfile, which should contain "section" - "clusterTechnique"
+        * @param[in] section - This string defines the value for "section" in the configfile.
+        * @return ClusterAlgorithm* - The ClusterAlgorithm to cluster samples according to the selected clustering technique.
+        * @date 14-06-2013 (dd-mm-yyyy)
+        * @author Alexander Freytag
+        */
+        static
+        OBJREC::ClusterAlgorithm *selectClusterAlgo ( const NICE::Config *conf, std::string section = "clustering" )
+        {
+          // return value
+          OBJREC::ClusterAlgorithm *clusterAlgo = NULL;
+        
+          // string which defines the clustering technique
+          std::string clusterTechnique = conf->gS(section, "clusterTechnique", "");
+                  
+          if ( clusterTechnique == "kmeans" )
+          {
+            clusterAlgo = new OBJREC::KMeans ( conf );
+          }        
+          else if ( clusterTechnique == "kmeansHeuristic" )
+          {
+            clusterAlgo = new OBJREC::KMeansHeuristic ( conf );
+          }   
+          else if ( clusterTechnique == "kmeansMatlab" )
+          {
+            clusterAlgo = new OBJREC::KMeansMatlab ( conf );
+          }            
+          else if ( clusterTechnique == "kmedian" )
+          {
+            clusterAlgo = new OBJREC::KMedian ( conf );
+          }     
+          else if ( clusterTechnique == "GMM" )
+          {
+            clusterAlgo = new OBJREC::GMM ( conf );
+          } 
+          else if ( clusterTechnique == "spectral" )
+          {
+            clusterAlgo = new OBJREC::SpectralCluster ( conf );
+          }           
+          else if ( clusterTechnique == "RandomClustering" )
+          {
+            clusterAlgo = new OBJREC::RandomClustering ( conf );
+          }            
+          else 
+          {
+            //default: random clustering - it is easy, fast, does not need extra memory, and is still better than a NULL pointer
+            std::cerr << "Unknown cluster algorithm selected, use random clustering instead" << std::endl;
+            clusterAlgo = new OBJREC::RandomClustering ( conf );
+          }
+            
+          return clusterAlgo;
+        }
+  };
+
+}
+
+#endif

+ 256 - 241
math/cluster/KMeans.cpp

@@ -1,9 +1,8 @@
 /**
  * @file KMeans.cpp
  * @brief K-Means
- * @author Erik Rodner
- * @date 10/29/2007
-
+ * @author Erik Rodner, Alexander Freytag
+ * @date 29-10-2007 (dd-mm-yyyy)
  */
 
 #include <iostream>
@@ -21,277 +20,293 @@ using namespace NICE;
 
 #undef DEBUG_KMEANS
 
-KMeans::KMeans(int _noClasses, string _distanceType) :
-	noClasses(_noClasses), distanceType(_distanceType)
+KMeans::KMeans(const int & _noClasses, const std::string & _distanceType) :
+        noClasses(_noClasses), distanceType(_distanceType)
 {
-	//srand(time(NULL));
-	distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+    //srand(time(NULL));
+    this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+}
+
+KMeans::KMeans( const NICE::Config *conf, const std::string & _section)
+{       
+  this->distanceType = conf->gS( _section, "distanceType", "euclidean" );
+  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+  
+  this->d_minDelta  = conf->gD( _section, "minDelta", 1e-5 );
+  this->i_maxIterations = conf->gI( _section, "maxIterations", 200);
+  
+  this->noClasses = conf->gI( _section, "noClasses", 20);
 }
 
 KMeans::~KMeans()
 {
 }
 
-void KMeans::initial_guess(const VVector & features, VVector & prototypes)
+void KMeans::initial_guess(const NICE::VVector & features, NICE::VVector & prototypes)
 {
-	int j = 0;
-	std::set<int, std::greater<int> > mark;
+    int j = 0;
+    std::set<int, std::greater<int> > mark;
 
-	for (VVector::iterator i = prototypes.begin(); i != prototypes.end(); i++, j++)
-	{
-		int k;
+    for (VVector::iterator i = prototypes.begin(); i != prototypes.end(); i++, j++)
+    {
+        int k;
 
-		do
-		{
-			k = rand() % features.size();
-		} while (mark.find(k) != mark.end());
+        do
+        {
+            k = rand() % features.size();
+        } while (mark.find(k) != mark.end());
 
-		mark.insert(mark.begin(), k);
+        mark.insert(mark.begin(), k);
 
-		*i = features[k];
-	}
+        *i = features[k];
+    }
 }
 
 int KMeans::compute_prototypes(const VVector & features, VVector & prototypes,
-		std::vector<double> & weights, const std::vector<int> & assignment)
+                               std::vector<double> & weights, const std::vector<int> & assignment)
 {
-	int j = 0;
-	// fprintf (stderr, "KMeans::compute_prototypes: init noClasses=%d\n", noClasses);
-	for (int k = 0; k < noClasses; k++)
-	{
-		prototypes[k].set(0);
-		weights[k] = 0;
-	}
-
-	// fprintf (stderr, "KMeans::compute_prototypes: compute means\n");
-	for (VVector::const_iterator i = features.begin(); i != features.end(); i++, j++)
-	{
-		int k = assignment[j];
-
-		NICE::Vector & p = prototypes[k];
-
-		const NICE::Vector & x = *i;
-
-#ifdef DEBUG_KMEANS
-
-		fprintf(
-				stderr,
-				"KMeans::compute_prototypes: std::vector %d has assignment %d\n",
-				j, k);
-#endif
-
-		p += x;
-
-#ifdef DEBUG_KMEANS
-		cerr << "vector was : " << x << endl;
-		cerr << "prototype for this class is now : " << p << endl;
-#endif
-		weights[k]++;
-	}
-
-	// fprintf (stderr, "KMeans::compute_prototypes: scaling\n");
-	for (int k = 0; k < noClasses; k++)
-	{
-
-		NICE::Vector & p = prototypes[k];
-
-#ifdef DEBUG_KMEANS
-		cerr << "prototype for this class before scaling : " << p << endl;
-#endif
-
-		if (weights[k] <= 0)
-		{
-			return -1;
-		}
-
-		p *= (1.0 / weights[k]);
-
-		weights[k] = weights[k] / features.size();
-
-#ifdef DEBUG_KMEANS
-		cerr << "prototype for this class after scaling with " << weights[k]
-				<< " : " << p << endl;
-#endif
-	}
-
-	return 0;
+    int j = 0;
+    // fprintf (stderr, "KMeans::compute_prototypes: init noClasses=%d\n", noClasses);
+    for (int k = 0; k < this->noClasses; k++)
+    {
+        prototypes[k].set(0);
+        weights[k] = 0;
+    }
+
+    // fprintf (stderr, "KMeans::compute_prototypes: compute means\n");
+    for (VVector::const_iterator i = features.begin(); i != features.end(); i++, j++)
+    {
+        int k = assignment[j];
+
+        NICE::Vector & p = prototypes[k];
+
+        const NICE::Vector & x = *i;
+
+        #ifdef DEBUG_KMEANS
+          fprintf(
+              stderr,
+              "KMeans::compute_prototypes: std::vector %d has assignment %d\n",
+              j, k);
+        #endif
+
+        p += x;
+
+        #ifdef DEBUG_KMEANS
+          std::cerr << "vector was : " << x << std::endl;
+          std::cerr << "prototype for this class is now : " << p << std::endl;
+        #endif
+          
+        weights[k]++;
+    }
+
+    // fprintf (stderr, "KMeans::compute_prototypes: scaling\n");
+    for (int k = 0; k < this->noClasses; k++)
+    {
+
+        NICE::Vector & p = prototypes[k];
+
+        #ifdef DEBUG_KMEANS
+          std::cerr << "prototype for this class before scaling : " << p << std::endl;
+        #endif
+
+        if (weights[k] <= 0)
+        {
+            return -1;
+        }
+
+        p *= (1.0 / weights[k]);
+
+        weights[k] = weights[k] / features.size();
+
+        #ifdef DEBUG_KMEANS
+          std::cerr << "prototype for this class after scaling with " << weights[k]
+             << " : " << p << std::endl;
+        #endif
+    }
+
+    return 0;
 }
 
-double KMeans::compute_delta(const VVector & oldprototypes,
-		const VVector & prototypes)
+double KMeans::compute_delta(const NICE::VVector & oldprototypes,
+                             const NICE::VVector & prototypes)
 {
-	double distance = 0;
-
-	for (uint k = 0; k < oldprototypes.size(); k++)
-	{
-		distance
-				+= distancefunction->calculate(oldprototypes[k], prototypes[k]);
-#ifdef DEBUG_KMEANS
-	fprintf(stderr, "KMeans::compute_delta: Distance:",
-			distancefunction->calculate(oldprototypes[k], prototypes[k]));
-#endif
-	}
-	return distance;
+    double distance = 0;
+
+    for (uint k = 0; k < oldprototypes.size(); k++)
+    {
+        distance += this->distancefunction->calculate(oldprototypes[k], prototypes[k]);
+        
+        #ifdef DEBUG_KMEANS
+          fprintf(stderr, "KMeans::compute_delta: Distance: %f",
+                distancefunction->calculate(oldprototypes[k], prototypes[k]));
+        #endif
+    }
+    return distance;
 }
 
-double KMeans::compute_assignments(const VVector & features,
-		const VVector & prototypes, std::vector<int> & assignment)
+double KMeans::compute_assignments(const NICE::VVector & features,
+                                   const NICE::VVector & prototypes, std::vector<int> & assignment)
 {
-	int index = 0;
-	for (VVector::const_iterator i = features.begin(); i != features.end(); i++, index++)
-	{
-
-		const NICE::Vector & x = *i;
-		double mindist = std::numeric_limits<double>::max();
-		int minclass = 0;
-
-		int c = 0;
-#ifdef DEBUG_KMEANS
-
-		fprintf(stderr, "computing nearest prototype for std::vector %d\n",
-				index);
-#endif
-		for (VVector::const_iterator j = prototypes.begin(); j
-				!= prototypes.end(); j++, c++)
-		{
-
-			const NICE::Vector & p = *j;
-			double distance = distancefunction->calculate(p, x);
-#ifdef DEBUG_KMEANS
-	fprintf(stderr, "KMeans::compute_delta: Distance:",
-			distancefunction->calculate(p, x));
-#endif
-
-#ifdef DEBUG_KMEANS
-			cerr << p << endl;
-			cerr << x << endl;
-			fprintf(stderr, "distance to prototype %d is %f\n", c, distance);
-#endif
-
-			if (distance < mindist)
-			{
-				minclass = c;
-				mindist = distance;
-			}
-		}
-
-		assignment[index] = minclass;
-	}
-
-	return 0.0;
+    int index = 0;
+    for (VVector::const_iterator i = features.begin(); i != features.end(); i++, index++)
+    {
+
+        const NICE::Vector & x = *i;
+        double mindist = std::numeric_limits<double>::max();
+        int minclass = 0;
+
+        int c = 0;
+        #ifdef DEBUG_KMEANS
+
+          fprintf(stderr, "computing nearest prototype for std::vector %d\n",
+                index);
+        #endif
+        for (VVector::const_iterator j = prototypes.begin(); j
+                != prototypes.end(); j++, c++)
+        {
+
+            const NICE::Vector & p = *j;
+            double distance = this->distancefunction->calculate(p, x);
+            #ifdef DEBUG_KMEANS
+              fprintf(stderr, "KMeans::compute_delta: Distance: %f",
+                    this->distancefunction->calculate(p, x));
+            #endif
+
+            #ifdef DEBUG_KMEANS
+              std::cerr << p << std::endl;
+              std::cerr << x << std::endl;
+              fprintf(stderr, "distance to prototype %d is %f\n", c, distance);
+            #endif
+
+            if (distance < mindist)
+            {
+                minclass = c;
+                mindist = distance;
+            }
+        }
+
+        assignment[index] = minclass;
+    }
+
+    return 0.0;
 }
 
-double KMeans::compute_weights(const VVector & features,
-		std::vector<double> & weights, std::vector<int> & assignment)
+double KMeans::compute_weights(const NICE::VVector & features,
+                               std::vector<double> & weights, std::vector<int> & assignment)
 {
-	for (int k = 0; k < noClasses; k++)
-		weights[k] = 0;
+    for (int k = 0; k < this->noClasses; k++)
+        weights[k] = 0;
 
-	int j = 0;
+    int j = 0;
 
-	for (VVector::const_iterator i = features.begin(); i != features.end(); i++, j++)
-	{
-		int k = assignment[j];
-		weights[k]++;
-	}
+    for (NICE::VVector::const_iterator i = features.begin(); i != features.end(); i++, j++)
+    {
+        int k = assignment[j];
+        weights[k]++;
+    }
 
-	for (int k = 0; k < noClasses; k++)
-		weights[k] = weights[k] / features.size();
+    for (int k = 0; k < this->noClasses; k++)
+        weights[k] = weights[k] / features.size();
 
-	return 0.0;
+    return 0.0;
 }
 
-void KMeans::cluster(const VVector & features, VVector & prototypes,
-		std::vector<double> & weights, std::vector<int> & assignment)
+void KMeans::cluster(const NICE::VVector & features, NICE::VVector & prototypes,
+                     std::vector<double> & weights, std::vector<int> & assignment)
 {
-	VVector oldprototypes;
-
-	prototypes.clear();
-	weights.clear();
-	assignment.clear();
-	weights.resize(noClasses, 0);
-	assignment.resize(features.size(), 0);
-
-	int dimension;
-
-	if ((int) features.size() >= noClasses)
-		dimension = features[0].size();
-	else
-	{
-		fprintf(stderr,
-				"FATAL ERROR: Not enough feature vectors provided for kMeans\n");
-		exit(-1);
-	}
-
-	for (int k = 0; k < noClasses; k++)
-	{
-		prototypes.push_back(Vector(dimension));
-		prototypes[k].set(0);
-	}
-
-	KMeans_Restart:
-
-	initial_guess(features, prototypes);
-
-	int iterations = 0;
-	double delta = std::numeric_limits<double>::max();
-	const double minDelta = 1e-5;
-	const int maxIterations = 200;
-
-	do
-	{
-		iterations++;
-		compute_assignments(features, prototypes, assignment);
-
-		if (iterations > 1)
-			oldprototypes = prototypes;
-
-#ifdef DEBUG_KMEANS
-		fprintf(stderr, "KMeans::cluster compute_prototypes\n");
-
-#endif
-		if (compute_prototypes(features, prototypes, weights, assignment) < 0)
-		{
-			fprintf(stderr, "KMeans::cluster restart\n");
-			goto KMeans_Restart;
-		}
-
-#ifdef DEBUG_KMEANS
-		fprintf(stderr, "KMeans::cluster compute_delta\n");
-
-#endif
-		if (iterations > 1)
-			delta = compute_delta(oldprototypes, prototypes);
-
-#ifdef DEBUG_KMEANS
-		print_iteration(iterations, prototypes, delta);
-
-#endif
-
-	} while ((delta > minDelta) && (iterations < maxIterations));
-
-#ifdef DEBUG_KMEANS
-	fprintf(stderr, "KMeans::cluster: iterations = %d, delta = %f\n",
-			iterations, delta);
-
-#endif
-
-	compute_weights(features, weights, assignment);
+  NICE::VVector oldprototypes;
+
+  prototypes.clear();
+  weights.clear();
+  assignment.clear();
+  weights.resize(noClasses, 0);
+  assignment.resize(features.size(), 0);
+
+  int dimension;
+
+  if ((int) features.size() >= this->noClasses)
+      dimension = features[0].size();
+  else
+  {
+      fprintf(stderr,
+              "FATAL ERROR: Not enough feature vectors provided for kMeans\n");
+      exit(-1);
+  }
+
+  for (int k = 0; k < this->noClasses; k++)
+  {
+      prototypes.push_back(Vector(dimension));
+      prototypes[k].set(0);
+  }
+
+  bool successKMeans ( false );
+  int iterations ( 0 );
+  double delta ( std::numeric_limits<double>::max() );
+  
+  while ( !successKMeans )
+  {
+    //we assume that this run will be successful
+    successKMeans = true;  
+
+    this->initial_guess(features, prototypes);
+    
+    iterations = 0;
+    delta =  std::numeric_limits<double>::max();    
+
+    do
+    {
+        iterations++;
+        this->compute_assignments(features, prototypes, assignment);
+
+        if (iterations > 1)
+            oldprototypes = prototypes;
+
+        #ifdef DEBUG_KMEANS
+        fprintf(stderr, "KMeans::cluster compute_prototypes\n");
+        #endif
+        
+        if ( this->compute_prototypes(features, prototypes, weights, assignment) < 0 )
+        {
+            fprintf(stderr, "KMeans::cluster restart\n");
+            successKMeans = false;
+            break;
+        }
+
+        #ifdef DEBUG_KMEANS
+          fprintf(stderr, "KMeans::cluster compute_delta\n");
+        #endif
+        
+        if (iterations > 1)
+            delta = this->compute_delta(oldprototypes, prototypes);
+
+        #ifdef DEBUG_KMEANS
+          print_iteration(iterations, prototypes, delta);
+        #endif
+
+    } while ((delta > d_minDelta) && (iterations < i_maxIterations));
+    
+  }
+
+  #ifdef DEBUG_KMEANS
+    fprintf(stderr, "KMeans::cluster: iterations = %d, delta = %f\n", iterations, delta);
+  #endif
+
+  this->compute_weights(features, weights, assignment);
 }
 
-void KMeans::print_iteration(int iterations, VVector & prototypes, double delta)
+void KMeans::print_iteration(int iterations, NICE::VVector & prototypes, double delta)
 {
-	if (iterations > 1)
-		fprintf(stderr, "KMeans::cluster: iteration=%d delta=%f\n", iterations,
-				delta);
-	else
-		fprintf(stderr, "KMeans::cluster: iteration=%d\n", iterations);
-
-	int k = 0;
-
-	for (VVector::const_iterator i = prototypes.begin(); i != prototypes.end(); i++, k++)
-	{
-		fprintf(stderr, "class (%d)\n", k);
-		cerr << "prototype = " << (*i) << endl;
-	}
+    if (iterations > 1)
+        fprintf(stderr, "KMeans::cluster: iteration=%d delta=%f\n", iterations,
+                delta);
+    else
+        fprintf(stderr, "KMeans::cluster: iteration=%d\n", iterations);
+
+    int k = 0;
+
+    for (NICE::VVector::const_iterator i = prototypes.begin(); i != prototypes.end(); i++, k++)
+    {
+        fprintf(stderr, "class (%d)\n", k);
+        std::cerr << "prototype = " << (*i) << std::endl;
+    }
 }

+ 99 - 39
math/cluster/KMeans.h

@@ -1,13 +1,14 @@
 /** 
 * @file KMeans.h
 * @brief K-Means
-* @author Erik Rodner
-* @date 10/29/2007
-
+* @author Erik Rodner, Alexander Freytag
+* @date 29-10-2007 (dd-mm-yyyy)
 */
 #ifndef KMEANSINCLUDE
 #define KMEANSINCLUDE
 
+#include <core/basics/Config.h>
+#include <core/vector/Distance.h>
 #include "core/vector/VectorT.h"
 #include "core/vector/MatrixT.h"
   
@@ -17,51 +18,110 @@
 namespace OBJREC {
 
 /** K-Means */
-class KMeans : public ClusterAlgorithm
-{
+  /**
+   * @class K-Means
+   * @brief K-Means
+   * @author Erik Rodner, Alexander Freytag
+   * @date 29-10-2007 (dd-mm-yyyy)
+  */  
+  class KMeans : public ClusterAlgorithm
+  {
 
     protected:
-	int noClasses;
-	std::string distanceType;
-	NICE::VectorDistance<double> *distancefunction;
-	double vectorDistance(const NICE::Vector &vector1, const NICE::Vector &vector2, uint distancetype);
-	double compute_assignments ( const NICE::VVector & features,
-				     const NICE::VVector & prototypes,
-				     std::vector<int> & assignment );
+          
+        /************************
+        * 
+        *   protected variables
+        * 
+        **************************/         
+          
+          //! desired number of clusters
+          int noClasses;
+          
+          //! specify which distance to use for calculating assignments
+          std::string distanceType;
+          
+          //! the actual distance metric
+          NICE::VectorDistance<double> *distancefunction;
+          
+          //! maximum difference between prototype-solutions of two iterations for convergence
+          double d_minDelta;
+          
+          //! maximum number of iterations until convergence
+          int i_maxIterations;          
+          
+        /************************
+        * 
+        *   protected methods
+        * 
+        **************************/          
+          
+        //! compute the distance between two features using the specified distance metric
+          double vectorDistance(const NICE::Vector &vector1, const NICE::Vector &vector2, uint distancetype);
+          
+        //! compute assignments of all given features wrt to the currently known prototypes (cluster centroids) == ~ E-step
+          double compute_assignments ( const NICE::VVector & features,
+                                      const NICE::VVector & prototypes,
+                                      std::vector<int> & assignment );
 
-	double compute_weights ( const NICE::VVector & features,
-				 std::vector<double> & weights,
-				 std::vector<int>    & assignment );
+        //! compute number of assignments for every currently found cluster
+          double compute_weights ( const NICE::VVector & features,
+                                  std::vector<double> & weights,
+                                  std::vector<int>    & assignment );
 
-	double compute_delta ( const NICE::VVector & oldprototypes,
-				       const NICE::VVector & prototypes );
+        //! compute the difference between prototypes of previous iteration and those currently found
+          double compute_delta ( const NICE::VVector & oldprototypes,
+                                const NICE::VVector & prototypes );
 
-	int compute_prototypes ( const NICE::VVector & features,
-				  NICE::VVector & prototypes,
-				  std::vector<double> & weights,
-				  const std::vector<int>    & assignment );
+        //! compute (update) prototypes given the current assignments == ~ M-step
+          int compute_prototypes ( const NICE::VVector & features,
+                                  NICE::VVector & prototypes,
+                                  std::vector<double> & weights,
+                                  const std::vector<int>    & assignment );
+          
+        //! have an initial guess, i.e., randomly pick some features as initial cluster centroids
+          void initial_guess ( const NICE::VVector & features,
+                              NICE::VVector & prototypes );
+        //! give additional information for the current iteration
+          void print_iteration ( int iterations,
+                                NICE::VVector & prototypes,
+                                double delta );
 
-	void initial_guess ( const NICE::VVector & features,
-			     NICE::VVector & prototypes );
-	
-	void print_iteration ( int iterations, 
-			       NICE::VVector & prototypes,
-			       double delta );
+      public:
 
-    public:
-  
-	/** simple constructor */
-	KMeans( int noClasses , std::string distanceMode="euclidean");
+        /**
+        * @brief simple constructor
+        * @param _noClasses the number of clusters to be computed
+        * @param _distanceMode a string specifying the distance function to be used (default: euclidean)
+        */
+        KMeans( const int & _noClasses , const std::string & _distanceMode="euclidean");
       
-	/** simple destructor */
-	virtual ~KMeans();
-     
-	void cluster ( const NICE::VVector & features,
-		       NICE::VVector & prototypes,
-		       std::vector<double> & weights,
-		       std::vector<int>    & assignment );
+        /**
+        * @brief standard constructor
+        * @param conf config file specifying all relevant variable settings
+        * @param _section name of the section within the configfile where the settings can be found (default: KMeans)
+        */
+        KMeans( const NICE::Config *conf, const std::string & _section = "KMeans");      
+
+        /** simple destructor */
+        virtual ~KMeans();
+
+        
+          /**
+          *@brief this is the actual method that performs the clustering for a given set of features
+          *@author Erik Rodner, Alexander Freytag
+          *@date 29-10-2007 (dd-mm-yyyy)
+          *@param   features input features to be clustered
+          *@param   prototypes computed prototypes (cluster medoids) for the given samples
+          *@param   weights number of assignments for every cluster
+          *@param   assignment explicite assignments of features to computed cluster medoids
+          */            
+        void cluster ( const NICE::VVector & features,
+                      NICE::VVector & prototypes,
+                      std::vector<double> & weights,
+                      std::vector<int>    & assignment );
 
-};
+  };
 
 
 } // namespace

+ 17 - 9
math/cluster/KMeansHeuristic.cpp

@@ -18,11 +18,19 @@ using namespace NICE;
 
 #undef DEBUG_KMeansHeuristic
 
-KMeansHeuristic::KMeansHeuristic(int _noClasses, string _distanceType) :
-	noClasses(_noClasses), distanceType(_distanceType)
+KMeansHeuristic::KMeansHeuristic(int _noClusters, string _distanceType) :
+	noClusters(_noClusters), distanceType(_distanceType)
 {
-	//srand(time(NULL));
-	distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+  //srand(time(NULL));
+  distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+}
+
+KMeansHeuristic::KMeansHeuristic( const NICE::Config *conf, const std::string & _section)
+{       
+  this->distanceType = conf->gS( _section, "distanceType", "euclidean" );
+  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+  
+  this->noClusters = conf->gI( _section, "noClusters", 20);
 }
 
 KMeansHeuristic::~KMeansHeuristic()
@@ -200,7 +208,7 @@ double KMeansHeuristic::compute_assignments(const VVector & features,
 double KMeansHeuristic::compute_weights(const VVector & features, std::vector<
 		double> & weights, std::vector<int> & assignment)
 {
-	for (int k = 0; k < noClasses; k++)
+	for (int k = 0; k < noClusters; k++)
 		weights[k] = 0;
 
 	int j = 0;
@@ -211,7 +219,7 @@ double KMeansHeuristic::compute_weights(const VVector & features, std::vector<
 		weights[k]++;
 	}
 
-	for (int k = 0; k < noClasses; k++)
+	for (int k = 0; k < noClusters; k++)
 		weights[k] = weights[k] / features.size();
 
 	return 0.0;
@@ -225,12 +233,12 @@ void KMeansHeuristic::cluster(const VVector & features, VVector & prototypes,
 	prototypes.clear();
 	weights.clear();
 	assignment.clear();
-	weights.resize(noClasses, 0);
+	weights.resize(noClusters, 0);
 	assignment.resize(features.size(), 0);
 
 	int dimension;
 
-	if ((int) features.size() >= noClasses)
+	if ((int) features.size() >= noClusters)
 		dimension = features[0].size();
 	else
 	{
@@ -239,7 +247,7 @@ void KMeansHeuristic::cluster(const VVector & features, VVector & prototypes,
 		exit(-1);
 	}
 
-	for (int k = 0; k < noClasses; k++)
+	for (int k = 0; k < noClusters; k++)
 	{
 		prototypes.push_back(Vector(dimension));
 		prototypes[k].set(0);

+ 37 - 26
math/cluster/KMeansHeuristic.h

@@ -8,50 +8,61 @@
 #ifndef KMeansHeuristicINCLUDE
 #define KMeansHeuristicINCLUDE
 
+#include <core/basics/Config.h>
 #include <core/vector/Distance.h>
-#include "ClusterAlgorithm.h"
-
 #include "core/vector/VectorT.h"
 #include "core/vector/MatrixT.h"
 
+#include "ClusterAlgorithm.h"
+
 
 namespace OBJREC
 {
 
-/** K-Means */
-class KMeansHeuristic: public ClusterAlgorithm
-{
+  /** K-Means (but what does Heuristic actually mean? )*/
+  class KMeansHeuristic: public ClusterAlgorithm
+  {
 
-protected:
-	int noClasses;
-	std::string distanceType;
-	NICE::VectorDistance<double> *distancefunction;
-	double compute_assignments(const NICE::VVector & features,
-			const NICE::VVector & prototypes, std::vector<int> & assignment);
+  protected:
+    int noClusters;
+    std::string distanceType;
+    NICE::VectorDistance<double> *distancefunction;
+    
+    double compute_assignments(const NICE::VVector & features,
+        const NICE::VVector & prototypes, std::vector<int> & assignment);
 
-	double compute_weights(const NICE::VVector & features,
-			std::vector<double> & weights, std::vector<int> & assignment);
+    double compute_weights(const NICE::VVector & features,
+        std::vector<double> & weights, std::vector<int> & assignment);
 
-	double compute_delta(const NICE::VVector & oldprototypes,
-			const NICE::VVector & prototypes);
+    double compute_delta(const NICE::VVector & oldprototypes,
+        const NICE::VVector & prototypes);
 
 
-	void initial_guess(const NICE::VVector & features, NICE::VVector & prototypes);
+    void initial_guess(const NICE::VVector & features, NICE::VVector & prototypes);
 
-	void print_iteration(int iterations, NICE::VVector & prototypes, double delta);
-	int robust_prototypes(const NICE::VVector &features, NICE::VVector &prototypes, std::vector<
-			double> & weights, const std::vector<int> & assignment);
-public:
+    void print_iteration(int iterations, NICE::VVector & prototypes, double delta);
+    int robust_prototypes(const NICE::VVector &features, NICE::VVector &prototypes, std::vector<
+        double> & weights, const std::vector<int> & assignment);
+  public:
 
-	/** simple constructor */
-	KMeansHeuristic(int noClasses, std::string distanceMode = "euclidean");
+    /** simple constructor */
+    KMeansHeuristic(int noClusters, std::string distanceMode = "euclidean");
+    
+    /**
+    * @brief standard constructor
+    * @param conf config file specifying all relevant variable settings
+    * @param _section name of the section within the configfile where the settings can be found (default: KMeansHeuristic)
+    * @date 14-06-2013 (dd-mm-yyyy)
+    * @author Alexander Freytag
+    */
+    KMeansHeuristic( const NICE::Config *conf, const std::string & _section = "KMeansHeuristic");    
 
-	/** simple destructor */
-	virtual ~KMeansHeuristic();
+    /** simple destructor */
+    virtual ~KMeansHeuristic();
 
-	void cluster(const NICE::VVector & features, NICE::VVector & prototypes, std::vector<double> & weights, std::vector<int> & assignment);
+    void cluster(const NICE::VVector & features, NICE::VVector & prototypes, std::vector<double> & weights, std::vector<int> & assignment);
 
-};
+  };
 
 } // namespace
 

+ 18 - 18
math/cluster/KMeansMatlab.cpp

@@ -19,23 +19,23 @@ using namespace NICE;
 
 #undef DEBUG_KMeansMatlab
 
-KMeansMatlab::KMeansMatlab( const Config *conf, 
-			    int _noClasses ) : noClasses(_noClasses)
+KMeansMatlab::KMeansMatlab( const Config *conf, const std::string & _section )
 {
-    kmeansDir = conf->gS("matlab", "source_root", "/home/rodner/osl/labor/cvs/osl/") + "/kernel/";
-    inputFN   = conf->gS("KMeansMatlab", "tmpInput", "/tmp/KMeansMatlab.input" );
-    outputFN   = conf->gS("KMeansMatlab", "tmpoutput", "/tmp/KMeansMatlab.output" );
-
-    matlabExec = conf->gS("matlab", "matlab_exec", "matlab");
-    matlabArgs = conf->gS("matlab", "matlab_args", "-nosplash -nojvm -nodesktop");
-    
+  this->noClusters = conf->gI( _section, "noClusters", 20);
+  
+    kmeansDir = conf->gS(_section, "source_root", "/home/rodner/osl/labor/cvs/osl/") + "/kernel/";
+    inputFN   = conf->gS(_section, "tmpInput", "/tmp/KMeansMatlab.input" );
+    outputFN   = conf->gS(_section, "tmpOutput", "/tmp/KMeansMatlab.output" );
+
+    matlabExec = conf->gS(_section, "matlab_exec", "matlab");
+    matlabArgs = conf->gS(_section, "matlab_args", "-nosplash -nojvm -nodesktop");   
     
 }
 
 KMeansMatlab::~KMeansMatlab()
 {
-    if ( matlabPipe != NULL )
-	pclose (matlabPipe);
+  if ( matlabPipe != NULL )
+    pclose (matlabPipe);
 }
 
 
@@ -45,8 +45,8 @@ int KMeansMatlab::compute_prototypes ( const VVector & features,
 				  const std::vector<int>    & assignment )
 {
     int j = 0;
-    // fprintf (stderr, "KMeansMatlab::compute_prototypes: init noClasses=%d\n", noClasses);
-    for ( int k = 0 ; k < noClasses ; k++ )
+    // fprintf (stderr, "KMeansMatlab::compute_prototypes: init noClusters=%d\n", noClusters);
+    for ( int k = 0 ; k < noClusters ; k++ )
     {
 	prototypes[k].set(0);
 	weights[k] = 0;
@@ -81,7 +81,7 @@ int KMeansMatlab::compute_prototypes ( const VVector & features,
     }
 
     // fprintf (stderr, "KMeansMatlab::compute_prototypes: scaling\n");
-    for ( int k = 0 ; k < noClasses ; k++ )
+    for ( int k = 0 ; k < noClusters ; k++ )
     {
 	// refactor-nice.pl: check this substitution
 	// old: Vector & p = prototypes[k];
@@ -117,7 +117,7 @@ void KMeansMatlab::cluster ( const VVector & features,
     prototypes.clear();
     weights.clear();
     assignment.clear ();
-    weights.resize ( noClasses, 0 );
+    weights.resize ( noClusters, 0 );
     assignment.resize ( features.size(), 0 );
 
     // ----------- routine argument -------------
@@ -127,7 +127,7 @@ void KMeansMatlab::cluster ( const VVector & features,
 
     int dimension;
 
-    if ( (int)features.size() >= noClasses )
+    if ( (int)features.size() >= noClusters )
 	dimension = features[0].size();
     else {
 	fprintf (stderr, "FATAL ERROR: Not enough feature vectors provided for KMeansMatlab\n");
@@ -140,7 +140,7 @@ void KMeansMatlab::cluster ( const VVector & features,
 	fprintf (stderr, "KMeansMatlab: FATAL ERROR cannot write features!\n");
 	exit(-1);
     }
-    fwrite (&noClasses, sizeof(int), 1, fi );
+    fwrite (&noClusters, sizeof(int), 1, fi );
     int n = features.size();
     fwrite (&n, sizeof(int), 1, fi );
     int d = features[0].size();
@@ -191,7 +191,7 @@ void KMeansMatlab::cluster ( const VVector & features,
     fclose(g);
 
 
-    for ( int k = 0 ; k < noClasses ; k++ )
+    for ( int k = 0 ; k < noClusters ; k++ )
     {
 	// fprintf (stderr, "KMeansMatlab::cluster prototype init constructor\n");
 	prototypes.push_back( Vector( dimension ) );

+ 55 - 46
math/cluster/KMeansMatlab.h

@@ -1,6 +1,6 @@
 /** 
 * @file KMeansMatlab.h
-* @brief K-Means
+* @brief K-Means using a matlab implementation
 * @author Erik Rodner
 * @date 10/29/2007
 
@@ -17,51 +17,60 @@
 
 namespace OBJREC {
 
-/** K-Means */
-class KMeansMatlab : public ClusterAlgorithm
-{
-
-    protected:
-	int noClasses;
-	// refactor-nice.pl: check this substitution
-	// old: string kmeansDir;
-	std::string kmeansDir;
-	// refactor-nice.pl: check this substitution
-	// old: string matlabExec;
-	std::string matlabExec;
-	// refactor-nice.pl: check this substitution
-	// old: string matlabArgs;
-	std::string matlabArgs;
-
-	// refactor-nice.pl: check this substitution
-	// old: string inputFN;
-	std::string inputFN;
-	// refactor-nice.pl: check this substitution
-	// old: string outputFN;
-	std::string outputFN;
-
-	FILE *matlabPipe;
-	
-	int compute_prototypes ( const NICE::VVector & features,
-				  NICE::VVector & prototypes,
-				  std::vector<double> & weights,
-				  const std::vector<int>    & assignment );
-
-
-    public:
-  
-	/** simple constructor */
-	KMeansMatlab( const NICE::Config *conf, int noClasses );
-      
-	/** simple destructor */
-	virtual ~KMeansMatlab();
-     
-	void cluster ( const NICE::VVector & features,
-		       NICE::VVector & prototypes,
-		       std::vector<double> & weights,
-		       std::vector<int>    & assignment );
-
-};
+  /** 
+  * @class KMeansMatlab
+  * @brief K-Means using a matlab implementation
+  * @author Erik Rodner
+  */
+
+  class KMeansMatlab : public ClusterAlgorithm
+  {
+
+      protected:
+        int noClusters;
+        // refactor-nice.pl: check this substitution
+        // old: string kmeansDir;
+        std::string kmeansDir;
+        // refactor-nice.pl: check this substitution
+        // old: string matlabExec;
+        std::string matlabExec;
+        // refactor-nice.pl: check this substitution
+        // old: string matlabArgs;
+        std::string matlabArgs;
+
+        // refactor-nice.pl: check this substitution
+        // old: string inputFN;
+        std::string inputFN;
+        // refactor-nice.pl: check this substitution
+        // old: string outputFN;
+        std::string outputFN;
+
+        FILE *matlabPipe;
+        
+        int compute_prototypes ( const NICE::VVector & features,
+                NICE::VVector & prototypes,
+                std::vector<double> & weights,
+                const std::vector<int>    & assignment );
+
+
+      public:
+    
+        /** 
+        * @brief simple constructor
+        * @author Erik Rodner, Alexander Freytag
+        * Among others, you can specify for "section" the following attributes: "source_root", "tmpInput", "tmpOutput", "matlab_exec", "matlab_args"
+        */
+        KMeansMatlab( const NICE::Config *conf,  const std::string & _section = "KMeansMatlab" );
+            
+        /** simple destructor */
+        virtual ~KMeansMatlab();
+          
+        void cluster ( const NICE::VVector & features,
+                NICE::VVector & prototypes,
+                std::vector<double> & weights,
+                std::vector<int>    & assignment );
+
+  };
 
 
 } // namespace

+ 430 - 0
math/cluster/KMedian.cpp

@@ -0,0 +1,430 @@
+/**
+ * @file KMedian.cpp
+ * @brief KMedian (aka K-medoid)
+ * @author Alexander Freytag
+ * @date 23-04-2013 (dd-mm-yyyy)
+ */
+
+#ifdef NICE_USELIB_OPENMP
+#include <omp.h>
+#endif
+
+#include <iostream>
+#include <map>
+#include <algorithm> //to easily find the smallest value in a map
+
+#include "vislearning/math/cluster/KMedian.h"
+#include "vislearning/math/distances/genericDistance.h"
+
+#include <set>
+
+using namespace OBJREC;
+
+using namespace std;
+
+using namespace NICE;
+
+
+typedef std::pair<int, double> MyPairType;
+struct CompareSecond
+{
+    bool operator()(const MyPairType& left, const MyPairType& right) const
+    {
+        return left.second < right.second;
+    }
+};
+
+#undef DEBUG_KMEDIAN_ASSIGNMENTS
+// #define DEBUG_KMEDIAN_ASSIGNMENTS
+
+#undef DEBUG_KMEDIAN_PROTOCOMP
+// #define DEBUG_KMEDIAN_PROTOCOMP
+
+
+KMedian::KMedian(const int & _noClusters, const std::string & _distanceType) :
+  noClusters(_noClusters), distanceType(_distanceType)
+{
+  //srand(time(NULL));
+  distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+  
+  this->d_minDelta  = 1e-5;
+  this->i_maxIterations = 200;
+}
+
+KMedian::KMedian( const NICE::Config *conf, const std::string & _section)
+{       
+  this->distanceType = conf->gS( _section, "distanceType", "euclidean" );
+  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+  
+  this->d_minDelta  = conf->gD( _section, "minDelta", 1e-5 );
+  this->i_maxIterations = conf->gI( _section, "maxIterations", 200);
+  
+  this->noClusters = conf->gI( _section, "noClusters", 20);
+}
+
+KMedian::~KMedian()
+{
+}
+
+void KMedian::initial_guess(const VVector & features, VVector & prototypes)
+{
+  int j = 0;
+  std::set<int, std::greater<int> > mark;
+
+  for (VVector::iterator i = prototypes.begin(); i != prototypes.end(); i++, j++)
+  {
+    int k;
+
+    do
+    {
+      k = rand() % features.size();
+    } while (mark.find(k) != mark.end());
+
+    mark.insert(mark.begin(), k);
+
+    *i = features[k];
+  }
+}
+
+int KMedian::compute_prototypes(const VVector & features, VVector & prototypes,
+    std::vector<double> & weights, const std::vector<int> & assignment)
+{
+  
+  #ifdef DEBUG_KMEDIAN_PROTOCOMP  
+    std::cerr << "initial assignments: ";
+    for (std::vector<int>::const_iterator assignIt = assignment.begin(); assignIt != assignment.end(); assignIt++)
+    { 
+      std::cerr << " " << *assignIt;
+    } 
+    std::cerr << std::endl;
+  #endif
+  
+  //initialization
+  for (int k = 0; k < noClusters; k++)
+  {
+    prototypes[k].set(0);
+    weights[k] = 0;
+  }
+  
+  NICE::VectorT<int> numberOfCurrentAssignments ( noClusters ) ;
+  numberOfCurrentAssignments.set ( 0 );
+  
+  int exCnt = 0;  
+  //how many examples are assigned to the current clusters?
+  for (VVector::const_iterator i = features.begin(); i != features.end(); i++, exCnt++)
+  {
+    int k = assignment[exCnt];
+    //increase counter for assigned cluster
+    numberOfCurrentAssignments[ k ] ++;    
+  }
+    
+  #ifdef DEBUG_KMEDIAN_PROTOCOMP    
+    std::cerr << "k-median -- current assignmens: " << numberOfCurrentAssignments << std::endl << "noClusters: " << noClusters << std::endl;
+  #endif
+  
+  //compute the median for every cluster
+  #pragma omp parallel for
+  for (int clusterCnt = 0; clusterCnt < noClusters; clusterCnt++)
+  {    
+    NICE::Vector overallDistances ( numberOfCurrentAssignments[ clusterCnt ] );
+    VVector::const_iterator lastExampleWorkedOn = features.begin();
+    int i_idxOfLastExampleWorkedOn ( 0 );
+    uint i_exCntInt ( 0 );
+
+    //this map will contain overall distances of all examples within the current clusters
+    //we need separate maps for every cluster to allow parallelization
+    std::map<int,double> distancesWithinCluster;
+    for (VVector::const_iterator featIt = features.begin(); featIt != features.end(); featIt++, i_exCntInt++)
+    {
+      int k = assignment[i_exCntInt];
+      
+      //only considere examples currently assigned to cluster clusterCnt
+      if ( k != clusterCnt)
+      {
+        continue;      
+      }
+      
+      uint exCntIntTmp ( i_idxOfLastExampleWorkedOn ); //idx going over all features 
+      for (VVector::const_iterator j = lastExampleWorkedOn ; j != features.end(); j++, exCntIntTmp++)
+      {
+        int kTmp;
+        if ( exCntIntTmp < assignment.size() )
+          kTmp = assignment[exCntIntTmp];
+        else
+        {
+          //actually, this will be never be reached :)
+          std::cerr << "ERROR: exCntIntTmp >= assignment.size() " << exCntIntTmp << " " << assignment.size() << std::endl;
+        }
+        
+        //only considere examples currently assigned to cluster clusterCnt
+        if ( kTmp != clusterCnt)
+          continue;         
+       
+        
+        double dist ( distancefunction->calculate( *featIt, *j) );
+        if ( i_exCntInt < features.size() )
+        {
+          distancesWithinCluster[ i_exCntInt ] += dist;
+          #ifdef DEBUG_KMEDIAN_PROTOCOMP
+            std::cerr << "increase " << i_exCntInt << " by " << dist << " for " <<*featIt << " and " << *j << std::endl;
+          #endif
+        }
+        else
+        {
+          //actually, this will be never be reached :)          
+          std::cerr << "ERROR: i_exCntInt >= features.size() " << i_exCntInt << " " << features.size() << std::endl;
+        }
+
+        if ( i_exCntInt != exCntIntTmp )
+        {
+          if (exCntIntTmp < features.size() )
+          {
+            distancesWithinCluster[ exCntIntTmp ] += dist;
+            #ifdef DEBUG_KMEDIAN_PROTOCOMP
+              std::cerr << "increase also " << exCntIntTmp << " by " << dist << std::endl;
+            #endif
+          }
+          else
+            std::cerr << "ERROR: exCntIntTmp >= features.size() " << exCntIntTmp << " " << features.size() << std::endl;
+        }
+        
+      }      
+      
+      //inc by one to avoid calculating some distances twice
+      if ( ( featIt != features.end()) && ( (featIt +1 ) != features.end()) )
+      {
+        lastExampleWorkedOn = ( featIt + 1 );      
+        i_idxOfLastExampleWorkedOn = i_exCntInt+1;
+      }
+    }
+       
+    #ifdef DEBUG_KMEDIAN_PROTOCOMP
+      std::cerr << "distances for cluster " << clusterCnt << " ";
+      for(std::map<int,double>::const_iterator distIt = distancesWithinCluster.begin(); distIt != distancesWithinCluster.end(); distIt++)
+      {
+        std::cerr << distIt->first << " " << distIt->second << " ";
+      }
+      std::cerr << std::endl;
+    #endif
+      
+    //now compute the index of example with min overall distance
+    int idxOfClusterMedian ( (min_element(distancesWithinCluster.begin(), distancesWithinCluster.end(), CompareSecond()))->first );
+        
+    #pragma omp critical
+    prototypes[clusterCnt] = features[idxOfClusterMedian]; 
+ 
+    //finished computations for cluster k
+  }
+  
+  #ifdef DEBUG_KMEDIAN_PROTOCOMP
+    std::cerr << " ----   prototypes after current iteration:  --- " << std::endl;
+    for (NICE::VVector::const_iterator protoIt = prototypes.begin(); protoIt != prototypes.end(); protoIt++)
+    {
+      std::cerr << *protoIt << " ";
+    }
+    
+    std::cerr << std::endl;
+  #endif
+
+  return 0;
+}
+
+double KMedian::compute_delta(const VVector & oldprototypes,
+    const VVector & prototypes)
+{
+  double distance = 0;
+
+  for (uint k = 0; k < oldprototypes.size(); k++)
+  {
+    distance += distancefunction->calculate(oldprototypes[k], prototypes[k]);
+    
+    #ifdef DEBUG_KMEDIAN_ASSIGNMENTS
+      fprintf(stderr, "KMedian::compute_delta: Distance:",
+          distancefunction->calculate(oldprototypes[k], prototypes[k]));
+    #endif
+  }
+  return distance;
+}
+
+double KMedian::compute_assignments(const VVector & features,
+                                    const VVector & prototypes,
+                                    std::vector<int> & assignment)
+{
+  int index = 0;
+  for (VVector::const_iterator i = features.begin(); i != features.end(); i++, index++)
+  {
+
+    const NICE::Vector & x = *i;
+    double mindist = std::numeric_limits<double>::max();
+    int minclass = 0;
+
+    int c = 0;
+    
+    #ifdef DEBUG_KMEDIAN_ASSIGNMENTS
+
+        fprintf(stderr, "computing nearest prototype for std::vector %d\n",
+            index);
+    #endif
+        
+    for (VVector::const_iterator j = prototypes.begin(); j
+        != prototypes.end(); j++, c++)
+    {
+
+      const NICE::Vector & p = *j;
+      double distance = distancefunction->calculate(p, x);
+      
+      #ifdef DEBUG_KMEDIAN_ASSIGNMENTS
+        fprintf(stderr, "KMedian::compute_delta: Distance: %f\n",
+            distancefunction->calculate(p, x));
+      #endif
+
+      #ifdef DEBUG_KMEDIAN_ASSIGNMENTS
+            cerr << p << endl;
+            cerr << x << endl;
+            fprintf(stderr, "distance to prototype %d is %f\n", c, distance);
+      #endif
+
+      if (distance < mindist)
+      {
+        minclass = c;
+        mindist = distance;
+      }
+    }
+
+    assignment[index] = minclass;
+  }
+
+  return 0.0;
+}
+
+double KMedian::compute_weights(const VVector & features,
+                                std::vector<double> & weights,
+                                std::vector<int> & assignment)
+{
+  for (int k = 0; k < noClusters; k++)
+    weights[k] = 0;
+
+  int j = 0;
+
+  for (VVector::const_iterator i = features.begin(); i != features.end(); i++, j++)
+  {
+    int k = assignment[j];
+    weights[k]++;
+  }
+
+  for (int k = 0; k < noClusters; k++)
+    weights[k] = weights[k] / features.size();
+
+  return 0.0;
+}
+
+void KMedian::cluster(const NICE::VVector & features,
+                      NICE::VVector & prototypes,
+                      std::vector<double> & weights,
+                      std::vector<int> & assignment)
+{
+  NICE::VVector oldprototypes;
+
+  prototypes.clear();
+  weights.clear();
+  assignment.clear();
+  weights.resize(noClusters, 0);
+  assignment.resize(features.size(), 0);
+
+  int dimension;
+
+  if ((int) features.size() >= noClusters)
+    dimension = features[0].size();
+  else
+  {
+    fprintf(stderr,
+        "FATAL ERROR: Not enough feature vectors provided for kMedians -- number of Features: %i - number of clusters: %i\n", (int) features.size(), noClusters);
+    exit(-1);
+  }
+
+  for (int k = 0; k < noClusters; k++)
+  {
+    prototypes.push_back( NICE::Vector(dimension) );
+    prototypes[k].set(0);
+  }
+ 
+  bool successKMedian ( false );
+  int iterations ( 0 );
+  double delta ( std::numeric_limits<double>::max() );
+  
+  while ( !successKMedian )
+  {
+    //we assume that this run will be successful
+    successKMedian = true;
+    
+    this->initial_guess(features, prototypes);
+
+    iterations = 0;
+    delta =  std::numeric_limits<double>::max();
+
+    //until-loop over iterations
+    do
+    {
+      iterations++;
+      
+//       #ifdef DEBUG_KMEDIAN_ASSIGNMENTS
+        std::cerr << "k-median iteration " << iterations << std::endl;
+//       #endif
+        
+      this->compute_assignments( features, prototypes, assignment );
+
+      if (iterations > 1)
+        oldprototypes = prototypes;
+
+      #ifdef DEBUG_KMEDIAN_ASSIGNMENTS
+          fprintf(stderr, "KMedian::cluster compute_prototypes\n");
+      #endif
+      
+      if ( this->compute_prototypes( features, prototypes, weights, assignment ) < 0 )
+      {
+        fprintf(stderr, "KMedian::cluster restart\n");
+        successKMedian = false;
+        break;
+      }
+
+      #ifdef DEBUG_KMEDIAN_ASSIGNMENTS
+          fprintf(stderr, "KMedian::cluster compute_delta\n");
+      #endif
+      
+      if (iterations > 1)
+        delta = this->compute_delta( oldprototypes, prototypes );
+
+      #ifdef DEBUG_KMEDIAN_ASSIGNMENTS
+          this->print_iteration( iterations, prototypes, delta );
+      #endif
+
+    } while ((delta > d_minDelta) && (iterations < i_maxIterations));
+    
+  }
+
+  std::cerr << "ended optimization  -- delta: " << delta  << " of d_minDelta: " << d_minDelta << " --- and iterations: " << iterations << " of i_maxIterations: " << i_maxIterations << std::endl;
+    
+  #ifdef DEBUG_KMEDIAN_ASSIGNMENTS
+    fprintf(stderr, "KMedian::cluster: iterations = %d, delta = %f\n",
+        iterations, delta);
+  #endif
+
+  this->compute_weights( features, weights, assignment );
+}
+
+void KMedian::print_iteration( int iterations, VVector & prototypes, double delta )
+{
+  if (iterations > 1)
+    fprintf(stderr, "KMedian::cluster: iteration=%d delta=%f\n", iterations,
+        delta);
+  else
+    fprintf(stderr, "KMedian::cluster: iteration=%d\n", iterations);
+
+  int k = 0;
+
+  for (VVector::const_iterator i = prototypes.begin(); i != prototypes.end(); i++, k++)
+  {
+    fprintf(stderr, "class (%d)\n", k);
+    cerr << "prototype = " << (*i) << endl;
+  }
+}

+ 131 - 0
math/cluster/KMedian.h

@@ -0,0 +1,131 @@
+/** 
+* @file KMedian.h
+ * @brief KMedian (aka K-medoid)
+* @author Alexander Freytag
+* @date 23-04-2013 (dd-mm-yyyy)
+
+*/
+#ifndef KMEDIANINCLUDE
+#define KMEDIANINCLUDE
+
+#include <core/basics/Config.h>
+#include <core/vector/Distance.h>
+#include <core/vector/MatrixT.h>
+#include <core/vector/VectorT.h>
+  
+#include "ClusterAlgorithm.h"
+
+namespace OBJREC {
+
+  /**
+   * @class KMedian
+   * @brief KMedian (aka K-medoid)
+   * @author Alexander Freytag
+   * @date 23-04-2013 (dd-mm-yyyy)
+  */    
+  class KMedian : public ClusterAlgorithm
+  {
+
+      protected:
+        
+      /************************
+       * 
+       *   protected variables
+       * 
+       **************************/ 
+      
+        //! desired number of clusters
+        int noClusters;
+        
+        //! specify which distance to use for calculating assignments
+        std::string distanceType;
+        
+        //! the actual distance metric
+        NICE::VectorDistance<double> *distancefunction;
+        
+        //! maximum difference between prototype-solutions of two iterations for convergence
+        double d_minDelta;
+        
+        //! maximum number of iterations until convergence
+        int i_maxIterations;
+        
+  
+       /************************
+       * 
+       *   protected methods
+       * 
+       **************************/  
+      
+        //! compute the distance between two features using the specified distance metric
+        double vectorDistance(const NICE::Vector &vector1, const NICE::Vector &vector2, uint distancetype);
+        
+        //! compute assignments of all given features wrt to the currently known prototypes (cluster medoids) == ~ E-step
+        double compute_assignments ( const NICE::VVector & features,
+                  const NICE::VVector & prototypes,
+                  std::vector<int> & assignment );
+
+        //! compute number of assignments for every currently found cluster
+        double compute_weights ( const NICE::VVector & features,
+              std::vector<double> & weights,
+              std::vector<int>    & assignment );
+
+        //! compute the difference between prototypes of previous iteration and those currently found
+        double compute_delta ( const NICE::VVector & oldprototypes,
+                    const NICE::VVector & prototypes );
+
+        //! compute (update) prototypes given the current assignments == ~ M-step
+        int compute_prototypes ( const NICE::VVector & features,
+                NICE::VVector & prototypes,
+                std::vector<double> & weights,
+                const std::vector<int>    & assignment );
+
+        //! have an initial guess, i.e., randomly pick some features as initial cluster centroids
+        void initial_guess ( const NICE::VVector & features,
+                NICE::VVector & prototypes );
+        
+        //! give additional information for the current iteration
+        void print_iteration ( int iterations, 
+                  NICE::VVector & prototypes,
+                  double delta );
+
+      public:
+    
+        /**
+        * @brief simple constructor
+        * @param _noClusters the number of clusters to be computed
+        * @param _distanceMode a string specifying the distance function to be used (default: euclidean)
+        */
+        KMedian( const int & _noClusters , const std::string & _distanceMode="euclidean");
+        
+        /**
+        * @brief standard constructor
+        * @param conf config file specifying all relevant variable settings
+        * @param _section name of the section within the configfile where the settings can be found (default: KMedian)
+        */
+        KMedian( const NICE::Config *conf, const std::string & _section = "KMedian");
+
+        
+            
+        /** simple destructor */
+        virtual ~KMedian();
+          
+        /**
+        *@brief this is the actual method that performs the clustering for a given set of features
+        *@author Alexander Freytag
+        *@date 25-04-2013 (dd-mm-yyyy)
+        *@param   features input features to be clustered
+        *@param   prototypes computed prototypes (cluster medoids) for the given samples
+        *@param   weights number of assignments for every cluster
+        *@param   assignment explicite assignments of features to computed cluster medoids
+        */        
+        void cluster ( const NICE::VVector & features,
+                NICE::VVector & prototypes,
+                std::vector<double> & weights,
+                std::vector<int>    & assignment );
+
+  };
+
+
+} // namespace
+
+#endif

+ 157 - 0
math/cluster/RandomClustering.cpp

@@ -0,0 +1,157 @@
+/**
+ * @file RandomClustering.cpp
+* @brief Clustering by randomly picking some samples from the set of features as representatives
+* @author Alexander Freytag
+* @date 03-06-2013 (dd-mm-yyyy)
+ */
+
+#ifdef NICE_USELIB_OPENMP
+#include <omp.h>
+#endif
+
+#include <iostream>
+#include <map>
+
+#include "vislearning/math/distances/genericDistance.h"
+
+#include "vislearning/math/cluster/RandomClustering.h"
+
+#include <set>
+
+using namespace OBJREC;
+
+using namespace std;
+
+using namespace NICE;
+
+
+
+RandomClustering::RandomClustering(const int & _noClusters, const std::string & _distanceType) :
+  noClusters(_noClusters), distanceType(_distanceType)
+{
+}
+
+RandomClustering::RandomClustering( const NICE::Config *conf, const std::string & _section)
+{  
+  this->noClusters = conf->gI( _section, "noClusters", 20);
+  
+  this->distanceType = conf->gS( _section, "distanceType", "euclidean" );
+  this->distancefunction = GenericDistanceSelection::selectDistance(distanceType);  
+}
+
+RandomClustering::~RandomClustering()
+{
+}
+
+int RandomClustering::compute_prototypes(const NICE::VVector & _features, NICE::VVector & _prototypes,
+    std::vector<double> & _weights, const std::vector<int> & _assignment)
+{
+  
+  int noFeatures ( _features.size() );
+  
+  std::set<int, std::greater<int> > chosenIdx;
+  
+  //empty init
+  chosenIdx.clear();
+  
+  //pick k distinct cluster representatives randomly
+  for (int cnt = 0; cnt < this->noClusters; cnt++)
+  {
+    int idx;
+    do
+    {
+      idx = rand() % noFeatures;
+    }
+    while ( chosenIdx.find ( idx ) != chosenIdx.end() );
+                             
+    //if a new (distinct) idx was computed, insert it into the set of randomly picked indicees
+    chosenIdx.insert ( idx );
+  }
+  
+  _prototypes.resize( this->noClusters ); 
+  
+  int clusterCnt ( 0 );
+  for ( std::set<int>::const_iterator idxIt = chosenIdx.begin(); idxIt != chosenIdx.end(); idxIt++, clusterCnt++ )
+  {
+     _prototypes[clusterCnt] = _features[ *idxIt ];
+  }
+
+  return 0;
+}
+
+double RandomClustering::compute_assignments(const NICE::VVector & _features,
+                                    const NICE::VVector & _prototypes,
+                                    std::vector<int> & _assignment)
+{
+  _assignment.resize( _features.size() );
+  
+  int index = 0;
+  for (NICE::VVector::const_iterator i = _features.begin(); i != _features.end(); i++, index++)
+  {
+
+    const NICE::Vector & x = *i;
+    double mindist = std::numeric_limits<double>::max();
+    int minclass = 0;
+
+    int c = 0;
+           
+    for (NICE::VVector::const_iterator j = _prototypes.begin(); j
+        != _prototypes.end(); j++, c++)
+    {
+
+      const NICE::Vector & p = *j;
+      double distance = this->distancefunction->calculate(p, x);
+      
+      if (distance < mindist)
+      {
+        minclass = c;
+        mindist = distance;
+      }
+    }
+
+    _assignment[index] = minclass;
+  }
+
+  return 0.0;
+}
+
+double RandomClustering::compute_weights(const NICE::VVector & _features,
+                                std::vector<double> & _weights,
+                                std::vector<int> & _assignment)
+{
+  _weights.resize( this->noClusters );
+  
+  //initalization
+  for (int k = 0; k < noClusters; k++)
+    _weights[k] = 0;
+
+  int j = 0;
+
+  //increase weight for every assignment
+  for (NICE::VVector::const_iterator i = _features.begin(); i != _features.end(); i++, j++)
+  {
+    int k = _assignment[j];
+    _weights[k]++;
+  }
+
+  //normalize weights
+  for (int k = 0; k < noClusters; k++)
+    _weights[k] = _weights[k] / _features.size();
+
+  return 0.0;
+}
+
+void RandomClustering::cluster(const NICE::VVector & _features,
+                      NICE::VVector & _prototypes,
+                      std::vector<double> & _weights,
+                      std::vector<int> & _assignment)
+{
+  //randomly pick cluster centers
+  this->compute_prototypes( _features, _prototypes, _weights, _assignment );
+  
+  //compute assignments for every cluster
+  this->compute_assignments( _features, _prototypes, _assignment );
+  
+  //compute corresponding weights
+  this->compute_weights( _features, _weights, _assignment );
+}

+ 112 - 0
math/cluster/RandomClustering.h

@@ -0,0 +1,112 @@
+/** 
+* @file RandomClustering.h
+* @brief Clustering by randomly picking some samples from the set of features as representatives
+* @author Alexander Freytag
+* @date 03-06-2013 (dd-mm-yyyy)
+*/
+#ifndef RANDOMCLUSTERERNINCLUDE
+#define RANDOMCLUSTERERNINCLUDE
+
+#include <core/basics/Config.h>
+#include <core/vector/Distance.h>
+#include <core/vector/MatrixT.h>
+#include <core/vector/VectorT.h>
+  
+#include "ClusterAlgorithm.h"
+
+namespace OBJREC {
+
+  /**
+   * @class RandomClustering
+   * @brief Clustering by randomly picking some samples from the set of features as representatives
+   * @author Alexander Freytag
+   * @date 03-06-2013 (dd-mm-yyyy)
+  */    
+  class RandomClustering : public ClusterAlgorithm
+  {
+
+      protected:
+        
+      /************************
+       * 
+       *   protected variables
+       * 
+       **************************/ 
+      
+        //! desired number of clusters
+        int noClusters;
+        
+        //! specify which distance to use for calculating assignments
+        std::string distanceType;
+        
+        //! the actual distance metric
+        NICE::VectorDistance<double> *distancefunction;        
+        
+  
+       /************************
+       * 
+       *   protected methods
+       * 
+       **************************/  
+      
+        
+        //! compute assignments of all given features wrt to the currently known prototypes (cluster medoids) == ~ E-step
+        double compute_assignments ( const NICE::VVector & features,
+                  const NICE::VVector & prototypes,
+                  std::vector<int> & assignment );
+
+        //! compute number of assignments for every currently found cluster
+        double compute_weights ( const NICE::VVector & features,
+              std::vector<double> & weights,
+              std::vector<int>    & assignment );
+
+
+        //! compute (update) prototypes given the current assignments == ~ M-step
+        int compute_prototypes ( const NICE::VVector & features,
+                NICE::VVector & prototypes,
+                std::vector<double> & weights,
+                const std::vector<int>    & assignment );
+
+      public:
+    
+        /**
+        * @brief simple constructor
+        * @param[in] _noClasses the number of clusters to be computed
+        * @param[in] _distanceMode a string specifying the distance function to be used (default: euclidean)* 
+        * @date 03-06-2013 (dd-mm-yyyy)
+        */
+        RandomClustering( const int & _noClasses , const std::string & _distanceMode="euclidean" );
+        
+        /**
+        * @brief standard constructor
+        * @param[in] conf config file specifying all relevant variable settings
+        * @param[in] _section name of the section within the configfile where the settings can be found (default: RandomClustering)
+        * @date 03-06-2013 (dd-mm-yyyy)
+        */
+        RandomClustering( const NICE::Config *conf, const std::string & _section = "RandomClustering");
+
+        
+            
+        /** simple destructor */
+        virtual ~RandomClustering();
+          
+        /**
+        * @brief this is the actual method that performs the clustering for a given set of features
+        * @author Alexander Freytag
+        * @date 03-06-2013 (dd-mm-yyyy)
+        * @param   features input features to be clustered
+        * @param   prototypes computed prototypes (randomly chosen) for the given samples
+        * @param   weights number of assignments for every cluster
+        * @param   assignment explicite assignments of features to computed cluster medoids
+        */        
+        void cluster ( const NICE::VVector & features,
+                NICE::VVector & prototypes,
+                std::vector<double> & weights,
+                std::vector<int>    & assignment );
+
+  };
+
+
+} // namespace
+
+#endif

+ 118 - 93
math/cluster/SpectralCluster.cpp

@@ -18,18 +18,24 @@ using namespace OBJREC;
 using namespace std;
 using namespace NICE;
 
-SpectralCluster::SpectralCluster ( int _noClasses, double alpha ) : noClasses(_noClasses), kmeans(_noClasses)
+SpectralCluster::SpectralCluster ( int _noClusters, double alpha ) : noClusters(_noClusters), kmeans(_noClusters)
 {
     this->alpha = alpha;
 }
 
+SpectralCluster::SpectralCluster( const NICE::Config *conf, const std::string & _section) : kmeans(conf)
+{  
+  this->noClusters = conf->gI( _section, "noClusters", 20);
+  this->alpha = conf->gD( _section, "alpha", 1.0);
+}
+
 SpectralCluster::~SpectralCluster()
 {
 }
 
 void SpectralCluster::getSimilarityMatrix ( const VVector & features, 
-					    NICE::Matrix & laplacian,
-					    double alpha )
+                                            NICE::Matrix & laplacian,
+                                            double alpha )
 {
     NICE::Matrix distances ( laplacian );
     double mindist = numeric_limits<double>::max();
@@ -41,48 +47,53 @@ void SpectralCluster::getSimilarityMatrix ( const VVector & features,
 
     for ( int i = 0 ; i < (int)features.size() ; i++ )
     {
-	const NICE::Vector & xi = features[i];
-	for ( int j = i ; j < (int)features.size() ; j++ )
-	{
-	    const NICE::Vector & xj = features[j];
-	    // double sim = xi * xj;
-	    double dist = distance.calculate ( xi, xj );
-	    distances(i, j) = dist;
-
-	    if ( dist < mindist )
-		mindist = dist;
-	    if ( dist > maxdist )
-		maxdist = dist;
-
-	    count++;
-	    mean += dist;
-	}
+      const NICE::Vector & xi = features[i];
+      for ( int j = i ; j < (int)features.size() ; j++ )
+      {
+          const NICE::Vector & xj = features[j];
+          // double sim = xi * xj;
+          double dist = distance.calculate ( xi, xj );
+          distances(i, j) = dist;
+
+          if ( dist < mindist )
+        mindist = dist;
+          if ( dist > maxdist )
+        maxdist = dist;
+
+          count++;
+          mean += dist;
+      }
     }
     mean /= count;
 
     for ( int i = 0 ; i < (int)features.size() ; i++ )
-	for ( int j = i ; j < (int)features.size() ; j++ )
-	{
-	    double d = ( mean - distances(i, j) );
-	    stddev += d*d;
-	}
+    {
+      for ( int j = i ; j < (int)features.size() ; j++ )
+      {
+          double d = ( mean - distances(i, j) );
+          stddev += d*d;
+      }
+    }
 
     stddev /= count;
 
     double norm = alpha / (2.0 * stddev);
 
     for ( int i = 0 ; i < (int)features.size() ; i++ )
-	for ( int j = i ; j < (int)features.size() ; j++ )
-	{
-	    double sim = exp(-distances(i, j) * norm );
-	    
-	    laplacian(i, j) = - sim;
-	    laplacian(j, i) = - sim;
-	}
+    {
+      for ( int j = i ; j < (int)features.size() ; j++ )
+      {
+          double sim = exp(-distances(i, j) * norm );
+          
+          laplacian(i, j) = - sim;
+          laplacian(j, i) = - sim;
+      }
+    }
 }
 
-void SpectralCluster::computeLaplacian ( const VVector & features,
-					 NICE::Matrix & laplacian, int method, double alpha )
+void SpectralCluster::computeLaplacian ( const NICE::VVector & features,
+                                         NICE::Matrix & laplacian,
+                                         int method, double alpha )
 {
     laplacian.set(0.0);
     getSimilarityMatrix(features, laplacian, alpha);
@@ -91,8 +102,10 @@ void SpectralCluster::computeLaplacian ( const VVector & features,
     d.set(0.0);
     for ( int i = 0 ; i < (int)laplacian.rows(); i++ )
     {
-		for ( int j = 0 ; j < (int)laplacian.cols(); j++ )
-	    	d[i] -=laplacian(i, j);
+      for ( int j = 0 ; j < (int)laplacian.cols(); j++ )
+      {
+          d[i] -=laplacian(i, j);
+      }
     }
 
     // Now we got the negative weight matrix laplacian : -W
@@ -102,31 +115,40 @@ void SpectralCluster::computeLaplacian ( const VVector & features,
     // D^-1 * L
     if ( method == L_RW_NORMALIZED ) 
     {
-	// L = D^-1 L_unnormalized = I - D^-1*W
-		for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
-			for ( int j = 0 ; j < (int)laplacian.cols() ; j++ )
-				laplacian(i, j) *= (1.0/d[i]);
-
-		for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
-	    	laplacian(i, i) += 1.0;
-
-    } else if ( method == L_UNNORMALIZED ) {
-	// unnormalized version
-	// L = D - W
-		for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
-	    	laplacian(i, i) += d[i];
+    // L = D^-1 L_unnormalized = I - D^-1*W
+      for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
+      {
+        for ( int j = 0 ; j < (int)laplacian.cols() ; j++ )
+        {
+          laplacian(i, j) *= (1.0/d[i]);
+        }
+      }
+
+      for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
+      {
+          laplacian(i, i) += 1.0;
+      }
+
+    }
+    else if ( method == L_UNNORMALIZED )
+    {
+    // unnormalized version
+    // L = D - W
+      for ( int i = 0 ; i < (int)laplacian.rows() ; i++ )
+      {
+          laplacian(i, i) += d[i];
+      }
     }
 }
 
-void SpectralCluster::cluster ( const VVector & features,
-				VVector & prototypes,
-				std::vector<double> & weights,
-				std::vector<int>    & assignment )
+void SpectralCluster::cluster ( const NICE::VVector & features,
+                                NICE::VVector & prototypes,
+                                std::vector<double> & weights,
+                                std::vector<int>    & assignment )
 {
-
     if ( features.size() <= 0 ) {
-	fprintf (stderr, "FATAL ERROR: not enough features vectors provided\n");
-	exit(-1);
+      fprintf (stderr, "FATAL ERROR: not enough features vectors provided\n");
+      exit(-1);
     }
 
     const NICE::Vector & x = features[0];
@@ -141,67 +163,70 @@ void SpectralCluster::cluster ( const VVector & features,
     NICE::Vector eigvals;
     try {
       NICE::eigenvectorvalues ( laplacian, eigvect, eigvals );
-    } catch (...) {
-      cerr << "You should adjust the alpha parameter, or the features are somehow weird" << endl;
-      cerr << "Laplacian = " << laplacian(0, 0, min((int)laplacian.rows()-1, 5), min((int)laplacian.cols()-1, 5)) << endl;
+    }
+    catch (...)
+    {
+      std::cerr << "You should adjust the alpha parameter, or the features are somehow weird" << std::endl;
+      std::cerr << "Laplacian = " << laplacian(0, 0, min((int)laplacian.rows()-1, 5), min((int)laplacian.cols()-1, 5)) << std::endl;
       throw Exception ("Laplacian matrix is singular or not well-conditioned!");
     }
 
     std::map<double, int> eigvals_sorted;
-	for ( int i = 0 ; i < (int)eigvals.size(); i++ ) 
+    for ( int i = 0 ; i < (int)eigvals.size(); i++ ) 
     {
-	eigvals_sorted.insert ( make_pair( eigvals[i], i ) );
+      eigvals_sorted.insert ( make_pair( eigvals[i], i ) );
     }
 
-    VVector spectral_features;
+    NICE::VVector spectral_features;
 
-	for ( int i = 0 ; i < (int)eigvect.rows() ; i++ )
+    for ( int i = 0 ; i < (int)eigvect.rows() ; i++ )
     {
-	NICE::Vector eigvec_k ( noClasses );
-	map<double, int>::const_iterator k = eigvals_sorted.begin();
-	for ( int j = 0 ; j < noClasses ; j++ )
-	{
-	    int eigval_index = k->second;
-	    eigvec_k[j] = eigvect(i, eigval_index ) ;
-	    k++;
-	}
-
-	spectral_features.push_back ( eigvec_k );
+      NICE::Vector eigvec_k ( noClusters );
+      map<double, int>::const_iterator k = eigvals_sorted.begin();
+      for ( int j = 0 ; j < noClusters ; j++ )
+      {
+        int eigval_index = k->second;
+        eigvec_k[j] = eigvect(i, eigval_index ) ;
+        k++;
+      }
+
+      spectral_features.push_back ( eigvec_k );
     }
 
-    kmeans.cluster ( spectral_features, prototypes, weights, assignment ); 
+    this->kmeans.cluster ( spectral_features, prototypes, weights, assignment ); 
 
     // recompute prototypes
 
-    for ( int k = 0 ; k < noClasses ; k++ )
+    for ( int k = 0 ; k < noClusters ; k++ )
     {
-	prototypes[k].resize( dimension );
-	prototypes[k].set(0);
-	weights[k] = 0;
+      prototypes[k].resize( dimension );
+      prototypes[k].set(0);
+      weights[k] = 0;
     }
 
     int j = 0;
     for ( VVector::const_iterator i  = features.begin();
-                                              i != features.end();
-	                                      i++, j++ )
+                                  i != features.end();
+                                  i++, j++ )
     {
-	int k = assignment[j];
-	
-	NICE::Vector & p = prototypes[k];
-	const NICE::Vector & x = *i;
-	p += x;
-	weights[k]++;
+      int k = assignment[j];
+      
+      NICE::Vector & p = prototypes[k];
+      const NICE::Vector & x = *i;
+      p += x;
+      weights[k]++;
     }
 
-    for ( int k = 0 ; k < noClasses ; k++ )
+    for ( int k = 0 ; k < noClusters ; k++ )
     {
-	NICE::Vector & p = prototypes[k];
-	if ( weights[k] <= 0 ) {
-	    fprintf (stderr, "FATAL ERROR: spectral clustering produced empty cluster !\n");
-	    exit(-1);
-	}
-	p *= ( 1.0 / weights[k] );
-	weights[k] = weights[k] / features.size();
+      NICE::Vector & p = prototypes[k];
+      if ( weights[k] <= 0 )
+      {
+          fprintf (stderr, "FATAL ERROR: spectral clustering produced empty cluster !\n");
+          exit(-1);
+      }
+      p *= ( 1.0 / weights[k] );
+      weights[k] = weights[k] / features.size();
     }
 }
 

+ 47 - 38
math/cluster/SpectralCluster.h

@@ -8,8 +8,8 @@
 #ifndef SPECTRALCLUSTERINCLUDE
 #define SPECTRALCLUSTERINCLUDE
 
-#include "core/vector/VectorT.h"
-#include "core/vector/MatrixT.h"
+#include <core/vector/VectorT.h>
+#include <core/vector/MatrixT.h>
 
 #include "ClusterAlgorithm.h"
 #include "KMeans.h"
@@ -17,42 +17,51 @@
 
 namespace OBJREC {
 
-/** spectral clustering by kmeans-clustering of eigenvectors */
-class SpectralCluster : public ClusterAlgorithm
-{
-
-    protected:
-	int noClasses;
-	double alpha;
-
-	KMeans kmeans;
-
-	enum {
-	    L_UNNORMALIZED  = 0,
-	    L_RW_NORMALIZED 
-	};
-
-	virtual void computeLaplacian ( const NICE::VVector & features,
-					 NICE::Matrix & laplacian,
-					 int method, double alpha );
-
-
-	virtual void getSimilarityMatrix ( const NICE::VVector & features, 
-					    NICE::Matrix & laplacian, double alpha );
-    public:
-  
-	/** simple constructor */
-	SpectralCluster (int _noClasses, double alpha);
-      
-	/** simple destructor */
-	virtual ~SpectralCluster();
-     
-	void cluster ( const NICE::VVector & features,
-		       NICE::VVector & prototypes,
-		       std::vector<double> & weights,
-		       std::vector<int>    & assignment );
-
-};
+  /** spectral clustering by kmeans-clustering of eigenvectors */
+  class SpectralCluster : public ClusterAlgorithm
+  {
+
+      protected:
+        int noClusters;
+        double alpha;
+
+        KMeans kmeans;
+
+        enum {
+            L_UNNORMALIZED  = 0,
+            L_RW_NORMALIZED 
+        };
+
+        virtual void computeLaplacian ( const NICE::VVector & features,
+                NICE::Matrix & laplacian,
+                int method, double alpha );
+
+
+        virtual void getSimilarityMatrix ( const NICE::VVector & features, 
+                    NICE::Matrix & laplacian, double alpha );
+      public:
+    
+        /** simple constructor */
+        SpectralCluster (int _noClusters, double alpha);
+        
+        /**
+        * @brief standard constructor
+        * @param conf config file specifying all relevant variable settings
+        * @param _section name of the section within the configfile where the settings can be found (default: SpectralCluster)
+        * @date 14-06-2013 (dd-mm-yyyy)
+        * @author Alexander Freytag
+        */
+        SpectralCluster( const NICE::Config *conf, const std::string & _section = "SpectralCluster");     
+            
+        /** simple destructor */
+        virtual ~SpectralCluster();
+          
+        void cluster ( const NICE::VVector & features,
+                NICE::VVector & prototypes,
+                std::vector<double> & weights,
+                std::vector<int>    & assignment );
+
+  };
 
 
 } // namespace

+ 89 - 0
math/cluster/tests/Makefile.inc

@@ -0,0 +1,89 @@
+# BINARY-DIRECTORY-MAKEFILE
+# conventions:
+# - there are no subdirectories, they are ignored!
+# - all ".C", ".cpp" and ".c" files in the current directory are considered
+#   independent binaries, and linked as such.
+# - the binaries depend on the library of the parent directory
+# - the binary names are created with $(BINNAME), i.e. it will be more or less
+#   the name of the .o file
+# - all binaries will be added to the default build list ALL_BINARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+#SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+#include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# include the libdepend.inc file, which gives additional dependencies for the
+# libraries and binaries. additionally, an automatic dependency from the library
+# of the parent directory is added (commented out in the code below).
+
+-include $(SUBDIR)libdepend.inc
+
+PARENTDIR:=$(patsubst %/,%,$(dir $(patsubst %/,%,$(SUBDIR))))
+$(call PKG_DEPEND_INT,$(PARENTDIR))
+$(call PKG_DEPEND_EXT,CPPUNIT)
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+      $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+CHECKS:=$(BINDIR)$(call LIBNAME,$(SUBDIR))
+ALL_CHECKS+=$(CHECKS)
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. each binary depends on the corresponding .o file and
+# on the libraries specified by the INTLIBS/EXTLIBS. these dependencies can be
+# specified manually or they are automatically stored in a .bd file.
+
+$(foreach head,$(wildcard $(SUBDIR)*.h),$(eval $(shell grep -q Q_OBJECT $(head) && echo $(head) | sed -e's@^@/@;s@.*/\(.*\)\.h$$@$(BINDIR)\1:$(OBJDIR)moc_\1.o@')))
+$(eval $(foreach c,$(CHECKS),$(c):$(BUILDDIR)$(CPPUNIT_MAIN_OBJ) $(OBJS) $(call PRINT_INTLIB_DEPS,$(c),.a)))
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 89 - 0
math/cluster/tests/TestKMedian.cpp

@@ -0,0 +1,89 @@
+#ifdef NICE_USELIB_CPPUNIT
+
+#include <string>
+#include <exception>
+
+#include "TestKMedian.h"
+
+#include <core/basics/Config.h>
+#include "vislearning/math/distances/genericDistance.h"
+
+
+const bool verboseStartEnd = true;
+const bool verbose = false;
+const std::string distanceType = "euclidean";
+
+using namespace OBJREC;
+using namespace NICE;
+using namespace std;
+
+CPPUNIT_TEST_SUITE_REGISTRATION( TestKMedian );
+
+void TestKMedian::setUp() {
+}
+
+void TestKMedian::tearDown() {
+}
+
+void TestKMedian::testKMedianClustering() 
+{
+  if (verboseStartEnd)
+    std::cerr << "================== TestKMedian::testKMedianClustering ===================== " << std::endl;
+  
+  Config * conf = new Config;
+  std::string section ( "KMedian" );
+  conf->sS( section, "distanceType", "euclidean" );
+  conf->sI( section, "maxIterations", 200 );
+  conf->sI( section, "noClusters", 2 );
+   
+  OBJREC::KMedian kMedian ( conf, section );
+  
+  //create some artificial data
+  NICE::VVector features;
+  NICE::Vector x1 (2); x1[0] = 1;  x1[1] = 1; features.push_back(x1);
+  NICE::Vector x2 (2); x2[0] = 4;  x2[1] = 1; features.push_back(x2);
+  NICE::Vector x3 (2); x3[0] = 2;  x3[1] = 4; features.push_back(x3);
+  NICE::Vector x4 (2); x4[0] = 10; x4[1] = 3; features.push_back(x4);
+  NICE::Vector x5 (2); x5[0] = 8;  x5[1] = 3; features.push_back(x5);
+  NICE::Vector x6 (2); x6[0] = 4;  x6[1] = 3; features.push_back(x6);
+  NICE::Vector x7 (2); x7[0] = 3;  x7[1] = 2; features.push_back(x7);
+  NICE::Vector x8 (2); x8[0] = 1;  x8[1] = 3; features.push_back(x8);
+  NICE::Vector x9 (2); x9[0] = 9;  x9[1] = 2; features.push_back(x9);
+  
+  //cluster data
+  NICE::VVector prototypes;
+  std::vector<double> weights;
+  std::vector<int> assignment;
+  
+  kMedian.cluster ( features, prototypes, weights, assignment );  
+
+  //check whether the results fits the ground truth  
+  //NOTE
+  // If no random initialization is activated, we initially grab x2 and x8.
+  // After 3 iterations, we should have converged and obtain x5 and x7.
+
+  NICE::VectorDistance<double> * distancefunction = GenericDistanceSelection::selectDistance(distanceType);
+
+  if ( verbose )
+  {
+    std::cerr << " x9: " << x9 << " cl1: " << prototypes[0] << std::endl;
+    std::cerr << " x7: " << x7 << " cl2: " << prototypes[1] << std::endl;
+  }
+  
+  double distX9Cl1 ( distancefunction->calculate( x9, prototypes[0] ) );
+  double distX7Cl2 ( distancefunction->calculate( x7, prototypes[1] ) );
+  
+  CPPUNIT_ASSERT_DOUBLES_EQUAL( distX9Cl1, 0.0, 1e-8);
+  CPPUNIT_ASSERT_DOUBLES_EQUAL( distX7Cl2, 0.0, 1e-8); 
+  
+  std::cerr << "                               successfull              " << std::endl;
+        
+  //don't waste memory
+  delete conf;
+  
+  if (verboseStartEnd)
+    std::cerr << "================== TestKMedian::testKMedianClustering done ===================== " << std::endl;
+}
+
+
+#endif

+ 32 - 0
math/cluster/tests/TestKMedian.h

@@ -0,0 +1,32 @@
+#ifndef _TESTKMEDIAN_H
+#define _TESTKMEDIAN_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "vislearning/math/cluster/KMedian.h"
+
+/**
+ * CppUnit-Testcase. 
+ * @brief CppUnit-Testcase to verify that the KMedian-clusterin works correctly
+ */
+class TestKMedian : public CppUnit::TestFixture {
+
+    CPPUNIT_TEST_SUITE( TestKMedian );
+    
+    CPPUNIT_TEST(testKMedianClustering);
+    
+    CPPUNIT_TEST_SUITE_END();
+  
+ private:
+ 
+ public:
+    void setUp();
+    void tearDown();
+
+    /**
+    * Constructor / Destructor testing 
+    */  
+    void testKMedianClustering();
+
+};
+
+#endif // _TESTKMEDIAN_H

+ 8 - 0
noveltyDetection/Makefile

@@ -0,0 +1,8 @@
+#TARGETS_FROM:=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM)
+#$(info recursivly going up: $(TARGETS_FROM) ($(shell pwd)))
+
+all:
+
+%:
+	$(MAKE) TARGETS_FROM=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM) -C .. $@
+

+ 103 - 0
noveltyDetection/Makefile.inc

@@ -0,0 +1,103 @@
+# LIBRARY-DIRECTORY-MAKEFILE
+# conventions:
+# - all subdirectories containing a "Makefile.inc" are considered sublibraries
+#   exception: "progs/" and "tests/" subdirectories!
+# - all ".C", ".cpp" and ".c" files in the current directory are linked to a
+#   library
+# - the library depends on all sublibraries 
+# - the library name is created with $(LIBNAME), i.e. it will be somehow
+#   related to the directory name and with the extension .a
+#   (e.g. lib1/sublib -> lib1_sublib.a)
+# - the library will be added to the default build list ALL_LIBRARIES
+
+# --------------------------------
+# - remember the last subdirectory
+#
+# set the variable $(SUBDIR) correctly to the current subdirectory. this
+# variable can be used throughout the current makefile.inc. The many 
+# SUBDIR_before, _add, and everything are only required so that we can recover
+# the previous content of SUBDIR before exitting the makefile.inc
+
+SUBDIR_add:=$(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+SUBDIR_before:=$(SUBDIR)
+SUBDIR:=$(strip $(SUBDIR_add))
+SUBDIR_before_$(SUBDIR):=$(SUBDIR_before)
+ifeq "$(SUBDIR)" "./"
+SUBDIR:=
+endif
+
+# ------------------------
+# - include subdirectories
+#
+# note the variables $(SUBDIRS_OF_$(SUBDIR)) are required later on to recover
+# the dependencies automatically. if you handle dependencies on your own, you
+# can also dump the $(SUBDIRS_OF_$(SUBDIR)) variable, and include the
+# makefile.inc of the subdirectories on your own...
+
+SUBDIRS_OF_$(SUBDIR):=$(patsubst %/Makefile.inc,%,$(wildcard $(SUBDIR)*/Makefile.inc))
+include $(SUBDIRS_OF_$(SUBDIR):%=%/Makefile.inc)
+
+# ----------------------------
+# - include local dependencies
+#
+# you can specify libraries needed by the individual objects or by the whole
+# directory. the object specific additional libraries are only considered
+# when compiling the specific object files
+# TODO: update documentation...
+
+-include $(SUBDIR)libdepend.inc
+
+$(foreach d,$(filter-out %progs %tests,$(SUBDIRS_OF_$(SUBDIR))),$(eval $(call PKG_DEPEND_INT,$(d))))
+
+# ---------------------------
+# - objects in this directory
+#
+# the use of the variable $(OBJS) is not mandatory. it is mandatory however
+# to update $(ALL_OBJS) in a way that it contains the path and name of
+# all objects. otherwise we can not include the appropriate .d files.
+
+OBJS:=$(patsubst %.cpp,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.cpp))) \
+      $(patsubst %.C,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.C))) \
+	  $(shell grep -ls Q_OBJECT $(SUBDIR)*.h | sed -e's@^@/@;s@.*/@$(OBJDIR)moc_@;s@\.h$$@.o@') \
+      $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(wildcard $(SUBDIR)*.c)))
+ALL_OBJS += $(OBJS)
+
+# ----------------------------
+# - binaries in this directory
+#
+# output of binaries in this directory. none of the variables has to be used.
+# but everything you add to $(ALL_LIBRARIES) and $(ALL_BINARIES) will be
+# compiled with `make all`. be sure again to add the files with full path.
+
+LIBRARY_BASENAME:=$(call LIBNAME,$(SUBDIR))
+ifneq "$(SUBDIR)" ""
+ALL_LIBRARIES+=$(LIBDIR)$(LIBRARY_BASENAME).$(LINK_FILE_EXTENSION)
+endif
+
+# ---------------------
+# - binary dependencies
+#
+# there is no way of determining the binary dependencies automatically, so we
+# follow conventions. the current library depends on all sublibraries.
+# all other dependencies have to be added manually by specifying, that the
+# current .pc file depends on some other .pc file. binaries depending on
+# libraries should exclusivelly use the .pc files as well.
+
+ifeq "$(SKIP_BUILD_$(OBJDIR))" "1"
+$(LIBDIR)$(LIBRARY_BASENAME).a:
+else
+$(LIBDIR)$(LIBRARY_BASENAME).a:$(OBJS) \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).a,.$(LINK_FILE_EXTENSION))
+endif
+
+$(PKGDIR)$(LIBRARY_BASENAME).pc: \
+	$(call PRINT_INTLIB_DEPS,$(PKGDIR)$(LIBRARY_BASENAME).pc,.pc)
+
+# -------------------
+# - subdir management
+#
+# as the last step, always add this line to correctly recover the subdirectory
+# of the makefile including this one!
+
+SUBDIR:=$(SUBDIR_before_$(SUBDIR))
+

+ 72 - 0
noveltyDetection/NDCodebookLevelImagePooling.cpp

@@ -0,0 +1,72 @@
+
+#include "NDCodebookLevelImagePooling.h"
+
+//STL
+#include <iostream>
+
+//core
+#include <core/vector/VectorT.h>
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+
+  //**********************************************
+  //
+  //                 PROTECTED METHODS
+  //
+  //********************************************** 
+
+
+
+  //**********************************************
+  //
+  //                 PUBLIC METHODS
+  //
+  //********************************************** 
+
+
+NDCodebookLevelImagePooling::NDCodebookLevelImagePooling ( const Config *_conf,
+                               const MultiDataset *_md, const std::string & _section )
+    : NoveltyDetectorCodebookLevel ( _conf, _md, _section )
+{ 
+  this->section = _section;
+//   d_noveltyThreshold = conf->gD ( section , "noveltyThreshold", 0.0064 );  
+  d_noveltyThreshold = conf->gD ( section , "stupidNoveltyThreshold", 0.0064 );  
+}
+
+NDCodebookLevelImagePooling::~NDCodebookLevelImagePooling()
+{
+}
+
+bool NDCodebookLevelImagePooling::evaluateNoveltyOfImage ( const std::string & _filename )
+{
+  ROADWORKSNOVDET;
+}
+
+bool NDCodebookLevelImagePooling::evaluateNoveltyOfImage ( const NICE::FloatImage & _noveltyImage )
+{
+    double meanNovelty ( 0.0 );
+    for ( uint y = 0 ; y < ( uint ) _noveltyImage.height() ; y++ )
+    {
+      for ( uint x = 0 ; x < ( uint ) _noveltyImage.width(); x++ )
+      {
+        meanNovelty += _noveltyImage(x,y);
+      }
+    }      
+    int imageSize ( _noveltyImage.height() * _noveltyImage.width() );
+    meanNovelty /= imageSize;
+
+      std::cerr << "  NOVELTY SCORE FOR CURRENT IMAGE: " <<  meanNovelty << " -- threshold: " << d_noveltyThreshold << std::endl;    
+    
+    if ( meanNovelty < d_noveltyThreshold )
+    {
+      // --- NOT NOVEL ---
+      return false;
+    }
+    else
+    {
+      // --- NOVEL ---
+      return true;
+    }
+}

+ 97 - 0
noveltyDetection/NDCodebookLevelImagePooling.h

@@ -0,0 +1,97 @@
+/**
+ * @file NDCodebookLevelImagePooling.h
+ * @brief Compute novelty of images based on relations between extracted features and current codebook, pool novelty scores over the whole image without considering spatial information
+ * @author Alexander Freytag
+ * @date 02-05-2013 (dd-mm-yyyy)
+*/
+#ifndef _NDCODEBOOKLEVELIMAGEPOOLING
+#define _NDCODEBOOKLEVELIMAGEPOOLING
+
+#include "NoveltyDetectorCodebookLevel.h"
+
+//core
+#include <core/vector/Distance.h>
+#include <core/vector/VVector.h>
+
+// vislearning
+#include <vislearning/cbaselib/MultiDataset.h>
+// 
+#include <vislearning/features/localfeatures/GenericLocalFeatureSelection.h>
+// 
+#include <vislearning/math/cluster/ClusterAlgorithm.h>
+
+
+
+
+namespace OBJREC
+{
+
+  /**
+   * @class NDCodebookLevelImagePooling
+   * @brief Compute novelty of images based on relations between extracted features and current codebook, pool novelty scores over the whole image without considering spatial information
+   * @author Alexander Freytag
+   * @date 02-05-2013 (dd-mm-yyyy)
+  */  
+  
+  class NDCodebookLevelImagePooling : public NoveltyDetectorCodebookLevel
+  {
+
+    protected:
+      
+      /************************
+       * 
+       *   protected variables
+       * 
+       **************************/       
+      
+      //TODO ENUM HOW TO POOL
+      
+      //! this is the (stupid) global threshold for novelty within an image (i.e., if novelty scores summed over all pixels and divided by image size is larger than this score, the image is considered as "novel")      
+      double d_noveltyThreshold;
+                       
+      
+      /************************
+       * 
+       *   protected methods
+       * 
+       **************************/
+    
+
+
+    public:
+
+      /** constructor
+        * @param _conf needs a configfile
+        * @param _md and a MultiDataset (contains images and other things)
+        * @param _section section information for parsing config files
+        */
+      NDCodebookLevelImagePooling ( const NICE::Config *_conf, const OBJREC::MultiDataset *_md , const std::string & _section = "noveltyDetector");
+
+      /** simple destructor */
+      virtual ~NDCodebookLevelImagePooling();
+      
+      /** 
+       * @brief  Evaluate whether or not the image of the specified filename is novel with respect to the current known examples or not
+       * @author Alexander Freytag
+       * @date 02-05-2013 (dd-mm-yyyy)
+       * @param _filename of the new image 
+       * @return bool (true: class/content/... of image is novel, false: class/content/... of image is known)
+       * @note This function has to be overloaded by all subclasses!          
+      */
+      virtual bool evaluateNoveltyOfImage ( const std::string & _filename );
+      
+      /** 
+       * @brief  Evaluate whether or not the image of the specified filename is novel with respect to the current known examples or not
+       * @author Alexander Freytag
+       * @date 02-05-2013 (dd-mm-yyyy)
+       * @param _noveltyImage contains min distances of features to the current codebook
+       * @return bool (true: class/content/... of image is novel, false: class/content/... of image is known)
+      */      
+      virtual bool evaluateNoveltyOfImage ( const NICE::FloatImage & _noveltyImage ) ;                  
+
+  };
+
+
+} // namespace
+
+#endif

+ 24 - 0
noveltyDetection/NoveltyDetector.cpp

@@ -0,0 +1,24 @@
+/**
+* @file NoveltyDetector.cpp
+* @brief abstract interface for novelty detection algorithms
+* @author Alexander Freytag
+* @date 16-04-2013 (dd-mm-yyyy)
+
+*/
+#include <iostream>
+
+#include "NoveltyDetector.h"
+
+using namespace OBJREC;
+using namespace std;
+using namespace NICE;
+
+NoveltyDetector::NoveltyDetector ( const Config *_conf, const std::string & _section )
+{
+  this->section = _section;  
+  this->conf = _conf;  
+}
+
+NoveltyDetector::~NoveltyDetector()
+{
+}

+ 84 - 0
noveltyDetection/NoveltyDetector.h

@@ -0,0 +1,84 @@
+/**
+ * @file NoveltyDetector.h
+ * @brief abstract interface for novelty detection algorithms
+ * @author Alexander Freytag
+ * @date 02-05-2013 (dd-mm-yyyy)
+*/
+#ifndef _INCLUDENOVELTYDETECTOR
+#define _INCLUDENOVELTYDETECTOR
+
+#define ROADWORKSNOVDET fthrow(NICE::Exception, "Novelty Detector -- not yet implemented!");
+
+// STL
+#include <string>
+
+//core
+#include <core/basics/Config.h>
+
+
+namespace OBJREC
+{
+
+  /**
+   * @class NoveltyDetector
+   * @brief abstract interface for novelty detection algorithms
+   * @author Alexander Freytag
+   * @date 02-05-2013 (dd-mm-yyyy)
+  */
+  class NoveltyDetector
+  {
+
+    protected:   
+      
+      /************************
+       * 
+       *   protected variables
+       * 
+       **************************/       
+      
+      //! section information for parsing config files
+      std::string section;      
+      
+      //! Configuration File
+      const NICE::Config *conf;    
+           
+      
+      /************************
+       * 
+       *   protected methods
+       * 
+       **************************/      
+            
+
+    public:
+
+      /**
+       * @brief  simple constructor
+       * @author Alexander Freytag
+       * @date 02-05-2013 (dd-mm-yyyy)
+       * @param _conf global settings
+       * @param _section section information for parsing config files
+      */
+      NoveltyDetector ( const NICE::Config *_conf, const std::string & _section = "noveltyDetector" );
+
+      /** simple destructor */
+      virtual ~NoveltyDetector();
+
+      
+      /** 
+       * @brief  Evaluate whether or not the image of the specified filename is novel with respect to the current known examples or not
+       * @author Alexander Freytag
+       * @date 02-05-2013 (dd-mm-yyyy)
+       * @param _filename of the new image 
+       * @return bool (true: class/content/... of image is novel, false: class/content/... of image is known)
+       * @note This function has to be overloaded by all subclasses!          
+      */
+      virtual bool evaluateNoveltyOfImage ( const std::string & _filename) = 0;  
+      
+
+  };
+
+
+} // namespace
+
+#endif

+ 230 - 0
noveltyDetection/NoveltyDetectorCodebookLevel.cpp

@@ -0,0 +1,230 @@
+
+#include "NoveltyDetectorCodebookLevel.h"
+
+//STL
+#include <iostream>
+
+//core
+#include <core/vector/VectorT.h>
+
+//vislearning
+#include <vislearning/features/localfeatures/LFonHSG.h>
+#include <vislearning/features/localfeatures/LFColorSande.h>
+#include <vislearning/features/localfeatures/LFColorWeijer.h>
+#include <vislearning/features/localfeatures/LFReadCache.h>
+#include <vislearning/features/localfeatures/LFWriteCache.h>
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+
+  //**********************************************
+  //
+  //                 PROTECTED METHODS
+  //
+  //********************************************** 
+
+
+void NoveltyDetectorCodebookLevel::setFeatureExtractor( const bool & _setForTraining )
+{  
+  //be careful with previously allocated memory
+  if (this->featureExtractor != NULL)
+    delete featureExtractor;  
+  
+    //feature stuff
+  // which OpponentSIFT implementation to use {NICE, VANDESANDE}
+  std::string opSiftImpl;  
+  opSiftImpl = this->conf->gS ( "Descriptor", "implementation", "VANDESANDE" );
+  // read features?
+  bool readfeat;
+  readfeat = this->conf->gB ( "Descriptor", "read", true );
+  // write features?
+  bool writefeat;  
+  writefeat = this->conf->gB ( "Descriptor", "write", true );   
+  
+  // Welche Opponentsift Implementierung soll genutzt werden ?
+  LocalFeatureRepresentation *cSIFT = NULL;
+  LocalFeatureRepresentation *writeFeats = NULL;
+  LocalFeatureRepresentation *readFeats = NULL;
+  this->featureExtractor = NULL;
+  if ( opSiftImpl == "NICE" )
+  {
+    if ( _setForTraining )
+      cSIFT = new OBJREC::LFonHSG ( this->conf, "HSGtrain" );
+    else
+      cSIFT = new OBJREC::LFonHSG ( this->conf, "HSGtest" );
+  }
+  else if ( opSiftImpl == "VANDESANDE" )
+  {
+    if ( _setForTraining )
+      cSIFT = new OBJREC::LFColorSande ( this->conf, "LFColorSandeTrain" );
+    else
+      cSIFT = new OBJREC::LFColorSande ( this->conf, "LFColorSandeTest" );
+  }
+  else
+  {
+    fthrow ( Exception, "feattype: %s not yet supported" << opSiftImpl );
+  }
+
+  this->featureExtractor = cSIFT;
+  
+  if ( writefeat )
+  {
+    // write the features to a file, if there isn't any to read
+    writeFeats = new LFWriteCache ( this->conf, cSIFT );
+    this->featureExtractor = writeFeats;
+  }
+
+  if ( readfeat )
+  {
+    // read the features from a file
+    if ( writefeat )
+    {
+      readFeats = new LFReadCache ( this->conf, writeFeats, -1 );
+    }
+    else
+    {
+      readFeats = new LFReadCache ( this->conf, cSIFT, -1 );
+    }
+    this->featureExtractor = readFeats; 
+  }  
+  
+  //only set feature stuff to NULL, deletion of the underlying object is done in the destructor
+  if ( cSIFT != NULL )
+    cSIFT = NULL;
+  if ( writeFeats != NULL )
+    writeFeats = NULL;
+  if ( readFeats != NULL )
+    readFeats  = NULL ;   
+}
+
+
+
+bool NoveltyDetectorCodebookLevel::loadInitialCodebook ( )
+{
+  if ( b_loadInitialCodebook  )
+  {
+    std::cerr << " INITIAL CODEBOOK ALREADY COMPUTED - RE-USE IT" << std::endl;    
+    std::cerr << " // WARNING - WE DO NOT VERIFY WHETHER THIS IS THE CORRECT CODEBOOK FOR THIS TRAINING SET!!!!" << std::endl;    
+    
+    prototypes->clear();
+    
+    try
+    {
+      prototypes->read(cacheInitialCodebook);
+    }
+    catch (...)
+    {
+      std::cerr << "Error while loading initial codebook" << std::endl;
+      return false;
+    }  
+    return true;
+  }
+  else
+    return false;
+}
+
+bool NoveltyDetectorCodebookLevel::writeInitialCodebook ( )
+{      
+  if (  b_saveInitialCodebook )
+  {
+    std::cerr << " SAVE INITIAL CODEBOOK " << std::endl;
+    
+    try 
+    {
+      prototypes->write( cacheInitialCodebook );
+    }
+    catch (...)
+    {
+      std::cerr << "Error while saving initial codebook" << std::endl;
+      return false;
+    }    
+    return true;
+  } 
+  else
+    return false;
+}
+
+
+  //**********************************************
+  //
+  //                 PUBLIC METHODS
+  //
+  //********************************************** 
+
+
+NoveltyDetectorCodebookLevel::NoveltyDetectorCodebookLevel ( const Config *_conf,
+                               const MultiDataset *_md, const std::string & _section )
+    : NoveltyDetector ( _conf, _section )
+{ 
+  // define the distance function to be used
+  std::string distFunctionString = conf->gS(section, "distFunction", "euclidian");    
+  
+  
+  //**********************************************
+  //
+  //      SET UP VARIABLES AND METHODS
+  //             - FEATURE TYPE
+  //             - DISTANCE FUNCTION
+  //             - ...
+  //
+  //**********************************************  
+  
+  
+  if (distFunctionString.compare("euclidian") == 0)
+  {
+    distFunction = new NICE::EuclidianDistance<double>();
+  }
+  else
+  {
+    std::cerr << "Unknown vector distance selected, use euclidian instead" << std::endl;
+    distFunction = new NICE::EuclidianDistance<double>();
+  }    
+
+  //feature extraction for comparison against codebook
+  this->featureExtractor = NULL;
+  //feature extraction for unseen images
+  this->setFeatureExtractor( false /* set for training */ );    
+  
+  this->prototypes = NULL;  
+}
+
+NoveltyDetectorCodebookLevel::~NoveltyDetectorCodebookLevel()
+{
+  // clean-up
+  if ( distFunction != NULL )
+    delete distFunction;
+  if ( featureExtractor != NULL )
+    delete featureExtractor; 
+  if ( ( ! externalCodebook ) && (prototypes != NULL) )
+    delete prototypes;
+}
+
+void NoveltyDetectorCodebookLevel::setCodebook( NICE::VVector * _prototypes)
+{
+  std::cerr << "aim to set codebook" << std::endl;
+  // if we had no codebook so far, we simply store the pointer and remember, that we use the external one
+  // such that we do not have to delete it lateron
+  if ( this->prototypes == NULL)
+  {
+    std::cerr << "previous codebook is null -- set it as external codebook" << std::endl;
+    this->prototypes = _prototypes;
+    this->externalCodebook = true;
+  }
+  else
+  {
+    std::cerr << "previous codebook is not null - do we want to treat the new one as external?" << std::endl;
+    //in case of an internal codebook, we need to copy the whole thing
+    if ( ! externalCodebook )
+    {
+      *(this->prototypes) = *_prototypes;
+      std::cerr << "new codebook treated as internal codebook" << std::endl;
+    }
+    //if we use a pointer to an external codebook, we simply renew the pointer
+    else
+    {
+      this->prototypes = _prototypes;
+      std::cerr << "new codebook treated as external codebook " << std::endl;
+    }
+  }
+}

+ 125 - 0
noveltyDetection/NoveltyDetectorCodebookLevel.h

@@ -0,0 +1,125 @@
+/**
+ * @file NoveltyDetectorCodebookLevel.h
+ * @brief Compute novelty of images based on relations between extracted features and current codebook
+ * @author Alexander Freytag
+ * @date 02-05-2013 (dd-mm-yyyy)
+*/
+#ifndef _INCLUDENOVELTYDETECTIONCODEBOOKLEVEL
+#define _INCLUDENOVELTYDETECTIONCODEBOOKLEVEL
+
+#include "NoveltyDetector.h"
+
+//core
+#include <core/vector/Distance.h>
+#include <core/vector/VVector.h>
+
+// vislearning
+#include <vislearning/cbaselib/MultiDataset.h>
+// 
+#include <vislearning/features/localfeatures/GenericLocalFeatureSelection.h>
+// 
+#include <vislearning/math/cluster/ClusterAlgorithm.h>
+
+
+
+
+namespace OBJREC
+{
+
+  /**
+   * @class NoveltyDetectorCodebookLevel
+   * @brief Compute novelty of images based on relations between extracted features and current codebook
+   * @author Alexander Freytag
+   * @date 02-05-2013 (dd-mm-yyyy)
+  */  
+  
+  class NoveltyDetectorCodebookLevel : public NoveltyDetector
+  {
+
+    protected:
+      
+      /************************
+       * 
+       *   protected variables
+       * 
+       **************************/       
+             
+      NICE::VectorDistance<double> * distFunction;
+
+      LocalFeatureRepresentation * featureExtractor;
+      
+      //! The currently known "cluster" centers, which are used for BoW histogram computation  (i.e., the codebook)
+      NICE::VVector * prototypes;   
+      
+      //! was an initial codebook already computed?
+      bool b_loadInitialCodebook;
+      //!shall the initially computed codebook be stored somewhere?
+      bool  b_saveInitialCodebook; 
+      //! where should an initial codebook be located, i.e., read from and written to?
+      std::string cacheInitialCodebook;  
+      
+      //! did we compute a codebook on our own or do we use simply a pointer to an external codebook?
+      bool externalCodebook;
+                       
+      
+      /************************
+       * 
+       *   protected methods
+       * 
+       **************************/
+            
+      void setFeatureExtractor( const bool & _setForTraining = false);
+      
+      void extractFeaturesFromTrainingImages(  const OBJREC::MultiDataset *_md,  NICE::VVector & examplesTraining  ); 
+      
+      virtual bool loadInitialCodebook ( );
+      virtual bool writeInitialCodebook ( );      
+
+
+    public:
+
+      /** constructor
+        * @param _conf needs a configfile
+        * @param _md and a MultiDataset (contains images and other things)
+        * @param _section section information for parsing config files
+        */
+      NoveltyDetectorCodebookLevel ( const NICE::Config *_conf, const OBJREC::MultiDataset *_md , const std::string & _section = "noveltyDetector");
+
+      /** simple destructor */
+      virtual ~NoveltyDetectorCodebookLevel();
+      
+      /** 
+       * @brief  Evaluate whether or not the image of the specified filename is novel with respect to the current known examples or not
+       * @author Alexander Freytag
+       * @date 02-05-2013 (dd-mm-yyyy)
+       * @param _filename of the new image 
+       * @return bool (true: class/content/... of image is novel, false: class/content/... of image is known)
+       * @note This function has to be overloaded by all subclasses!          
+      */
+      virtual bool evaluateNoveltyOfImage ( const std::string & _filename ) = 0;
+      
+      /** 
+       * @brief  Evaluate whether or not the image of the specified filename is novel with respect to the current known examples or not
+       * @author Alexander Freytag
+       * @date 02-05-2013 (dd-mm-yyyy)
+       * @param _noveltyImage contains min distances of features to the current codebook
+       * @return bool (true: class/content/... of image is novel, false: class/content/... of image is known)
+      */      
+      virtual bool evaluateNoveltyOfImage ( const NICE::FloatImage & _noveltyImage ) = 0;
+      
+      /** 
+       * @brief  Hand over a previously computed codebook
+       * @author Alexander Freytag
+       * @date 02-05-2013 (dd-mm-yyyy)
+       * @param _prototypes pointer to a codebook
+       * @note we check whether we just use the pointer to the external codebook, or alternatively copy it and have it as internal codebook available lateron
+      */            
+      virtual void setCodebook( NICE::VVector * _prototypes);
+            
+
+  };
+
+
+} // namespace
+
+#endif

+ 6 - 0
noveltyDetection/libdepend.inc

@@ -0,0 +1,6 @@
+$(call PKG_DEPEND_INT,core/)
+$(call PKG_DEPEND_INT,vislearning/baselib/)
+$(call PKG_DEPEND_INT,vislearning/cbaselib/)
+$(call PKG_DEPEND_INT,vislearning/features/)
+$(call PKG_DEPEND_INT,vislearning/math/)
+$(call PKG_DEPEND_INT,segmentation/)

+ 8 - 0
noveltyDetection/progs/Makefile

@@ -0,0 +1,8 @@
+#TARGETS_FROM:=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM)
+#$(info recursivly going up: $(TARGETS_FROM) ($(shell pwd)))
+
+all:
+
+%:
+	$(MAKE) TARGETS_FROM=$(notdir $(patsubst %/,%,$(shell pwd)))/$(TARGETS_FROM) -C .. $@
+

+ 5 - 0
noveltyDetection/progs/libdepend.inc

@@ -0,0 +1,5 @@
+$(call PKG_DEPEND_INT,vislearning/baselib/)
+$(call PKG_DEPEND_INT,vislearning/cbaselib/)
+$(call PKG_DEPEND_INT,vislearning/features/)
+$(call PKG_DEPEND_INT,vislearning/math/)
+$(call PKG_DEPEND_INT,segmentation/)

+ 303 - 0
progs/evaluateCompleteBoWPipeline.cpp

@@ -0,0 +1,303 @@
+/**
+* @file evaluateCompleteBoWPipeline.cpp
+* @brief A complete BoW pipeline: feature extraction, codebook creation, vector quantization, classifier training, evaluation on separate test set
+* @author Alexander Freytag
+* @date 10-05-2013
+*/
+
+//STL
+#include <iostream>
+#include <limits>
+
+//core -- basic stuff
+#include <core/basics/Config.h>
+#include <core/basics/ResourceStatistics.h>
+#include <core/basics/Timer.h>
+#include <core/image/Convert.h>
+#include <core/vector/VectorT.h>
+
+//vislearning -- basic stuff
+#include <vislearning/baselib/Globals.h>
+#include <vislearning/baselib/ICETools.h>
+#include <vislearning/cbaselib/MultiDataset.h>
+#include <vislearning/cbaselib/Example.h>
+#include <vislearning/cbaselib/ClassificationResult.h>
+#include <vislearning/cbaselib/ClassificationResults.h>
+//
+// vislearning -- classifier
+#include <vislearning/classifier/classifierbase/VecClassifier.h>
+#include <vislearning/classifier/genericClassifierSelection.h>
+//
+// vislearning -- BoW codebooks
+#include "vislearning/features/simplefeatures/CodebookPrototypes.h"
+#include "vislearning/features/simplefeatures/BoWFeatureConverter.h"
+// 
+// vislearning -- local features
+#include <vislearning/features/localfeatures/GenericLFSelection.h>
+//
+// vislearning -- clustering methods
+#include <vislearning/math/cluster/GenericClusterAlgorithmSelection.h>
+//
+
+using namespace std;
+using namespace NICE;
+using namespace OBJREC;
+
+/**
+ a complete BoW pipeline
+ 
+ possibly, we can make use of objrec/progs/testClassifier.cpp
+*/
+int main( int argc, char **argv )
+{
+  std::set_terminate( __gnu_cxx::__verbose_terminate_handler );
+
+  Config * conf = new Config ( argc, argv );
+  
+  const bool writeClassificationResults = conf->gB( "main", "writeClassificationResults", true );
+  const std::string resultsfile = conf->gS( "main", "resultsfile", "/tmp/results.txt" );
+  
+  ResourceStatistics rs;
+  
+  // ========================================================================
+  //                            TRAINING STEP
+  // ========================================================================
+
+  MultiDataset md( conf );
+  const LabeledSet *trainFiles = md["train"];  
+   
+  //**********************************************
+  //
+  //     FEATURE EXTRACTION FOR TRAINING IMAGES
+  //
+  //**********************************************  
+  
+  std::cerr << "FEATURE EXTRACTION FOR TRAINING IMAGES" << std::endl;
+  
+  OBJREC::LocalFeatureRepresentation * featureExtractor = OBJREC::GenericLFSelection::selectLocalFeatureRep ( conf, "features", OBJREC::GenericLFSelection::TRAINING );
+  
+  //collect features in a single data structure
+  NICE::VVector featuresFromAllTrainingImages;  
+  featuresFromAllTrainingImages.clear();
+  
+  //determine how many training images we actually use to easily allocate the correct amount of memory afterwards
+  int numberOfTrainingImages ( 0 );
+  for(LabeledSet::const_iterator classIt = trainFiles->begin() ; classIt != trainFiles->end() ; classIt++)
+  {
+    numberOfTrainingImages += classIt->second.size();
+    std::cerr << "number of examples for this class: " << classIt->second.size() << std::endl;
+  }
+  
+  
+  //okay, this is redundant - but I see no way to do it more easy right now...
+  std::vector<NICE::VVector> featuresOfImages ( numberOfTrainingImages );
+  //this again is somehow redundant, but we need the labels lateron for easy access - change this to a better solution :)
+  NICE::VectorT<int> labelsTrain ( numberOfTrainingImages, 0 );
+  
+  //TODO replace the nasty makro by a suitable for-loop to make it omp-ready (parallelization)
+  int imgCnt ( 0 );
+   
+  // the corresponding nasty makro: LOOP_ALL_S( *trainFiles )
+  for(LabeledSet::const_iterator classIt = trainFiles->begin() ; classIt != trainFiles->end() ; classIt++)
+  {
+    for ( std::vector<ImageInfo *>::const_iterator imgIt = classIt->second.begin(); 
+          imgIt != classIt->second.end(); 
+          imgIt++, imgCnt++
+        ) 
+    {
+      // the corresponding nasty makro: EACH_INFO( classno, info );
+      int classno ( classIt->first );
+      const ImageInfo imgInfo = *(*imgIt);      
+      
+      std::string filename = imgInfo.img();      
+      
+      NICE::ColorImage img( filename );
+  
+      //compute features
+      
+      //variables to store feature information
+      NICE::VVector features;
+      NICE::VVector positions;
+  
+      Globals::setCurrentImgFN ( filename );
+      featureExtractor->extractFeatures ( img, features, positions );  
+              
+      //normalization :)
+      for ( NICE::VVector::iterator i = features.begin();
+            i != features.end();
+            i++)
+      {              
+        i->normalizeL1();
+      }  
+            
+      //collect them all in a larger data structure
+      featuresFromAllTrainingImages.append( features );
+      
+      //and store it as well in the data struct that additionally keeps the information which features belong to which image
+      //TODO this can be made more clever!
+//       featuresOfImages.push_back( features );
+      featuresOfImages[imgCnt] = features;
+      labelsTrain[imgCnt] = classno;
+    }
+  }
+  
+  
+  
+  //**********************************************
+  //
+  //             CODEBOOK CREATION
+  //
+  //**********************************************    
+  
+  std::cerr << "CODEBOOK CREATION" << std::endl;
+  
+  OBJREC::ClusterAlgorithm * clusterAlgo = OBJREC::GenericClusterAlgorithmSelection::selectClusterAlgo ( conf );
+   
+  NICE::VVector prototypes;
+  
+  std::vector<double> weights;
+  std::vector<int> assignments;
+  
+  std::cerr << "call cluster of cluster algo " << std::endl;
+  clusterAlgo->cluster( featuresFromAllTrainingImages, prototypes, weights, assignments );
+  
+  std::cerr << "create new codebook with the computed prototypes" << std::endl;
+  OBJREC::CodebookPrototypes * codebook = new OBJREC::CodebookPrototypes ( prototypes );
+  
+  
+  //**********************************************
+  //
+  //             VECTOR QUANTIZATION OF
+  //           FEATURES OF TRAINING IMAGES
+  //
+  //**********************************************  
+  
+  OBJREC::BoWFeatureConverter * bowConverter = new OBJREC::BoWFeatureConverter ( conf, codebook );  
+  
+  OBJREC::LabeledSetVector trainSet;
+  
+  NICE::VVector histograms ( featuresOfImages.size() /* number of vectors*/, 0 /* dimension of vectors*/ ); //the internal vectors will be resized within calcHistogram
+  NICE::VVector::iterator histogramIt = histograms.begin();
+  NICE::VectorT<int>::const_iterator labelsIt = labelsTrain.begin();
+  
+  for (std::vector<NICE::VVector>::const_iterator imgIt = featuresOfImages.begin(); imgIt != featuresOfImages.end(); imgIt++, histogramIt++, labelsIt++)
+  {
+    bowConverter->calcHistogram ( *imgIt, *histogramIt );
+    bowConverter->normalizeHistogram ( *histogramIt );
+    
+    //NOTE perhaps we should use add_reference here
+    trainSet.add( *labelsIt, *histogramIt );
+  }
+  
+  
+  //**********************************************
+  //
+  //             CLASSIFIER TRAINING
+  //
+  //**********************************************  
+  
+  std::string classifierType = conf->gS( "main", "classifierType", "GPHIK" );
+  OBJREC::VecClassifier * classifier = OBJREC::GenericClassifierSelection::selectVecClassifier( conf, classifierType );
+  
+  //TODO integrate GP-HIK-NICE into vislearning and add it into genericClassifierSelection
+  
+  //this method adds the training data to the temporary knowledge of our classifier
+  classifier->teach( trainSet );
+  //now the actual training step starts (e.g., parameter estimation, ... )
+  classifier->finishTeaching();
+  
+  
+  // ========================================================================
+  //                            TEST STEP
+  // ========================================================================
+  
+  const LabeledSet *testFiles = md["test"];
+
+  delete featureExtractor;
+  featureExtractor = OBJREC::GenericLFSelection::selectLocalFeatureRep ( conf, "features", OBJREC::GenericLFSelection::TESTING );  
+  
+  NICE::Matrix confusionMat ( trainFiles->size() /* number of classes in training */, testFiles->size() /* number of classes for testing*/, 0.0 );
+  NICE::Timer t;
+  
+  ClassificationResults results;
+  
+  LOOP_ALL_S( *testFiles )
+  {
+      EACH_INFO( classno, info );
+      std::string filename = info.img();
+  
+      //**********************************************
+      //
+      //     FEATURE EXTRACTION FOR TEST IMAGES
+      //
+      //**********************************************  
+      
+      NICE::ColorImage img( filename );
+  
+      //compute features
+      
+      //variables to store feature information
+      NICE::VVector features;
+      NICE::VVector positions;
+  
+      Globals::setCurrentImgFN ( filename );
+      featureExtractor->extractFeatures ( img, features, positions );  
+        
+      //normalization :)
+      for ( NICE::VVector::iterator i = features.begin();
+            i != features.end();
+            i++)
+      {              
+        i->normalizeL1();
+      }        
+      
+      //**********************************************
+      //
+      //             VECTOR QUANTIZATION OF
+      //           FEATURES OF TEST IMAGES
+      //
+      //********************************************** 
+      
+      NICE::Vector histogramOfCurrentImg;
+      bowConverter->calcHistogram ( features, histogramOfCurrentImg );
+      bowConverter->normalizeHistogram ( histogramOfCurrentImg );
+      
+      //**********************************************
+      //
+      //             CLASSIFIER EVALUATION
+      //
+      //**********************************************   
+            
+      uint classno_groundtruth = classno;
+      
+      t.start();
+      ClassificationResult r = classifier->classify ( histogramOfCurrentImg );
+      t.stop();
+      uint classno_estimated = r.classno;
+      r.classno_groundtruth = classno_groundtruth;
+
+      //if we like to store the classification results for external post processing, uncomment this
+      if ( writeClassificationResults )
+      {
+        results.push_back( r );
+      }      
+      
+      confusionMat( classno_estimated, classno_groundtruth ) += 1;
+  }
+  
+  confusionMat.normalizeColumnsL1();
+  std::cerr << confusionMat << std::endl;
+
+  std::cerr << "average recognition rate: " << confusionMat.trace()/confusionMat.rows() << std::endl;  
+  
+  if ( writeClassificationResults )
+  {
+    double avgRecogResults  ( results.getAverageRecognitionRate () );    
+    std::cerr << "average recognition rate according to classificationResults: " << avgRecogResults << std::endl;
+    results.writeWEKA ( resultsfile, 0 );
+  }     
+  
+ 
+  
+   return 0;
+}

+ 4 - 1
progs/libdepend.inc

@@ -3,7 +3,10 @@ $(call PKG_DEPEND_INT,core/algebra)
 $(call PKG_DEPEND_INT,vislearning/math)
 $(call PKG_DEPEND_INT,vislearning/baselib)
 $(call PKG_DEPEND_INT,vislearning/cbaselib)
-$(call PKG_DEPEND_INT,vislearning/classifier/kernelclassifier)
+$(call PKG_DEPEND_INT,vislearning/classifier)
+$(call PKG_DEPEND_INT,vislearning/features)
 $(call PKG_DEPEND_INT,vislearning/matlabAccessHighLevel)
+$(call PKG_DEPEND_EXT,MATIO)
+$(call PKG_DEPEND_EXT,HDF5)
 
 

部分文件因为文件数量过多而无法显示