Răsfoiți Sursa

Merge branch 'master' of dbv.inf-cv.uni-jena.de:nice/nice-semseg

Christoph Runge 10 ani în urmă
părinte
comite
98dc8090d7

+ 103 - 0
progs/testSemSegConvTrees.cpp

@@ -0,0 +1,103 @@
+/**
+ * @file testSemSegConvTrees.cpp
+ * @brief test semantic segmentation routines of the ConvTree method
+ * @author Sven Sickert
+ * @date 10/20/2014
+
+*/
+
+#include "core/basics/StringTools.h"
+#include "core/basics/ResourceStatistics.h"
+
+#include "semseg/semseg/SemSegConvolutionalTree.h"
+#include "semseg/semseg/SemSegTools.h"
+
+#include <fstream>
+#include <vector>
+
+using namespace OBJREC;
+
+int main ( int argc, char **argv )
+{
+    // variables
+    NICE::Config conf (argc, argv );
+    NICE::ResourceStatistics rs;
+
+    MultiDataset md ( &conf );
+    const ClassNames & classNames = md.getClassNames ( "train" );
+    const LabeledSet *testFiles = md["test"];
+    std::set<int> forbiddenClasses;
+    classNames.getSelection ( conf.gS ( "analysis", "forbidden_classes", "" ),
+                              forbiddenClasses );
+
+    NICE::Matrix M ( classNames.getMaxClassno() + 1,
+                     classNames.getMaxClassno() + 1 );
+    M.set( 0 );
+
+    // initialize semantic segmentation method
+    SemanticSegmentation *semseg = NULL;
+
+    // setup actual segmentation method
+    semseg = new SemSegConvolutionalTree ( &conf, &classNames );
+
+    // training
+    std::cout << "\nTRAINING" << std::endl;
+    std::cout << "########\n" << std::endl;
+    semseg->train( &md );
+
+    // testing
+    std::cout << "\nCLASSIFICATION" << std::endl;
+    std::cout << "##############\n" << std::endl;
+    for (LabeledSet::const_iterator it = testFiles->begin(); it != testFiles->end(); it++)
+    {
+        for (std::vector<ImageInfo *>::const_iterator jt = it->second.begin();
+            jt != it->second.end(); jt++)
+        {
+            ImageInfo & info = *(*jt);
+            std::string file = info.img();
+
+            NICE::Image segresult, gtruth;
+            if ( info.hasLocalizationInfo() )
+            {
+                const LocalizationResult *l_gt = info.localization();
+
+                segresult.resize ( l_gt->xsize, l_gt->ysize );
+                segresult.set( 0 );
+                gtruth.resize( l_gt->xsize, l_gt->ysize );
+                gtruth.set ( 0 );
+                l_gt->calcLabeledImage ( gtruth, classNames.getBackgroundClass() );
+            }
+            else
+            {
+                std::cerr << "testSemSegConvTrees: WARNING: NO localization info found for "
+                          << file << std::endl;
+            }
+
+            // actual testing
+            NICE::MultiChannelImageT<double> probabilities;
+            semseg->semanticseg( file, segresult, probabilities );
+
+            // updating confusion matrix
+            SemSegTools::updateConfusionMatrix (
+                        segresult, gtruth, M, forbiddenClasses );
+
+            // saving results to image file
+            NICE::ColorImage rgb;
+            NICE::ColorImage rgb_gt;
+            NICE::ColorImage orig ( file );
+            classNames.labelToRGB( segresult, rgb);
+            classNames.labelToRGB( gtruth, rgb_gt);
+            std::string fname = NICE::StringTools::baseName ( file, false );
+
+            SemSegTools::saveResultsToImageFile(
+                        &conf, "analysis", orig, rgb_gt, rgb, fname );
+        }
+    }
+
+    // evaluation & analysis
+    SemSegTools::computeClassificationStatistics( M, classNames, forbiddenClasses);
+
+    // Cleaning up
+    delete semseg;
+
+}

+ 54 - 28
progs/testSemanticSegmentation3D.cpp

@@ -13,13 +13,13 @@
 
 #include "core/basics/Config.h"
 #include "core/basics/StringTools.h"
-#include <vislearning/baselib/ICETools.h>
+#include "vislearning/baselib/ICETools.h"
 
-#include <core/image/MultiChannelImage3DT.h>
-#include <semseg/semseg/SemSegContextTree3D.h>
+#include "core/image/MultiChannelImage3DT.h"
+#include "semseg/semseg/SemSegContextTree3D.h"
 
