diff --git a/cfg/GroundSegmentation.cfg b/cfg/GroundSegmentation.cfg
index 4673e08c21ec6dd3c524f235eeb0a30a288ebdb0..95565c7c31496208bc18ac484f46e60929fe5737 100644
--- a/cfg/GroundSegmentation.cfg
+++ b/cfg/GroundSegmentation.cfg
@@ -86,6 +86,7 @@ gen.add("max_navigation_slope", double_t, 0, "slopes greater than this threshold
 
 # visualization and debug parameters
 gen.add("evaluate_segmentation", bool_t, 0, "generates quantitative evaluation metrics", False);
+gen.add("only_road_is_traversable", bool_t, 0, "If set to false terrain and vegetation will be considered non-traversable, but sidewalks, parkings, etc will be considered to be traversable", False);
 gen.add("measure_performance", bool_t, 0, "to measure times of inner functions", False);
 gen.add("show_dense_reconstruction", bool_t, 0, "creates dense pointcloud with ground predictions", False);
  
diff --git a/include/ground_segmentation_alg_node.h b/include/ground_segmentation_alg_node.h
index d4e25e1a685150821724d5604cbea4817520595c..3ac96b2071a65d11263c92870f5d6c631f8f31a7 100644
--- a/include/ground_segmentation_alg_node.h
+++ b/include/ground_segmentation_alg_node.h
@@ -45,6 +45,12 @@ struct metrics
   unsigned long int tn = 0;
   unsigned long int fn = 0;
 
+  unsigned long int FN_due_to_unknown_points = 0;
+  unsigned long int TN_due_to_unknown_points = 0;
+
+  unsigned long int key_obstacle_true_positives = 0;
+  unsigned long int key_obstacle_false_negatives = 0;
+
   float prec = 0.0;
   float rec  = 0.0;
   float f1   = 0.0;
@@ -85,6 +91,7 @@ private:
   bool flag_new_ground_truth_lidar_data_;
   bool flag_use_low_obstacle_detection_;
   bool flag_evaluate_segmentation_;
+  bool flag_only_road_is_traversable_;
 
   metrics evaluation_metrics_;
 
diff --git a/params/iri_ground_segmentation.yaml b/params/iri_ground_segmentation.yaml
index 4eba5ee5d1dec71707e812b1ef06af6c89ce73b3..9626478273bbf474c7b5e80ac89cb35201be669b 100644
--- a/params/iri_ground_segmentation.yaml
+++ b/params/iri_ground_segmentation.yaml
@@ -46,19 +46,20 @@ iri_ground_segmentation: {
   
   # labeling parameters
   max_pred_std_dev_for_labelling: 0.333,                 ## ONLY IN USE TO GIVE COLOUR TO DENSE RECONSTRUCTION
-  score_threshold: 0.0,                                  ## for assigning ground class label: one means maha. dist. equal to zero, zero means mahalanobis dist equal to maha. thres
-  classify_not_labeled_points_as_obstacles: true,        ## when a point has no reference satisfying the max_pred_std_dev_for_labelling threshold we can leave as unknown or label it as obstacle
+  score_threshold: 0.475, #0.0 when using neural net     ## for assigning ground class label: one means maha. dist. equal to zero, zero means mahalanobis dist equal to maha. thres
+  classify_not_labeled_points_as_obstacles: false,       ## when a point has no reference satisfying the max_pred_std_dev_for_labelling threshold we can leave as unknown or label it as obstacle
   ground_threshold_in_not_analyzed_areas: 0.1,           ## when it is not possible to make a local analysis of the data, we will use the lowest point (the one in elevation_cloud) as ground height, and
                                                          ## all the points above it and below this threshold will be classified as ground 
                            
   # low obstacle detection parameters
-  use_low_obstacle_detection: false,
+  use_low_obstacle_detection: true,
   low_obstacle_min_height: 0.05,
   sensor_best_resolution_deg: 0.2, # Best resolution, either horizontal or vertical
   max_navigation_slope: 0.5,                           
                                                          
   # visualization and debug parameters
   evaluate_segmentation: true,
+  only_road_is_traversable: true,        # If set to false terrain and vegetation will be considered non-traversable, but sidewalks, parkings, etc will be considered to be traversable
   measure_performance: false,            ## (feature still not debugged) Flag to measure number of execution and execution times of the different functions of the algorithm 
   show_dense_reconstruction: false,      ## To show a dense ground surface reconstruction using the predictions of the ground mode (colored using the std_dev of z coordinate)   
                                          ## or alternatively the "elevation point cloud" (useful for parameter tunning) 
diff --git a/src/ground_segmentation_alg_node.cpp b/src/ground_segmentation_alg_node.cpp
index 61e56d8e676a76c977880c7b9eb5f01c790327fe..2750fc1154028e6069c84554fe0039a84846f286 100644
--- a/src/ground_segmentation_alg_node.cpp
+++ b/src/ground_segmentation_alg_node.cpp
@@ -264,6 +264,13 @@ GroundSegmentationAlgNode::GroundSegmentationAlgNode(void) :
   else
     this->flag_evaluate_segmentation_ = config_.evaluate_segmentation;
 
+  if (!this->private_node_handle_.getParam("only_road_is_traversable", this->config_.only_road_is_traversable))
+  {
+    ROS_WARN("GroundSegmentationAlgNode::GroundSegmentationAlgNode: param 'only_road_is_traversable' not found");
+  }
+  else
+    this->flag_only_road_is_traversable_ = config_.only_road_is_traversable;
+
   // [init subscribers]
   this->lidar_subscriber_ = this->private_node_handle_.subscribe("lidar_points", 1,
                                                                  &GroundSegmentationAlgNode::cb_lidar, this);
@@ -547,8 +554,13 @@ void GroundSegmentationAlgNode::convertInputsToSuitableFormats(void)
 
       lidar_pcl_cloud_.points.push_back(extended_point);
 
-      if(flag_evaluate_segmentation_)
+      if (flag_evaluate_segmentation_)
+      {
+        extended_point.data_c[DATA_C_1_ID_CLASS] = regular_point->label; // We recover the SemanticKitti ground truth
+                                                                         // because we want to have info about key obstacles for
+                                                                         // evaluation
         evaluated_segmentation_pointcloud_pcl_cloud_.points.push_back(extended_point);
+      }
     }
 
     flag_new_ground_truth_lidar_data_ = false;
@@ -596,6 +608,8 @@ void GroundSegmentationAlgNode::convertOutputsToSuitableFormats(void)
 
   this->PCLPointCloudToRosPointCloud(lidar_pcl_cloud_, lidar_points_ground_segmented_ros_cloud_);
 
+  this->PCLPointCloudToRosPointCloud(evaluated_segmentation_pointcloud_pcl_cloud_, evaluated_segmentation_pointcloud_ros_cloud_);
+
   this->PCLPointCloudToRosPointCloud(ground_dense_reconstruction_pcl_cloud_, ground_dense_reconstruction_ros_cloud_);
 
   this->nodesPCLPointCloudToVerticesArray(roadmap_vertices_pcl_cloud_, roadmap_vertices_array_);
@@ -615,6 +629,7 @@ void GroundSegmentationAlgNode::publishAll(void)
   this->lidar_points_ground_segmented_publisher_.publish(this->lidar_points_ground_segmented_ros_cloud_);
   this->obstacle_points_publisher_.publish(this->obstacle_points_ros_cloud_);
   this->ground_points_publisher_.publish(this->ground_points_ros_cloud_);
+  this->evaluated_segmentation_pointcloud_publisher_.publish(this->evaluated_segmentation_pointcloud_ros_cloud_);
 
   // Roadmap topics
   this->roadmap_edges_publisher_.publish(this->roadmap_edges_array_);
@@ -657,9 +672,44 @@ void GroundSegmentationAlgNode::showPerformanceStatistics(void)
   std::cout << "--------------------- ALGORITHM: ---------------------------------" << std::endl;
   this->alg_.showPerformanceStatistics();
   std::cout << "-------------------------------------------------------------------------------" << std::endl;
-//  std::cout << "--------------------- PROCESSOR: ---------------------------------" << std::endl;
-//  this->alg_.processor_.showPerformanceStatistics();
-//  std::cout << "-------------------------------------------------------------------------------" << std::endl;
+
+  //    std::cout << "TN_due_to_unknown_points = " << TN_due_to_unknown_points << std::endl;
+  //    std::cout << "FN_due_to_unknown_points = " << FN_due_to_unknown_points << std::endl;
+  //
+  //    std::cout << "number_of_evaluated_points = " << number_of_evaluated_points << std::endl;
+
+  evaluation_metrics_.prec = (float)evaluation_metrics_.tp / (float)(evaluation_metrics_.tp + evaluation_metrics_.fp);
+
+  evaluation_metrics_.rec = (float)evaluation_metrics_.tp / (float)(evaluation_metrics_.tp + evaluation_metrics_.fn);
+
+  evaluation_metrics_.f1 = (2.0 * evaluation_metrics_.prec * evaluation_metrics_.rec)
+  / (evaluation_metrics_.prec + evaluation_metrics_.rec);
+
+  evaluation_metrics_.iou = (float)evaluation_metrics_.tp
+  / (float)(evaluation_metrics_.tp + evaluation_metrics_.fp
+      + evaluation_metrics_.fn);
+
+  evaluation_metrics_.acc = (float)(evaluation_metrics_.tp + evaluation_metrics_.tn)
+      / (float)(evaluation_metrics_.tp + evaluation_metrics_.tn + evaluation_metrics_.fp + evaluation_metrics_.fn);
+
+  evaluation_metrics_.kor = (float)evaluation_metrics_.key_obstacle_true_positives
+      / (float)(evaluation_metrics_.key_obstacle_true_positives + evaluation_metrics_.key_obstacle_false_negatives);
+
+  std::cout << "Statistics: " << std::endl;
+  std::cout << "TP = " << evaluation_metrics_.tp << std::endl;
+  std::cout << "FP = " << evaluation_metrics_.fp << std::endl;
+
+  std::cout << "TN = " << evaluation_metrics_.tn << std::endl;
+  std::cout << "FN = " << evaluation_metrics_.fn << std::endl;
+
+  std::cout << "Precision = " << evaluation_metrics_.prec << std::endl;
+  std::cout << "Recall    = " << evaluation_metrics_.rec  << std::endl;
+
+  std::cout << "F1        = " << evaluation_metrics_.f1 << std::endl;
+  std::cout << "Acc       = " << evaluation_metrics_.acc << std::endl;
+  std::cout << "IoU       = " << evaluation_metrics_.iou << std::endl;
+
+  std::cout << "KOR = " << evaluation_metrics_.kor << std::endl;
 }
 
 struct Cell
