Sven Sickert 10 жил өмнө
parent
commit
872814b0a6
2 өөрчлөгдсөн 264 нэмэгдсэн , 14 устгасан
  1. 207 8
      semseg/SemSegTools.cpp
  2. 57 6
      semseg/SemSegTools.h

+ 207 - 8
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();

+ 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 );
 
 };