-#include <core/basics/ResourceStatistics.h>
-#include <core/image/Morph.h>
+#include "core/basics/ResourceStatistics.h"
+#include "core/image/Morph.h"
 
 #include <fstream>
 #include <vector>
@@ -132,7 +132,6 @@ void startClassification (SemanticSegmentation *semseg,
 
   vector< int > zsizeVec;
   semseg->getDepthVector ( testFiles, zsizeVec, run_3Dseg );
-
   int depthCount = 0, idx = 0;
   vector< string > filelist;
   NICE::MultiChannelImageT<double> segresult;
@@ -193,8 +192,6 @@ void startClassification (SemanticSegmentation *semseg,
           NICE::ColorImage rgb_gt;
           NICE::ColorImage ov_rgb;
           NICE::ColorImage ov_rgb_gt;
-          NICE::ColorImage prob_map( probabilities.width(), probabilities.height() );
-          prob_map.set(0,0,0);
 
           for ( int y = 0 ; y < orig.height(); y++ )
           {
@@ -206,15 +203,6 @@ void startClassification (SemanticSegmentation *semseg,
             }
           }
 
-          for ( int y = 0 ; y < probabilities.height(); y++ )
-            for ( int x = 0 ; x < probabilities.width(); x++ )
-            {
-              double probVal = probabilities.get( x, y, z, 1 ) * 255.0;
-              int tmp = round(probVal);
-              for ( int c = 0 ; c < 3 ; c++ )
-                prob_map.setPixel( x, y, c, tmp );
-            }
-
           // confusion matrix
           NICE::Matrix M ( classNames.getMaxClassno() + 1, classNames.getMaxClassno() + 1 );
           M.set ( 0 );
@@ -255,7 +243,29 @@ void startClassification (SemanticSegmentation *semseg,
             rgb_gt.write ( out.str() + "_groundtruth." + output_type );
             ov_rgb.write ( out.str() + "_overlay_res." + output_type );
             ov_rgb_gt.write ( out.str() + "_overlay_gt." + output_type );
-            prob_map.write ( out.str() + "_probs." + output_type );
+
+            // write Probability maps
+            NICE::ColorImage prob_map( probabilities.width(), probabilities.height() );
+            prob_map.set(0,0,0);
+            int iNumChannels = probabilities.channels();
+            for ( int idxProbMap = 0; idxProbMap < iNumChannels; idxProbMap++)
+            {
+                for ( int y = 0 ; y < probabilities.height(); y++ )
+                {
+                    for ( int x = 0 ; x < probabilities.width(); x++ )
+                    {
+                        double probVal = probabilities.get( x, y, z, idxProbMap ) * 255.0;
+                        int tmp = round(probVal);
+                        for ( int c = 0 ; c < 3 ; c++ )
+                            prob_map.setPixel( x, y, c, tmp );
+                    }
+                }
+                std::stringstream ssFileProbMap;
+                //ssFileProbMap << out.str() << "_probs." << "c" << idxProbMap << "." << output_type;
+                ssFileProbMap << out.str() << "_probs." << "c-" << classNames.code( idxProbMap ) << "." << output_type;
+                //classNames
+                prob_map.write ( ssFileProbMap.str() );
+            }
           }
         }
       }
@@ -303,7 +313,6 @@ int main ( int argc, char **argv )
 
   // initialize semantic segmentation method
   SemanticSegmentation *semseg = NULL;
-  //semseg = new SemSegContextTree3D ( &conf, &classNames );
   
   // TRAINING AND TESTING
   if (!doCrossVal)
@@ -360,6 +369,9 @@ int main ( int argc, char **argv )
   cout << "CPU Time (user): " << userCPUTime << " seconds" << endl;
   cout << "CPU Time (sys):  " << sysCPUTime << " seconds" << endl;
 
+  cout << "\nPERFORMANCE" << endl;
+  cout << "###########\n" << endl;
+
   double overall = 0.0;
   double sumall = 0.0;
 
@@ -382,6 +394,25 @@ int main ( int argc, char **argv )
   }
   overall /= sumall;
 
