From 800eb229b27f00d24eb1c3c34ee2ab7c63ce7567 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20del=20Pino?= <idelpino@iri.upc.edu>
Date: Wed, 13 Jul 2022 08:30:49 +0200
Subject: [PATCH] improved fast labelling, now achieving even better results
 than with the slow method!

---
 src/kf_based_terrain_analysis.cpp | 205 +++++++-----------------------
 1 file changed, 48 insertions(+), 157 deletions(-)

diff --git a/src/kf_based_terrain_analysis.cpp b/src/kf_based_terrain_analysis.cpp
index dd3c622..66baf53 100644
--- a/src/kf_based_terrain_analysis.cpp
+++ b/src/kf_based_terrain_analysis.cpp
@@ -367,30 +367,40 @@ void CKf_Based_Terrain_Analysis::labelLocalGroundPoints(
             elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]]);
       }
 
-      //std::cout << "Updating elevation cloud point to represent ground data" << std::endl;
-      if ((int)std::floor(point_in_sensor_frame.data_c[DATA_C_1_ID_CLASS]) != CLASS_GROUND) // if the point was seen as obstacle from another POV
-                                                                                            // or was unexplored, with set it to ground class
-      {
-        //std::cout << "Storing z point as z ground" << std::endl;
-        // as now the point is classified as ground, we store its own z value as z ground
-        elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_n[DATA_N_1_Z_GROUND] =
-            elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].z;
+      // now we compute the score
+      float score = 0.99 - (mahalanobis_distance / filtering_configuration.mahalanobis_threshold);
+      if (score < 0.0)
+        score = 0.0;
 
-        // set the class as ground
-        float score = 0.99 - (mahalanobis_distance / filtering_configuration.mahalanobis_threshold);
-        if (score < 0.0)
-          score = 0.0;
-        elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_c[DATA_C_1_ID_CLASS] =
-            (float)CLASS_GROUND + score;
-
-        // colour the point properly
-        elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].r = R_CLASS_GROUND;
-        elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].g = G_CLASS_GROUND;
-        elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].b = B_CLASS_GROUND;
+      float index_of_labelling_ref =
+          elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_c[DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL];
 
-        // and store the reference for the later full pointcloud labelling step
+      //std::cout << "Updating elevation cloud point to represent ground data" << std::endl;
+      if ((int)std::floor(point_in_sensor_frame.data_c[DATA_C_1_ID_CLASS]) != CLASS_GROUND
+          || std::floor((int)index_of_labelling_ref) == INDEX_UNKNOWN
+          || index_of_labelling_ref - std::floor((int)index_of_labelling_ref) < score) // if the point was seen as obstacle from another POV
+                                                                                       // or was unexplored, with set it to ground class
+      {
+        // and store the reference for the later full pointcloud labelling step (only if the score is better than the previous label
         elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_c[DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL] =
-            reference_index;
+            reference_index + score;
+
+        if ((int)std::floor(point_in_sensor_frame.data_c[DATA_C_1_ID_CLASS]) != CLASS_GROUND)
+        {
+          //std::cout << "Storing z point as z ground" << std::endl;
+          // as now the point is classified as ground, we store its own z value as z ground
+          elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_n[DATA_N_1_Z_GROUND] =
+              elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].z;
+
+          // set the class as ground
+          elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_c[DATA_C_1_ID_CLASS] =
+              (float)CLASS_GROUND + score;
+
+          // colour the point properly
+          elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].r = R_CLASS_GROUND;
+          elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].g = G_CLASS_GROUND;
+          elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].b = B_CLASS_GROUND;
+        }
       }
     }
     else