@@ -764,10 +814,122 @@ void GroundSegmentationAlgNode::evaluateSegmentation(void)
     pcl::PointXYZRGBNormal classified_point = *i;
     pcl::PointXYZRGBNormal gt_point = *gt_i;
 
-//    if ((int)std::floor(data_c[DATA_C_1_ID_CLASS]) == CLASS_GROUND)
-//    {
-//
-//    }
+    int gt_label = gt_point.data_c[DATA_C_1_ID_CLASS];
+
+    // Condensing the labels into bigger semantic meanings
+    bool gt_exclude_from_evaluation = false;
+    if (gt_label == OUTLIER || gt_label == UNLABELED || gt_label == OTHER_STRUCTURE || gt_label == OTHER_OBJECT)
+      gt_exclude_from_evaluation = true;
+
+    bool gt_ground_point = false;
+    bool gt_ordinary_obstacle_point = false;
+
+    // Extracting info from our segmentation algorithm
+    //std::cout << "Detected class + score as comes in the message = " << (float)it->data_c[DATA_C_1_ID_CLASS] << std::endl;
+    int detected_class = (int)std::floor(i->data_c[DATA_C_1_ID_CLASS]);
+    //std::cout << "detected_class = " << detected_class << std::endl;
+    float detection_score = i->data_c[DATA_C_1_ID_CLASS] - (float)detected_class; //we package the score_thres as decimal part of the label
+    //std::cout << "detection_score = " << detection_score << std::endl;
+
+    bool flag_not_analyzed_point = false; // Just to keep track of which TN and FN are due to the unknown points
+    if (detected_class == CLASS_UNKNOWN)
+      flag_not_analyzed_point = true;
+
+    if (flag_only_road_is_traversable_)
+    {
+      if (detected_class == ROAD || detected_class == CLASS_GROUND)
+        detected_class = CLASS_GROUND;
+      else
+        detected_class = CLASS_OBSTACLE;
+
+      if (gt_label == ROAD)
+        gt_ground_point = true;
+
+      if (gt_label == BUILDING || gt_label == FENCE || gt_label == TRUNK || gt_label == POLE || gt_label == TRAFFIC_SIGN
+          || gt_label == VEGETATION || gt_label == OTHER_GROUND || gt_label == LANE_MARKING || gt_label == TERRAIN
+          || gt_label == SIDEWALK || gt_label == PARKING)
+        gt_ordinary_obstacle_point = true;
+    }
+    else
+    {
+      if (detected_class == VEGETATION || detected_class == CLASS_UNKNOWN || detected_class == CLASS_OBSTACLE
+          || detected_class == CLASS_OVERHANGING_OBSTACLE || detected_class == TERRAIN)
+        detected_class = CLASS_OBSTACLE;
+      else
+        detected_class = CLASS_GROUND;
+
+      if (gt_label == ROAD || gt_label == PARKING || gt_label == SIDEWALK || gt_label == OTHER_GROUND
+          || gt_label == LANE_MARKING)
+        gt_ground_point = true;
+
+      if (gt_label == BUILDING || gt_label == FENCE || gt_label == TRUNK || gt_label == POLE || gt_label == TRAFFIC_SIGN
+          || gt_label == VEGETATION || gt_label == TERRAIN)
+        gt_ordinary_obstacle_point = true;
+    }
+
+    bool gt_key_obstacle = false;
+    if (!gt_exclude_from_evaluation && !gt_ground_point && !gt_ordinary_obstacle_point)
+      gt_key_obstacle = true;
+
+    if (!gt_exclude_from_evaluation)
+    {
+      bool gt_transversable = false;
+      if (gt_ground_point)
+        gt_transversable = true;
+
+      bool transversable = false;
+      if (detected_class == CLASS_GROUND)
+        transversable = true;
+
+      if (gt_transversable && transversable)
+      {
+        evaluation_metrics_.tp++;
+        gt_i->r = 0;
+        gt_i->g = 0;
+        gt_i->b = 255;
+      }
+
+      if (gt_transversable && !transversable)
+      {
+        evaluation_metrics_.fn++;
+        gt_i->r = 0;
+        gt_i->g = 255;
+        gt_i->b = 255;
+        if (flag_not_analyzed_point)
+          evaluation_metrics_.FN_due_to_unknown_points++;
+      }
+
+      if (!gt_transversable && transversable)
+      {
+        evaluation_metrics_.fp++;
+        gt_i->r = 255;
+        gt_i->g = 0;
+        gt_i->b = 0;
+      }
+
+      if (!gt_transversable && !transversable)
+      {
+        evaluation_metrics_.tn++;
+        gt_i->r = 0;
+        gt_i->g = 255;
+        gt_i->b = 0;
+        if (flag_not_analyzed_point)
+          evaluation_metrics_.TN_due_to_unknown_points++;
+      }
+
+      // evaluating KEY OBSTACLES /////////////////////////////////////////
+      if (gt_key_obstacle && !transversable)
+        evaluation_metrics_.key_obstacle_true_positives++;
+
+      if (gt_key_obstacle && transversable)
+        evaluation_metrics_.key_obstacle_false_negatives++;
+    }
+    else
+    {
+      gt_i->r = 127;
+      gt_i->g = 127;
+      gt_i->b = 127;
+    }
     ++gt_i;
   }
   return;