+  cout << "Confusion Matrix:" << endl;
+  for (int r = 0; r < (int) M.rows(); r++)
+  {
+    for (int c = 0; c < (int) M.cols(); c++)
+    {
+      cout << M(r,c) << "  ";
+    }
+    cout << endl;
+  }
+
+  // metrics for binary classification
+  double precision, recall, f1score = -1.0;
+  if (classNames.getMaxClassno()+1 == 2)
+  {
+    precision = (double)M(1,1) / (double)(M(1,1)+M(0,1));
+    recall = (double)M(1,1) / (double)(M(1,1)+M(1,0));
+    f1score = 2.0*(precision*recall)/(precision+recall);
+  }
+
   // normalizing M using rows
   for ( int r = 0 ; r < ( int ) M.rows() ; r++ )
   {
@@ -415,16 +446,13 @@ int main ( int argc, char **argv )
     }
   }
 
-  // print/save results of evaluation
-  cout << "\nPERFORMANCE" << endl;
-  cout << "###########\n" << endl;
-  ofstream fout ( ( resultdir + "/res.txt" ).c_str(), ios::out );
-  fout << "Overall Recognition Rate: " << overall << endl;
-  fout << "Average Recognition Rate: " << avg_perf / ( classes_trained ) << endl;
-  fout << "Lower Bound: " << 1.0  / classes_trained << endl;
+  // print results of evaluation
   cout << "Overall Recogntion Rate: " << overall << endl;
   cout << "Average Recogntion Rate: " << avg_perf / ( classes_trained ) << endl;
   cout << "Lower Bound: " << 1.0  / classes_trained << endl;
+  cout << "Precision: " << precision << endl;
+  cout << "Recall: " << recall << endl;
+  cout << "F1Score: " << f1score << endl;
 
   cout <<"\nClasses:" << endl;
   for ( int r = 0 ; r < ( int ) M.rows() ; r++ )
@@ -432,11 +460,9 @@ int main ( int argc, char **argv )
     if ( ( classNames.existsClassno ( r ) ) && ( forbidden_classes.find ( r ) == forbidden_classes.end() ) )
     {
       std::string classname = classNames.text ( r );
-      fout << classname.c_str() << ": " << M ( r, r ) << endl;
       cout << classname.c_str() << ": " << M ( r, r ) << endl;
     }
   }
-  fout.close();
 
   return 0;
 }

+ 1 - 1
semseg/SemSegContextTree3D.cpp