@@ -399,9 +409,23 @@ void CKf_Based_Terrain_Analysis::labelLocalGroundPoints(
       //    << "    z = " << point_in_sensor_frame.z << std::endl << "mahalanobis_distance = " << mahalanobis_distance
       //    << "    mahalanobis_threshold = " << filtering_configuration.mahalanobis_threshold << std::endl;
 
-      if ((int)std::floor(point_in_sensor_frame.data_c[DATA_C_1_ID_CLASS]) == CLASS_UNKNOWN) // we only store the data if it has not been done
-                                                                                             // previously
+      if ((int)std::floor(point_in_sensor_frame.data_c[DATA_C_1_ID_CLASS]) != CLASS_GROUND) // we don't want to convert ground points to obstacles
+                                                                                            // because of the POV (one thing can be seem as obstacle or ground depending on the POV)
       {
+        // Now we compute the score
+        float score = (mahalanobis_distance / filtering_configuration.mahalanobis_threshold) - 1.0;
+        if (score > 0.99)
+          score = 0.99;
+
+        // Now we check the score of the previous detection
+        float index_of_labelling_ref =
+            elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_c[DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL];
+
+        if (std::floor((int)index_of_labelling_ref) == INDEX_UNKNOWN
+            || index_of_labelling_ref - std::floor((int)index_of_labelling_ref) < score)
+          elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_c[DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL] =
+              reference_index + score;
+
         // if it is an obstacle point we use the ground reference z prediction as z ground
         float z_ground = predictZ(ground_reference_cloud_ptr->points[reference_index], point_in_sensor_frame.x,
                                   point_in_sensor_frame.y);
@@ -410,16 +434,13 @@ void CKf_Based_Terrain_Analysis::labelLocalGroundPoints(
 
         // set the class to OBSTACLE
         elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_c[DATA_C_1_ID_CLASS] =
-            (float)CLASS_OBSTACLE + 0.99;
+            (float)CLASS_OBSTACLE + score; //0.99;
 
         // and colour the point
         elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].r = R_CLASS_OBSTACLE;
         elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].g = G_CLASS_OBSTACLE;
         elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].b = B_CLASS_OBSTACLE;
       }
-      // and store the reference for the later full pointcloud labelling step
-      elevation_cloud_ptr->points[point_in_sensor_frame.data_c[DATA_C_3_ORIGINAL_INDEX]].data_c[DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL] =
-          reference_index;
     }
   }
   //std::cout << "Observations for local tangent plane estimation extracted!" << std::endl;
@@ -594,136 +615,6 @@ void CKf_Based_Terrain_Analysis::labelGroundPoints(
 //  getchar();
 }
 