@@ -815,7 +977,7 @@ void GroundSegmentationAlgNode::cb_lidar(const sensor_msgs::PointCloud2::ConstPt
 {
   this->mutex_enter();
   lidar_ros_cloud_ = *msg;
-  //std::cout << "GroundSegmentationAlgNode::cb_lidar --> lidar msg received!" << std::endl;
+//std::cout << "GroundSegmentationAlgNode::cb_lidar --> lidar msg received!" << std::endl;
   assert(msg != NULL && "Null pointer!!! in function cb_lidar!");
 
   flag_new_lidar_data_ = true;
@@ -827,7 +989,7 @@ void GroundSegmentationAlgNode::cb_ground_truth_lidar(const sensor_msgs::PointCl
 {
   this->mutex_enter();
   lidar_ros_cloud_ = *msg;
-  //std::cout << "GroundSegmentationAlgNode::cb_lidar --> lidar msg received!" << std::endl;
+//std::cout << "GroundSegmentationAlgNode::cb_lidar --> lidar msg received!" << std::endl;
   assert(msg != NULL && "Null pointer!!! in function cb_lidar!");
 
   flag_new_ground_truth_lidar_data_ = true;
@@ -859,45 +1021,45 @@ void GroundSegmentationAlgNode::node_config_update(Config &config, uint32_t leve
   if (config_.rate != this->getRate())
     this->setRate(config_.rate);
 
-  // Robot related geometric parameters
+// Robot related geometric parameters
   this->alg_.lidar_configuration_.sensor_height = config.sensor_height;
   this->alg_.filtering_configuration_.robot_height = config.robot_height;
 
-  // Parameters affecting the exploration of the pointcloud
+// Parameters affecting the exploration of the pointcloud
   this->alg_.filtering_configuration_.ROI_delta_x_and_y = config.ROI_delta_x_and_y;
   this->alg_.filtering_configuration_.ROI_shadow_area = config.ROI_shadow_area;
   this->alg_.filtering_configuration_.ground_reference_search_resolution = config.ground_reference_search_resolution_deg
       * M_PI / 180.0;
   this->alg_.filtering_configuration_.elevation_grid_resolution = config.elevation_grid_resolution;
 
-  // Kalman filter noise parameters
-  // Initial uncertainties
+// Kalman filter noise parameters
+// Initial uncertainties
   this->alg_.filtering_configuration_.z_initial_std_dev = config.z_initial_std_dev;
   this->alg_.filtering_configuration_.roll_initial_std_dev = tan(config.initial_angular_std_dev_deg * M_PI / 180.0);
   this->alg_.filtering_configuration_.pitch_initial_std_dev = tan(config.initial_angular_std_dev_deg * M_PI / 180.0);
-  // Propagation additive noises
+// Propagation additive noises
   this->alg_.filtering_configuration_.propagation_z_additive_noise = config.propagation_z_additive_noise_per_meter;
   this->alg_.filtering_configuration_.propagation_additive_noise = tan(
       config.propagation_additive_noise_deg_per_meter * M_PI / 180.0);
-  // Measurement noise
+// Measurement noise
   this->alg_.filtering_configuration_.z_observation_std_dev = config.z_observation_std_dev;
 
-  // threshold for outlier rejection and classification
+// threshold for outlier rejection and classification
   this->alg_.filtering_configuration_.mahalanobis_threshold = config.mahalanobis_threshold;
 
-  // labeling parameters
+// labeling parameters
   this->alg_.filtering_configuration_.score_threshold = config_.score_threshold;
   this->alg_.filtering_configuration_.max_pred_std_dev_for_labelling = config.max_pred_std_dev_for_labelling;
   this->alg_.filtering_configuration_.classify_not_labeled_points_as_obstacles =
       config_.classify_not_labeled_points_as_obstacles;
 
-  // Low obstacles detection parameters
+// Low obstacles detection parameters
   this->flag_use_low_obstacle_detection_ = config.use_low_obstacle_detection;
   this->alg_.filtering_configuration_.low_obstacle_min_height = config_.low_obstacle_min_height;
   this->alg_.filtering_configuration_.sensor_best_resolution_deg = config_.sensor_best_resolution_deg;
   this->alg_.filtering_configuration_.max_navigation_slope = config_.max_navigation_slope;
 
-  // visualization and debug parameters
+// visualization and debug parameters
   this->alg_.filtering_configuration_.measure_performance = config.measure_performance;
   this->alg_.filtering_configuration_.show_dense_reconstruction = config.show_dense_reconstruction;