@@ -127,7 +127,7 @@ SemSegContextTree3D::SemSegContextTree3D (
   this->useFeat4 = conf->gB ( section, "use_feat_4", false);    // pixel pair context features
   this->useFeat5 = conf->gB ( section, "use_feat_5", false);    // ray features
 
-  string segmentationtype = conf->gS ( section, "segmentation_type", "slic" );
+  string segmentationtype = conf->gS ( section, "segmentation_type", "none" );
   if ( segmentationtype == "meanshift" )
     this->segmentation = new RSMeanShift ( conf );
   else if ( segmentationtype == "felzenszwalb" )

+ 156 - 0
semseg/SemSegConvolutionalTree.cpp

@@ -0,0 +1,156 @@
+/**
+ * @file SemSegConvolutionalTree.h
+ * @brief Semantic Segmentation using Covolutional Trees
+ * @author Sven Sickert
+ * @date 10/17/2014
+
+*/
+
+#include <iostream>
+
+#include "SemSegConvolutionalTree.h"
+#include "SemSegTools.h"
+
+#include "vislearning/classifier/fpclassifier/randomforest/FPCRandomForests.h"
+#include "vislearning/features/fpfeatures/ConvolutionFeature.h"
+
+using namespace OBJREC;
+
+using namespace std;
+using namespace NICE;
+
+//###################### CONSTRUCTORS #########################//
+
+SemSegConvolutionalTree::SemSegConvolutionalTree () : SemanticSegmentation ()
+{
+    conf = NULL;
+
+    saveLoadData = false;
+    fileLocation = "classifier.data";
+
+    fpc = new FPCRandomForests ();
+}
+
+SemSegConvolutionalTree::SemSegConvolutionalTree (
+        const Config *conf,
+        const ClassNames *classNames )
+    : SemanticSegmentation( conf, classNames )
+{
+    initFromConfig( conf );
+}
+
+//###################### DESTRUCTORS ##########################//
+
+SemSegConvolutionalTree::~SemSegConvolutionalTree ()
+{
+    if ( fpc != NULL )
+        delete fpc;
+}
+
+//#################### MEMBER FUNCTIONS #######################//
+
+void SemSegConvolutionalTree::initFromConfig( const Config *_conf,
+                                         const string &s_confSection )
+{
+    conf = _conf;
+    saveLoadData = conf->gB ( s_confSection, "save_load_data", false );
+    fileLocation = conf->gS ( s_confSection, "datafile", "classifier.data" );
+
+    fpc = new FPCRandomForests ( _conf, "FPCRandomForests" );
+    fpc->setMaxClassNo( classNames->getMaxClassno() );
+}
+
+/** training function */
+void SemSegConvolutionalTree::train ( const MultiDataset *md )
+{
+    if ( saveLoadData && FileMgt::fileExists( fileLocation ) )
+    {
+        read( fileLocation );
+    }
+    else
+    {
+        Examples examples;
+
+        // image storage
+        vector<CachedExample *> imgexamples;
+
+        // create pixel-wise training examples
+        SemSegTools::collectTrainingExamples (
+          conf,
+          "FPCRandomForests",
+          * ( ( *md ) ["train"] ),
+          *classNames,
+          examples,
+          imgexamples );
+
+        assert ( examples.size() > 0 );
+
+        FeaturePool fp;
+        ConvolutionFeature cf ( conf );
+        cf.explode( fp );
+
+        // start training using random forests
+        fpc->train( fp, examples);
+
+        // save trained classifier to file
+        if (saveLoadData) save( fileLocation );
+
+        // Cleaning up
+        for ( vector<CachedExample *>::iterator i = imgexamples.begin();
+              i != imgexamples.end();
+              i++ )
+            delete ( *i );
+
+        fp.destroy();
+    }
+}
+
+/** classification function */
+void SemSegConvolutionalTree::semanticseg(
+        CachedExample *ce,
+        Image &segresult,
+        NICE::MultiChannelImageT<double> &probabilities )
+{
+    // for speed optimization
+    FPCRandomForests *fpcrf = dynamic_cast<FPCRandomForests *> ( fpc );
+
+    int xsize, ysize;
+    ce->getImageSize ( xsize, ysize );
+    probabilities.reInit ( xsize, ysize, classNames->getMaxClassno() + 1 );
+    segresult.resize ( xsize, ysize );
+
+    Example pce ( ce, 0, 0 );
+    for ( int y = 0 ; y < ysize ; y++ )
+      for ( int x = 0 ; x < xsize ; x++ )
+      {
+        pce.x = x ;
+        pce.y = y;
+        ClassificationResult r = fpcrf->classify ( pce );
+        segresult.setPixel ( x, y, r.classno );
+        for ( int i = 0 ; i < ( int ) probabilities.channels(); i++ )
+          probabilities[i](x,y) = r.scores[i];
+      }
+}
+
+///////////////////// INTERFACE PERSISTENT /////////////////////
+// interface specific methods for store and restore
+///////////////////// INTERFACE PERSISTENT /////////////////////
+
+void SemSegConvolutionalTree::restore( istream &is, int format )
+{
+    //dirty solution to circumvent the const-flag
+    const_cast<ClassNames*>(this->classNames)->restore ( is, format );
+
+    fpc->restore( is, format );
+}
+
+void SemSegConvolutionalTree::store ( ostream &os, int format ) const
+{
+    classNames->store( os, format );
+    fpc->store( os, format );
+}
+
+void SemSegConvolutionalTree::clear ( )
+{
+    fpc->clear();
+}

+ 104 - 0
semseg/SemSegConvolutionalTree.h

@@ -0,0 +1,104 @@
+/**
+ * @file SemSegConvolutionalTree.h
+ * @brief Semantic Segmentation using Covolutional Trees
+ * @author Sven Sickert
+ * @date 10/17/2014
+
+*/
+
+#ifndef SEMSEGCONVOLUTIONALTREEINCLUDE
+#define SEMSEGCONVOLUTIONALTREEINCLUDE
+
+// nice-core includes
+
+// nice-vislearning includes
+#include "vislearning/classifier/classifierbase/FeaturePoolClassifier.h"
+
+// nice-semseg includes
+#include "SemanticSegmentation.h"
+
+namespace OBJREC
+{
+
+class SemSegConvolutionalTree : public SemanticSegmentation
+{
+    private:
+
+        /** pointer to config file */
+        const NICE::Config *conf;
+
+        /** save / load trained classifier */
+        bool saveLoadData;
+
+        /** file location of trained classifier */
+        std::string fileLocation;
+
+        /** classifier for categorization */
+        FeaturePoolClassifier *fpc;
+
+    public:
+
+        /** simple constructor */
+        SemSegConvolutionalTree ();
+
+        /** config constructor */
+        SemSegConvolutionalTree ( const NICE::Config *conf,
+                                  const ClassNames *classNames );
+
+        /** simple destructor */
+        virtual ~SemSegConvolutionalTree();
+
+        /**
+         * @brief Setup internal variables and objects used
+         * @param conf Configuration file to specify variable settings
+         * @param s_confSection Section in configuration file
+         */
+        void initFromConfig (
+                const NICE::Config *_conf,
+                const std::string & s_confSection = "SemSegConvolutionalTree" );
+
+        /**
+         * @brief training function / learn classifier
+         * @param md the data set
+         */
+        void train ( const MultiDataset *md );
+
+        /**
+         * @brief classification function
+           @param ce image data
+           @param segresult result of the semantic segmentation with a label
+                  for each pixel
+           @param probabilities multi-channel image with one channel for
+                  each class and corresponding probabilities for each pixel
+         */
+        void semanticseg ( CachedExample *ce,
+                           NICE::Image &segresult,
+                           NICE::MultiChannelImageT<double> &probabilities );
+
+
+        ///////////////////// INTERFACE PERSISTENT /////////////////////
+        // interface specific methods for store and restore
+        ///////////////////// INTERFACE PERSISTENT /////////////////////
+
+        /**
+         * @brief Load segmentation object from external file (stream)
+         */
+        virtual void restore ( std::istream & is, int format = 0 );
+
+        /**
+         * @brief Save segmentation-object to external file (stream)
+         */
+        virtual void store( std::ostream & os, int format = 0 ) const;
+
+        /**
+         * @brief Clear segmentation-object object
+         */
+        virtual void clear ();
+
+};
+
+
+
+} // namespace
+
+#endif

+ 267 - 68
semseg/SemSegTools.cpp

@@ -1,7 +1,7 @@
-/** 
+/**
 * @file SemSegTools.cpp
 * @brief tools for semantic segmentation
-* @author Erik Rodner
+* @author Erik Rodner, Sven Sickert
 * @date 03/19/2009
 
 */
@@ -15,14 +15,213 @@ using namespace std;
 using namespace NICE;
 
 #undef DEBUG_LOCALIZATION
+#undef DEBUG
+
+void SemSegTools::segmentToOverlay (
+        const NICE::Image *orig,
+        const NICE::ColorImage & segment,
+        NICE::ColorImage & result )
+{
+    int xsize = orig->width();
+    int ysize = orig->height();
+
+    result.resize( xsize, ysize );
+    std::vector< NICE::MatrixT<double> > channelMat;
+
+    double alpha = .5;
+
+    for (int c = 0; c < 3; c++)
+    {
+        NICE::MatrixT<double> chan ( xsize, ysize );
+        channelMat.push_back( chan );
+    }
+
+    for (int y = 0; y < ysize; y++)
+    {
+        for (int x = 0; x < xsize; x++)
+        {
+            uchar val = orig->getPixelQuick(x,y);
+            for (int c = 0; c < 3; c++)
+                channelMat[c](x,y) = (double)val + alpha*(double)segment.getPixel( x, y, c );
+        }
+    }
+
+    for (int c = 0; c < 3; c++)
+    {
+        channelMat[c] /= channelMat[c].Max();
+        channelMat[c] *= 255;
+    }
+
+    for (int y = 0; y < ysize; y++)
+    {
+        for (int x = 0; x < xsize; x++)
+        {
+            for (int c = 0; c < 3; c++)
+            {
+                int val = channelMat[c](x,y);
+                result.setPixel( x, y, c, (uchar)val);
+            }
+        }
+    }
+}
+
+void SemSegTools::updateConfusionMatrix(
+        const Image &img,
+        const Image &gt,
+        Matrix &M,
+        const std::set<int> &forbiddenClasses )
+{
+    double subsamplex = gt.width() / ( double ) img.width();
+    double subsampley = gt.height() / ( double ) img.height();
+
+    for ( int y = 0 ; y < gt.height() ; y++ )
+        for ( int x = 0 ; x < gt.width() ; x++ )
+        {
+            int xx = ( int ) ( x / subsamplex );
+            int yy = ( int ) ( y / subsampley );
+
+            if ( xx < 0 ) xx = 0;
+
+            if ( yy < 0 ) yy = 0;
+
+            if ( xx > img.width() - 1 ) xx = img.width() - 1;
+
+            if ( yy > img.height() - 1 ) yy = img.height() - 1;
+
+            int cimg = img.getPixel ( xx, yy );
+            int gimg = gt.getPixel ( x, y );
+
+            if ( forbiddenClasses.find ( gimg ) == forbiddenClasses.end() )
+            {
+                M ( gimg, cimg ) ++;
+            }
+        }
+}
+
+void SemSegTools::computeClassificationStatistics(
+        Matrix &confMat,
+        const ClassNames &classNames,
+        const std::set<int> &forbiddenClasses )
+{
+    double overallTrue = 0.0;
+    double sumAll  = 0.0;
+
+    // print confusion matrix & get overall recognition rate
+    std::cout << "Confusion Matrix:" <<  std::endl;
+    for ( int r = 0; r < (int) confMat.rows(); r++ )
+    {
+        for ( int c = 0; c < (int) confMat.cols(); c++ )
+        {
+            if ( r == c )
+                overallTrue += confMat( r, c );
+
+            sumAll += confMat( r, c );
+            std::cout << confMat( r, c ) << " ";
+        }
+        std::cout << std::endl;
+    }
+    overallTrue /= sumAll;
+
+    // binary classification metrics
+    double precision, recall, f1score = -1.0;
+    if ( confMat.rows() == 2 )
+    {
+        precision = (double)confMat(1,1) / (double)(confMat(1,1)+confMat(0,1));
+        recall = (double)confMat(1,1) / (double)(confMat(1,1)+confMat(1,0));
+        f1score = 2.0*(precision*recall)/(precision+recall);
+    }
+
+    // normalizing confMat using rows
+    for ( int r = 0 ; r < (int) confMat.rows() ; r++ )
+    {
+        double sum = 0.0;
+
+        for ( int c = 0 ; c < (int) confMat.cols() ; c++ )
+            sum += confMat ( r, c );
+
+        if ( std::fabs ( sum ) > 1e-4 )
+            for ( int c = 0 ; c < (int) confMat.cols() ; c++ )
+                confMat ( r, c ) /= sum;
+    }
+
+    // get average recognition rate
+    double avgTrue = 0.0;
+    int classesTrained = 0;
+    for ( int r = 0 ; r < (int) confMat.rows() ; r++ )
+    {
+        if ( classNames.existsClassno ( r )
+             && ( forbiddenClasses.find ( r ) == forbiddenClasses.end() ) )
+        {
+            avgTrue += confMat ( r, r );
+            double lsum = 0.0;
+            for ( int r2 = 0; r2 < ( int ) confMat.rows(); r2++ )
+                lsum += confMat ( r,r2 );
+
+            if ( lsum != 0.0 )
+                classesTrained++;
+        }
+    }
+
+    // print classification statistics
+    std::cout << "\nOverall Recogntion Rate: " << overallTrue;
+    std::cout << "\nAverage Recogntion Rate: " << avgTrue / ( classesTrained );
+    std::cout << "\nLower Bound: " << 1.0 /(double)classesTrained;
+    std::cout << "\nPrecision: " << precision;
+    std::cout << "\nRecall: " << recall;
+    std::cout << "\nF1Score: " << f1score;
+
+    std::cout <<"\n\nClasses:" << std::endl;
+    for ( int r = 0 ; r < (int) confMat.rows() ; r++ )
+    {
+        if ( classNames.existsClassno ( r )
+             && ( forbiddenClasses.find ( r ) == forbiddenClasses.end() ) )
+        {
+            std::string cname = classNames.text ( r );
+            std::cout << cname.c_str() << ": " << confMat ( r, r ) << std::endl;
+        }
+    }
+
+}
+
+void SemSegTools::saveResultsToImageFile(
+        const Config *conf,
+        const string &section,
+        const ColorImage &orig,
+        const ColorImage &gtruth,
+        const ColorImage &segment,
+        const string &file )
+{
+    std::string resultDir = conf->gS ( section, "resultdir", "." );
+    std::string outputType = conf->gS ( section, "output_type", "ppm" );
+    std::string outputPostfix = conf->gS ( section, "output_postfix", "" );
+
+    NICE::ColorImage overlaySegment, overlayGTruth;
+
+    segmentToOverlay( orig.getChannel(1), segment, overlaySegment );
+    segmentToOverlay( orig.getChannel(1), gtruth, overlayGTruth );
+
+    std::stringstream out;
+    out << resultDir << "/" << file << outputPostfix;
+
+#ifdef DEBUG
+    std::cout << "Writing to file " << out.str() << "_*." << outputType << std::endl;
+#endif
+
+    orig.write ( out.str() + "_orig." + outputType );
+    segment.write ( out.str() + "_result." + outputType );
+    gtruth.write ( out.str() + "_groundtruth." + outputType );
+    overlaySegment.write ( out.str() + "_overlay_res." + outputType );
+    overlayGTruth.write ( out.str() + "_overlay_gt." + outputType );
+
+}
 
 void SemSegTools::collectTrainingExamples ( 
-			  const Config * conf,
-			  const std::string & section,
-			  const LabeledSet & train,
-			  const ClassNames & cn,
-			  Examples & examples,
-			  vector<CachedExample *> & imgexamples )
+        const Config * conf,
+        const std::string & section,
+        const LabeledSet & train,
+        const ClassNames & cn,
+        Examples & examples,
+        vector<CachedExample *> & imgexamples )
 {
     assert ( train.count() > 0 );
     examples.clear();
@@ -44,72 +243,72 @@ void SemSegTools::collectTrainingExamples (
     
     if ( useExcludedAsBG ) 
     {
-	backgroundClassNo = cn.classno("various");
-	assert ( backgroundClassNo >= 0 );
+        backgroundClassNo = cn.classno("various");
+        assert ( backgroundClassNo >= 0 );
     }
 
     LOOP_ALL_S (train)
     {
-	EACH_INFO(image_classno,imgInfo);
-	std::string imgfn = imgInfo.img();
-
-	if ( ! imgInfo.hasLocalizationInfo() ) {
-	    fprintf (stderr, "WARNING: NO localization info found for %s !\n",
-		imgfn.c_str() );
-	    continue;	
-	}
-
-	int xsize, ysize;
-	CachedExample *ce = new CachedExample ( imgfn );
-	ce->getImageSize ( xsize, ysize );
-	imgexamples.push_back ( ce );
-
-	const LocalizationResult *locResult = imgInfo.localization();
-	if ( locResult->size() <= 0 ) {
-	    fprintf (stderr, "WARNING: NO ground truth polygons found for %s !\n",
-		imgfn.c_str());
-	    continue;	
-	}
-
-	fprintf (stderr, "SemSegTools: Collecting pixel examples from localization info: %s\n", 
-	    imgfn.c_str() );
-
-	NICE::Image pixelLabels (xsize, ysize);
-	pixelLabels.set(0);
-	locResult->calcLabeledImage ( pixelLabels, cn.getBackgroundClass() );
-
-#ifdef DEBUG_LOCALIZATION
-	NICE::Image img (imgfn);
-	showImage(img);
-	showImage(pixelLabels);
-#endif
+        EACH_INFO(image_classno,imgInfo);
+        std::string imgfn = imgInfo.img();
+
+        if ( ! imgInfo.hasLocalizationInfo() ) {
+            std::cerr << "WARNING: NO localization info found for "
+                      << imgfn << " !" << std::endl;
+            continue;
+        }
+
+        int xsize, ysize;
+        CachedExample *ce = new CachedExample ( imgfn );
+        ce->getImageSize ( xsize, ysize );
+        imgexamples.push_back ( ce );
+
+        const LocalizationResult *locResult = imgInfo.localization();
+        if ( locResult->size() <= 0 ) {
+            std::cerr << "WARNING: NO ground truth polygons found for "
+                      << imgfn << " !" << std::endl;
+            continue;
+        }
+
+        std::cerr << "SemSegTools: Collecting pixel examples from localization info: "
+                  << imgfn << std::endl;
+
+        NICE::Image pixelLabels (xsize, ysize);
+        pixelLabels.set(0);
+        locResult->calcLabeledImage ( pixelLabels, cn.getBackgroundClass() );
+
+    #ifdef DEBUG_LOCALIZATION
+        NICE::Image img (imgfn);
+        showImage(img);
+        showImage(pixelLabels);
+    #endif
+
+        Example pce ( ce, 0, 0 );
+        for ( int x = 0 ; x < xsize ; x += grid_size_x )
+            for ( int y = 0 ; y < ysize ; y += grid_size_y )
+            {
+                if ( (x >= grid_border_x) &&
+                    ( y >= grid_border_y ) && ( x < xsize - grid_border_x ) &&
+                    ( y < ysize - grid_border_x ) )
+                {
+                    pce.x = x; pce.y = y;
+                    int classno = pixelLabels.getPixel(x,y);
 
-	Example pce ( ce, 0, 0 );
-	for ( int x = 0 ; x < xsize ; x += grid_size_x ) 
-	    for ( int y = 0 ; y < ysize ; y += grid_size_y )  
-	    {
-		if ( (x >= grid_border_x) &&
-		    ( y >= grid_border_y ) && ( x < xsize - grid_border_x ) &&
-		    ( y < ysize - grid_border_x ) )
-		{
-		    pce.x = x; pce.y = y;
-		    int classno = pixelLabels.getPixel(x,y);
-
-		    if ( classnoSelection.find(classno) != classnoSelection.end() ) {
-			examples.push_back ( pair<int, Example> (
-			    classno, 
-			    pce // FIXME: offset handling
-			) );
-		    } else if ( useExcludedAsBG ) {
-			examples.push_back ( pair<int, Example> (
-			    backgroundClassNo, 
-			    pce // FIXME: offset handling
-			) );
-		    } 
-		}
-	    }
+                    if ( classnoSelection.find(classno) != classnoSelection.end() ) {
+                    examples.push_back ( pair<int, Example> (
+                        classno,
+                        pce // FIXME: offset handling
+                    ) );
+                    } else if ( useExcludedAsBG ) {
+                    examples.push_back ( pair<int, Example> (
+                        backgroundClassNo,
+                        pce // FIXME: offset handling
+                    ) );
+                    }
+                }
+            }
     }
 
-    fprintf (stderr, "total number of examples: %d\n", (int)examples.size() );
+    std::cerr << "total number of examples: " << (int)examples.size() << std::endl;
 }
 

+ 57 - 6
semseg/SemSegTools.h

@@ -25,6 +25,57 @@ class SemSegTools
 
   public:
 
+    /**
+     * @brief produce an image with segmentation result as overlay
+     * @param orig original input image
+     * @param segment segmentation result
+     * @param result overlay image
+     */
+    static void segmentToOverlay (
+            const NICE::Image * orig,
+            const NICE::ColorImage & segment,
+            NICE::ColorImage & result );
+
+    /**
+     * @brief update confusion matrix with results of current image
+     * @param img segmentation result
+     * @param gt ground truth data
+     * @param M confusion matrix
+     * @param forbidden_classes set of classes, that should be ignored
+     */
+    static void updateConfusionMatrix (
+            const NICE::Image & img,
+            const NICE::Image & gt,
+            NICE::Matrix & M,
+            const std::set<int> & forbiddenClasses );
+
+    /**
+     * @brief compute typical classification statistics using confusion matrix
+     * @param confMat confusion matrix
+     * @param classNames class names object
+     * @param forbidden_classes set of classes, that should be ignored
+     */
+    static void computeClassificationStatistics (
+            NICE::Matrix & confMat,
+            const OBJREC::ClassNames & classNames,
+            const std::set<int> & forbiddenClasses );
+
+    /**
+     * @brief save results to image file
+     * @param conf Config file
+     * @param section section in config file
+     * @param orig input image
+     * @param gtruth ground truth data
+     * @param segment segmentation result
+     */
+    static void saveResultsToImageFile (
+            const NICE::Config * conf,
+            const std::string & section,
+            const NICE::ColorImage & orig,
+            const NICE::ColorImage & gtruth,
+            const NICE::ColorImage & segment,
+            const std::string & file );
+
     /** collect pixel-wise training examples
         from a set of images
         @param conf includes settings about grid size etc.
@@ -35,12 +86,12 @@ class SemSegTools
         @param imgexamples image based caching structure referenced by pixel-wise examples
     */
     static void collectTrainingExamples (
-      const NICE::Config * conf,
-      const std::string & section,
-      const LabeledSet & train,
-      const ClassNames & cn,
-      Examples & examples,
-      std::vector<CachedExample *> & imgexamples );
+            const NICE::Config * conf,
+            const std::string & section,
+            const LabeledSet & train,
+            const ClassNames & cn,
+            Examples & examples,
+            std::vector<CachedExample *> & imgexamples );
 
 };
 

+ 2 - 0
semseg/SemanticSegmentation.cpp

@@ -88,7 +88,9 @@ void SemanticSegmentation::semanticseg ( const std::string & filename,
     NICE::Image img = Preprocess::ReadImgAdv ( filename );
     ce = new CachedExample ( img );
   }
+#ifdef DEBUG_PRINTS
   fprintf ( stderr, "Starting Semantic Segmentation !\n" );
+#endif
   this->semanticseg ( ce, segresult, probabilities );
   delete ce;
 }