From 6f1695f9e3b47812de6324cb673699da8c8cdb25 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 12:17:35 +0200 Subject: [PATCH] improved optimized elevation cloud generation to avoid running out of memory --- src/kf_based_terrain_analysis.cpp | 242 ++++++++++++++++++++++-------- 1 file changed, 176 insertions(+), 66 deletions(-) diff --git a/src/kf_based_terrain_analysis.cpp b/src/kf_based_terrain_analysis.cpp index 978c863..0ff31b1 100644 --- a/src/kf_based_terrain_analysis.cpp +++ b/src/kf_based_terrain_analysis.cpp @@ -734,97 +734,206 @@ void CKf_Based_Terrain_Analysis::fastGenerateElevationCloud( int number_of_rows_and_columns = std::ceil(2.0 * MAX_RANGE / filtering_configuration.elevation_grid_resolution); //std::cout << "number_of_rows_and_columns = " << number_of_rows_and_columns << std::endl; - kf_based_terrain_analysis_lib::ElevationCloudCell elevation_map[number_of_rows_and_columns][number_of_rows_and_columns]; + int elevation_map[number_of_rows_and_columns][number_of_rows_and_columns]; + for (int i = 0; i < number_of_rows_and_columns; ++i) + for (int j = 0; j < number_of_rows_and_columns; ++j) + elevation_map[i][j] = INDEX_UNKNOWN; //std::cout << "elevation_map created! " << std::endl; + std::vector<kf_based_terrain_analysis_lib::ElevationCloudCell> elevation_cell_vector; + int i = 0; //std::cout << "Starting to fill the elevation_map! " << std::endl; for (pcl::PointCloud<pcl::PointXYZRGBNormal>::const_iterator it = pcl_cloud_ptr->begin(); it != pcl_cloud_ptr->end(); ++it) { - int row = std::round((number_of_rows_and_columns / 2.0) + (it->x / filtering_configuration.elevation_grid_resolution)); - int col = std::round((number_of_rows_and_columns / 2.0) + (it->y / filtering_configuration.elevation_grid_resolution)); + int row = std::round( + (number_of_rows_and_columns / 2.0) + (it->x / filtering_configuration.elevation_grid_resolution)); + int col = std::round( + (number_of_rows_and_columns / 2.0) + (it->y / filtering_configuration.elevation_grid_resolution)); - if(elevation_map[row][col].indexes_of_points_in_cell.empty()) + if (elevation_map[row][col] == INDEX_UNKNOWN) { + elevation_map[row][col] = elevation_cell_vector.size(); + kf_based_terrain_analysis_lib::ElevationCloudCell new_cell; //std::cout << "Pointing to an empty cell, storing current point as lowest, and keeping its index! " << std::endl; //std::cout << "Point number " << i << " row = " << row << " col = " << col << std::endl; - elevation_map[row][col].lowest_point_in_cell = *it; - elevation_map[row][col].index_of_lowest_point = i; + new_cell.lowest_point_in_cell = *it; + new_cell.index_of_lowest_point = i; + elevation_cell_vector.push_back(new_cell); } else { //std::cout << "Pointing to a NON-empty cell! checking z!" << std::endl; - if(it->z < elevation_map[row][col].lowest_point_in_cell.z) + if (it->z < elevation_cell_vector[elevation_map[row][col]].lowest_point_in_cell.z) { //std::cout << "Current point is the lowest, storing it as it is!" << std::endl; - elevation_map[row][col].lowest_point_in_cell = *it; - elevation_map[row][col].index_of_lowest_point = i; + elevation_cell_vector[elevation_map[row][col]].lowest_point_in_cell = *it; + elevation_cell_vector[elevation_map[row][col]].index_of_lowest_point = i; } } //std::cout << "Storing z coordinate and index in the indexes vector" << std::endl; - elevation_map[row][col].z_coordinates.push_back(it->z); - elevation_map[row][col].indexes_of_points_in_cell.push_back(i); + elevation_cell_vector[elevation_map[row][col]].z_coordinates.push_back(it->z); + elevation_cell_vector[elevation_map[row][col]].indexes_of_points_in_cell.push_back(i); i++; } //std::cout << "Now generating the elevation cloud from the elevation map!" << std::endl; //DEBUG //int total_number_of_points_stored = 0; - int index_respect_elevation_cloud = 0; - for(int row = 0; row < number_of_rows_and_columns; ++row) + + for (int i = 0; i < elevation_cell_vector.size(); ++i) { - for(int col = 0; col < number_of_rows_and_columns; ++col) + pcl::PointXYZRGBNormal elevation_cloud_point = elevation_cell_vector[i].lowest_point_in_cell; + if (elevation_cloud_point.data_c[DATA_C_1_ID_CLASS] == OUTLIER) { - if(!elevation_map[row][col].indexes_of_points_in_cell.empty()) - { - pcl::PointXYZRGBNormal elevation_cloud_point = elevation_map[row][col].lowest_point_in_cell; - if (elevation_cloud_point.data_c[DATA_C_1_ID_CLASS] == OUTLIER) - { - elevation_cloud_point.r = R_CLASS_OUTLIER; - elevation_cloud_point.g = G_CLASS_OUTLIER; - elevation_cloud_point.b = B_CLASS_OUTLIER; - } - else - { - elevation_cloud_point.r = R_CLASS_UNKNOWN; - elevation_cloud_point.g = G_CLASS_UNKNOWN; - elevation_cloud_point.b = B_CLASS_UNKNOWN; - } - float sum = std::accumulate(elevation_map[row][col].z_coordinates.begin(), elevation_map[row][col].z_coordinates.end(), 0.0); - float z_mean = sum / (float)elevation_map[row][col].z_coordinates.size(); - float var = 0; - for (int n = 0; n < elevation_map[row][col].z_coordinates.size(); ++n) - var += ((elevation_map[row][col].z_coordinates[n] - z_mean) * (elevation_map[row][col].z_coordinates[n] - z_mean)); + elevation_cloud_point.r = R_CLASS_OUTLIER; + elevation_cloud_point.g = G_CLASS_OUTLIER; + elevation_cloud_point.b = B_CLASS_OUTLIER; + } + else + { + elevation_cloud_point.r = R_CLASS_UNKNOWN; + elevation_cloud_point.g = G_CLASS_UNKNOWN; + elevation_cloud_point.b = B_CLASS_UNKNOWN; + } + float sum = std::accumulate(elevation_cell_vector[i].z_coordinates.begin(), + elevation_cell_vector[i].z_coordinates.end(), 0.0); + float z_mean = sum / (float)elevation_cell_vector[i].z_coordinates.size(); + float var = 0; + for (int n = 0; n < elevation_cell_vector[i].z_coordinates.size(); ++n) + var += ((elevation_cell_vector[i].z_coordinates[n] - z_mean) + * (elevation_cell_vector[i].z_coordinates[n] - z_mean)); - var /= (float)elevation_map[row][col].z_coordinates.size(); + var /= (float)elevation_cell_vector[i].z_coordinates.size(); - // Filling remaining fields - elevation_cloud_point.data_n[DATA_N_0_INTENSITY] = INTENSITY_UNKNOWN; - elevation_cloud_point.data_n[DATA_N_1_Z_GROUND] = Z_GROUND_UNKNOWN; - elevation_cloud_point.data_n[DATA_N_2_Z_MEAN] = z_mean; - elevation_cloud_point.data_n[DATA_N_3_Z_VARIANCE] = var; + // Filling remaining fields + elevation_cloud_point.data_n[DATA_N_0_INTENSITY] = INTENSITY_UNKNOWN; + elevation_cloud_point.data_n[DATA_N_1_Z_GROUND] = Z_GROUND_UNKNOWN; + elevation_cloud_point.data_n[DATA_N_2_Z_MEAN] = z_mean; + elevation_cloud_point.data_n[DATA_N_3_Z_VARIANCE] = var; - elevation_cloud_point.data_c[DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL] = INDEX_UNKNOWN; - elevation_cloud_point.data_c[DATA_C_3_ORIGINAL_INDEX] = index_respect_elevation_cloud++; //storing the index for later in labelling step + elevation_cloud_point.data_c[DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL] = INDEX_UNKNOWN; + elevation_cloud_point.data_c[DATA_C_3_ORIGINAL_INDEX] = i; //storing the index for later in labelling step - //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 << "var z = " << it->data_n[DATA_N_3_Z_VARIANCE] << std::endl; + //std::cout << "elevation_cell_vector[i].z_coordinates.size() = " << z_coordinates.size() << std::endl; - //DEBUG! - //total_number_of_points_stored += elevation_map[row][col].indexes_of_points_in_cell.size(); + //DEBUG! + //total_number_of_points_stored += elevation_map[row][col].indexes_of_points_in_cell.size(); - correspondence_indexes.push_back(elevation_map[row][col].indexes_of_points_in_cell); - //std::cout << "Storing point into elevation cloud!" << std::endl; - elevation_cloud->push_back(elevation_cloud_point); - } - } + correspondence_indexes.push_back(elevation_cell_vector[i].indexes_of_points_in_cell); + //std::cout << "Storing point into elevation cloud!" << std::endl; + elevation_cloud->push_back(elevation_cloud_point); } -// std::cout << "elevation_cloud generated!!" << std::endl; + //std::cout << "elevation_cloud generated!!" << std::endl; // //std::cout << "total_number_of_points_stored = " << total_number_of_points_stored << std::endl; // //std::cout << "original number of points = " << pcl_cloud_ptr->points.size() << std::endl; } +/* + void CKf_Based_Terrain_Analysis::fastGenerateElevationCloud( + 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 number_of_rows_and_columns = std::ceil(2.0 * MAX_RANGE / filtering_configuration.elevation_grid_resolution); + //std::cout << "number_of_rows_and_columns = " << number_of_rows_and_columns << std::endl; + + kf_based_terrain_analysis_lib::ElevationCloudCell elevation_map[number_of_rows_and_columns][number_of_rows_and_columns]; + //std::cout << "elevation_map created! " << std::endl; + + int i = 0; + //std::cout << "Starting to fill the elevation_map! " << std::endl; + for (pcl::PointCloud<pcl::PointXYZRGBNormal>::const_iterator it = pcl_cloud_ptr->begin(); it != pcl_cloud_ptr->end(); + ++it) + { + int row = std::round((number_of_rows_and_columns / 2.0) + (it->x / filtering_configuration.elevation_grid_resolution)); + int col = std::round((number_of_rows_and_columns / 2.0) + (it->y / filtering_configuration.elevation_grid_resolution)); + + if(elevation_map[row][col].indexes_of_points_in_cell.empty()) + { + //std::cout << "Pointing to an empty cell, storing current point as lowest, and keeping its index! " << std::endl; + //std::cout << "Point number " << i << " row = " << row << " col = " << col << std::endl; + elevation_map[row][col].lowest_point_in_cell = *it; + elevation_map[row][col].index_of_lowest_point = i; + } + else + { + //std::cout << "Pointing to a NON-empty cell! checking z!" << std::endl; + if(it->z < elevation_map[row][col].lowest_point_in_cell.z) + { + //std::cout << "Current point is the lowest, storing it as it is!" << std::endl; + elevation_map[row][col].lowest_point_in_cell = *it; + elevation_map[row][col].index_of_lowest_point = i; + } + } + //std::cout << "Storing z coordinate and index in the indexes vector" << std::endl; + elevation_map[row][col].z_coordinates.push_back(it->z); + elevation_map[row][col].indexes_of_points_in_cell.push_back(i); + i++; + } + + //std::cout << "Now generating the elevation cloud from the elevation map!" << std::endl; + //DEBUG + //int total_number_of_points_stored = 0; + int index_respect_elevation_cloud = 0; + for(int row = 0; row < number_of_rows_and_columns; ++row) + { + for(int col = 0; col < number_of_rows_and_columns; ++col) + { + if(!elevation_map[row][col].indexes_of_points_in_cell.empty()) + { + pcl::PointXYZRGBNormal elevation_cloud_point = elevation_map[row][col].lowest_point_in_cell; + if (elevation_cloud_point.data_c[DATA_C_1_ID_CLASS] == OUTLIER) + { + elevation_cloud_point.r = R_CLASS_OUTLIER; + elevation_cloud_point.g = G_CLASS_OUTLIER; + elevation_cloud_point.b = B_CLASS_OUTLIER; + } + else + { + elevation_cloud_point.r = R_CLASS_UNKNOWN; + elevation_cloud_point.g = G_CLASS_UNKNOWN; + elevation_cloud_point.b = B_CLASS_UNKNOWN; + } + float sum = std::accumulate(elevation_map[row][col].z_coordinates.begin(), elevation_map[row][col].z_coordinates.end(), 0.0); + float z_mean = sum / (float)elevation_map[row][col].z_coordinates.size(); + float var = 0; + for (int n = 0; n < elevation_map[row][col].z_coordinates.size(); ++n) + var += ((elevation_map[row][col].z_coordinates[n] - z_mean) * (elevation_map[row][col].z_coordinates[n] - z_mean)); + + var /= (float)elevation_map[row][col].z_coordinates.size(); + + // Filling remaining fields + elevation_cloud_point.data_n[DATA_N_0_INTENSITY] = INTENSITY_UNKNOWN; + elevation_cloud_point.data_n[DATA_N_1_Z_GROUND] = Z_GROUND_UNKNOWN; + elevation_cloud_point.data_n[DATA_N_2_Z_MEAN] = z_mean; + elevation_cloud_point.data_n[DATA_N_3_Z_VARIANCE] = var; + + elevation_cloud_point.data_c[DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL] = INDEX_UNKNOWN; + elevation_cloud_point.data_c[DATA_C_3_ORIGINAL_INDEX] = index_respect_elevation_cloud++; //storing the index for later in labelling step + + //std::cout << "var z = " << it->data_n[DATA_N_3_Z_VARIANCE] << std::endl; + //std::cout << "z_coordinates.size() = " << z_coordinates.size() << std::endl; + + //DEBUG! + //total_number_of_points_stored += elevation_map[row][col].indexes_of_points_in_cell.size(); + + correspondence_indexes.push_back(elevation_map[row][col].indexes_of_points_in_cell); + //std::cout << "Storing point into elevation cloud!" << std::endl; + elevation_cloud->push_back(elevation_cloud_point); + } + } + } + //std::cout << "elevation_cloud generated!!" << std::endl; + // //std::cout << "total_number_of_points_stored = " << total_number_of_points_stored << std::endl; + // //std::cout << "original number of points = " << pcl_cloud_ptr->points.size() << std::endl; + }*/ + void CKf_Based_Terrain_Analysis::generateRootVertex( const kf_based_terrain_analysis_lib::SensorConfiguration lidar_configuration, const kf_based_terrain_analysis_lib::FilteringConfiguration filtering_configuration, @@ -1198,7 +1307,7 @@ void CKf_Based_Terrain_Analysis::labelPointcloudUsingGroundModel( { pcl::PointXYZRGBNormal point_in_sensor_frame = *i; - // 0) K nearest neighbor search +// 0) K nearest neighbor search pcl::KdTreeFLANN < pcl::PointXYZRGBNormal > kdtree; kdtree.setInputCloud(ground_reference_cloud_ptr); int K = filtering_configuration.number_of_references_used_for_labelling; @@ -1535,8 +1644,8 @@ void CKf_Based_Terrain_Analysis::groundSegmentation( // if (filtering_configuration.measure_performance) // CFunctionMonitor performance_monitor("groundSegmentation", performance_supervisor_ptr_); - //std::cout << "Starting ground segmentation!!" << std::endl; - //std::cout << "Initializing pointcloud: Number of points in pcl_cloud = " << pcl_cloud.points.size() << std::endl; +//std::cout << "Starting ground segmentation!!" << std::endl; +//std::cout << "Initializing pointcloud: Number of points in pcl_cloud = " << pcl_cloud.points.size() << std::endl; pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr pcl_cloud_ptr(new pcl::PointCloud<pcl::PointXYZRGBNormal>); *pcl_cloud_ptr = pcl_cloud; @@ -1548,15 +1657,16 @@ void CKf_Based_Terrain_Analysis::groundSegmentation( pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr elevation_cloud_ptr(new pcl::PointCloud<pcl::PointXYZRGBNormal>); std::vector < std::vector<int> > correspondence_indexes; - fastGenerateElevationCloud(filtering_configuration, pcl_cloud_ptr, elevation_cloud_ptr, correspondence_indexes); + if (filtering_configuration.number_of_references_used_for_labelling > 0) + { + generateElevationCloud(filtering_configuration, pcl_cloud_ptr, elevation_cloud_ptr, correspondence_indexes); + } + else + { + fastGenerateElevationCloud(filtering_configuration, pcl_cloud_ptr, elevation_cloud_ptr, correspondence_indexes); + } //std::cout << "Elevation cloud generated! Npoints = " << elevation_cloud_ptr->points.size() << std::endl; -// pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr fast_elevation_cloud_ptr(new pcl::PointCloud<pcl::PointXYZRGBNormal>); -// std::vector < std::vector<int> > fast_correspondence_indexes; -// -// fastGenerateElevationCloud(filtering_configuration, pcl_cloud_ptr, fast_elevation_cloud_ptr, fast_correspondence_indexes); -// std::cout << "Fast Elevation cloud generated! Npoints = " << fast_elevation_cloud_ptr->points.size() << std::endl; - generateRootVertex(lidar_configuration, filtering_configuration, ground_reference_cloud_ptr); //std::cout << "Root vertex generated! Num of points = " << ground_reference_cloud_ptr->points.size() << std::endl; // << "Number of edges = " << edges[0].size() << std::endl; @@ -1589,8 +1699,8 @@ void CKf_Based_Terrain_Analysis::groundSegmentation( //std::cout << "Total number of references = " << ground_reference_cloud_ptr->points.size() << std::endl; //getchar(); - // We can discard ground references if they are not connected with any other, to test this, we need - // to be sure that connections are reflected in both ends +// We can discard ground references if they are not connected with any other, to test this, we need +// to be sure that connections are reflected in both ends ensureThatConnectionsAreReflectedInBothEnds(ground_reference_cloud_ptr, edges); if (filtering_configuration.number_of_references_used_for_labelling > 0) @@ -1600,7 +1710,7 @@ void CKf_Based_Terrain_Analysis::groundSegmentation( } else { - //std::cout << "Using fast labelling function!" << std::endl; +//std::cout << "Using fast labelling function!" << std::endl; fastLabelPointcloudUsingGroundModel(filtering_configuration, elevation_cloud_ptr, correspondence_indexes, ground_reference_cloud_ptr, edges, pcl_cloud_ptr); } @@ -1609,7 +1719,7 @@ void CKf_Based_Terrain_Analysis::groundSegmentation( if (filtering_configuration.show_dense_reconstruction) { - //std::cout << "Ready to create dense reconstruction" << std::endl; +//std::cout << "Ready to create dense reconstruction" << std::endl; pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr pcl_dense_cloud_ptr(new pcl::PointCloud<pcl::PointXYZRGBNormal>); createDenseGroundCloud(filtering_configuration, ground_reference_cloud_ptr, lidar_configuration, pcl_dense_cloud_ptr); -- GitLab