-// Just a try to optimize this function, it turned out to be slower :(
-//void CKf_Based_Terrain_Analysis::generateElevationCloud(
-//    const kf_based_terrain_analysis_lib::FilteringConfiguration filtering_configuration,
-//    pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr pcl_cloud_ptr,
-//    pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr elevation_cloud, std::vector<std::vector<int>> &correspondence_indexes)
-//{
-//  //if (filtering_configuration.measure_performance)
-//  CFunctionMonitor performance_monitor("generateElevationCloud", performance_supervisor_ptr_);
-//
-//  int i = 0;
-//  for (pcl::PointCloud<pcl::PointXYZRGBNormal>::iterator it = pcl_cloud_ptr->begin(); it != pcl_cloud_ptr->end();
-//      ++it)
-//    it->data_c[DATA_C_3_ORIGINAL_INDEX] = i++;
-//
-//  // We want to find the x and y values, but not interested in z
-//  //std::cout << "Elevation grid resolution = " << filtering_configuration.elevation_grid_resolution << std::endl;
-//  pcl::VoxelGrid < pcl::PointXYZRGBNormal > voxel_grid;
-//  voxel_grid.setInputCloud(pcl_cloud_ptr);
-//  voxel_grid.setLeafSize(filtering_configuration.elevation_grid_resolution,
-//                         filtering_configuration.elevation_grid_resolution, OUT_OF_RANGE);
-//  voxel_grid.filter(*elevation_cloud);
-//  //std::cout << "Number of points after voxelization = " << elevation_cloud->points.size() << std::endl;
-//
-//  pcl::PassThrough < pcl::PointXYZRGBNormal > pass;
-//  pass.setInputCloud(pcl_cloud_ptr);
-//
-//  i = 0;
-//  for (pcl::PointCloud<pcl::PointXYZRGBNormal>::iterator it = elevation_cloud->begin(); it != elevation_cloud->end();
-//      ++it)
-//  {
-//    float x_min, x_max, y_min, y_max, x_search_range, y_search_range;
-//
-//    x_search_range = filtering_configuration.elevation_grid_resolution;
-//    y_search_range = filtering_configuration.elevation_grid_resolution;
-//
-//    x_min = it->x - x_search_range;
-//    y_min = it->y - y_search_range;
-//    x_max = it->x + x_search_range;
-//    y_max = it->y + y_search_range;
-//
-//    pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr points_in_cell(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
-//
-//    // Extracting lidar points
-//    pass.setFilterFieldName("x");
-//    pass.setFilterLimits(x_min, x_max);
-//    pass.filter(*points_in_cell);
-//    pass.setInputCloud(points_in_cell);
-//    pass.setFilterFieldName("y");
-//    pass.setFilterLimits(y_min, y_max);
-//    pass.filter(*points_in_cell);
-//
-//    std::vector<int> pointIdxRadiusSearch;
-//    for (pcl::PointCloud<pcl::PointXYZRGBNormal>::iterator cell_point_iterator = points_in_cell->begin();
-//        cell_point_iterator != points_in_cell->end(); ++cell_point_iterator)
-//    {
-//      //std::cout << "id = " << cell_point_iterator->data_c[DATA_C_3_ORIGINAL_INDEX] << std::endl;
-//      pointIdxRadiusSearch.push_back(cell_point_iterator->data_c[DATA_C_3_ORIGINAL_INDEX]);
-//    }
-//    //std::cout << "Total number of points in cell = " << pointIdxRadiusSearch.size() << std::endl;
-//
-//    std::vector<float> z_coordinates;
-//    std::vector<float> x_coordinates;
-//    std::vector<float> y_coordinates;
-//
-//    bool outlier_detected = false;
-//    for (std::vector<int>::const_iterator iterator = pointIdxRadiusSearch.begin();
-//        iterator != pointIdxRadiusSearch.end(); ++iterator)
-//    {
-//      //std::cout << "storing coordinates of point in cell with id = " << *iterator << std::endl;
-//      z_coordinates.push_back(pcl_cloud_ptr->points[*iterator].z);
-//      x_coordinates.push_back(pcl_cloud_ptr->points[*iterator].x);
-//      y_coordinates.push_back(pcl_cloud_ptr->points[*iterator].y);
-//
-//      if (pcl_cloud_ptr->points[*iterator].data_c[DATA_C_1_ID_CLASS] == OUTLIER)
-//        outlier_detected = true;
-//    }
-//
-//    if (outlier_detected)
-//    {
-//      //std::cout << "Outlier detected!" << std::endl;
-//      it->data_c[DATA_C_1_ID_CLASS] = OUTLIER;
-//      it->r = R_CLASS_OUTLIER;
-//      it->g = G_CLASS_OUTLIER;
-//      it->b = B_CLASS_OUTLIER;
-//    }
-//    else
-//    {
-//      //std::cout << "Not outlier, setting points to unknown class" << std::endl;
-//      it->data_c[DATA_C_1_ID_CLASS] = CLASS_UNKNOWN;
-//      it->r = R_CLASS_UNKNOWN;
-//      it->g = G_CLASS_UNKNOWN;
-//      it->b = B_CLASS_UNKNOWN;
-//    }
-//
-//    //std::cout << "Computing cell statistics!" << std::endl;
-//    float sum = std::accumulate(z_coordinates.begin(), z_coordinates.end(), 0.0);
-//    float z_mean = sum / (float)z_coordinates.size();
-//    float var = 0;
-//    for (int n = 0; n < z_coordinates.size(); ++n)
-//      var += ((z_coordinates[n] - z_mean) * (z_coordinates[n] - z_mean));
-//
-//    var /= (float)z_coordinates.size();
-//
-//    //std::cout << "Retrieving the position of the lowest point in cell..." << std::endl;
-//    std::vector<float>::iterator lowest_point_in_cell = std::min_element(z_coordinates.begin(), z_coordinates.end());
-//    int position_in_vector = std::distance(z_coordinates.begin(), lowest_point_in_cell);
-//
-//    it->z = z_coordinates[position_in_vector];
-//    it->x = x_coordinates[position_in_vector];
-//    it->y = y_coordinates[position_in_vector];
-//
-//    //std::cout << "Filling remaining fields" << std::endl;
-//    it->data_n[DATA_N_0_INTENSITY] = INTENSITY_UNKNOWN;
-//    it->data_n[DATA_N_1_Z_GROUND] = Z_GROUND_UNKNOWN;
-//    it->data_n[DATA_N_2_Z_MEAN] = z_mean;
-//    it->data_n[DATA_N_3_Z_VARIANCE] = var;
-//
-//    it->data_c[DATA_C_2_CAR_PROB] = PROB_UNKNOWN;
-//
-//    //std::cout << "storing the index for later in labelling step" << std::endl;
-//    it->data_c[DATA_C_3_ORIGINAL_INDEX] = i++;
-//
-//    //std::cout << "var z = " << it->data_n[DATA_N_3_Z_VARIANCE] << std::endl;
-//    //std::cout << "z_coordinates.size() = " << z_coordinates.size() << std::endl;
-//
-//    //std::cout << "storing the vector of indexes" << std::endl;
-//    correspondence_indexes.push_back(pointIdxRadiusSearch);
-//  }
-//}
-
 void CKf_Based_Terrain_Analysis::generateElevationCloud(
     const kf_based_terrain_analysis_lib::FilteringConfiguration filtering_configuration,
     pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr pcl_cloud_ptr,
-- 
GitLab