diff --git a/include/structs_definitions.h b/include/structs_definitions.h index 9ade8a87677d8deb1869b3e6dba6c809e82e8f16..1ea91eff2561f9b1094322ac67b5d35cf3dd7df9 100644 --- a/include/structs_definitions.h +++ b/include/structs_definitions.h @@ -22,7 +22,7 @@ const int DATA_N_3_Z_VARIANCE = 3; const int DATA_C_0_RGB_CAST_INTO_FLOAT = 0; const int DATA_C_1_ID_CLASS = 1; -const int DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL = 2; +const int DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL = 2; // only used in elevation cloud const int DATA_C_3_ORIGINAL_INDEX = 3; @@ -42,12 +42,12 @@ const int INDEX_UNKNOWN = -1; const float VERTEX_CONNECTED_TO_ROOT = 0.0; const float VERTEX_NOT_CONNECTED_TO_ROOT = 100.0; -const float UNKNOWN_MEAN = -1000000.0; +const float UNKNOWN_MEAN = -1000.0; const float UNKOWN_VARIANCE = -1.0; const float UNKNOWN_INTENSITY = -1.0; const float UNKNOWN_PROB = -1.0; -const float UNKNOWN_Z_GROUND = -1000000.0; +const float UNKNOWN_Z_GROUND = -1000.0; const int KITTI_NUMBER_OF_PRECISION_RECALL_INTERVALES = 40; diff --git a/src/kf_based_terrain_analysis.cpp b/src/kf_based_terrain_analysis.cpp index 9a05e53b85f9264a8d4c4ea228a14139a441591e..0ce44b3cdf44c20ff60b84375b77315b56062326 100644 --- a/src/kf_based_terrain_analysis.cpp +++ b/src/kf_based_terrain_analysis.cpp @@ -755,7 +755,7 @@ void CKf_Based_Terrain_Analysis::fastGenerateElevationCloud( for (int i = 0; i < elevation_cell_vector.size(); ++i) { 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 ((int)std::floor(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; @@ -767,7 +767,7 @@ void CKf_Based_Terrain_Analysis::fastGenerateElevationCloud( elevation_cloud_point.g = G_CLASS_UNKNOWN; elevation_cloud_point.b = B_CLASS_UNKNOWN; } - // TODO: check this! + 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(); @@ -986,11 +986,14 @@ void CKf_Based_Terrain_Analysis::fastLabelPointcloudUsingGroundModel( { pcl::PointXYZRGBNormal point_in_sensor_frame = *i; + // We pick the reference that made the best prediction for this point in the elevation cloud int reference_index = (int)std::floor( point_in_sensor_frame.data_c[DATA_C_2_INDEX_OF_GROUND_REF_THAT_MADE_THE_LABEL]); if (reference_index != INDEX_UNKNOWN) { + // If this point in the elevation cloud has been labeled by a reference, we extract the reference to + // check the Mahalanobis distance and make the actual labeling of the original point cloud pcl::PointXYZRGBNormal reference_in_sensor_frame = ground_reference_cloud_ptr->points[reference_index]; // 1) We point to the vector of indices related to the elevation_cloud point under evaluation @@ -1001,35 +1004,52 @@ void CKf_Based_Terrain_Analysis::fastLabelPointcloudUsingGroundModel( for (std::vector<int>::const_iterator point_iterator = index_iterator->begin(); point_iterator != index_iterator->end(); ++point_iterator) { - float mahalanobis_distance = mahalanobisDistance(reference_in_sensor_frame, - pcl_cloud_ptr->points[*point_iterator]); -// if (std::isnan(mahalanobis_distance)) -// { -// std::cout << "posterior pred sigma = " << prediction_std_dev << " uncertainty = " -// << prediction_std_dev * filtering_configuration.mahalanobis_threshold << " mahalanobis distance = " -// << mahalanobis_distance << std::endl; -// -// std::getchar(); -// } + // We now copy the data that is common to every point in the vector (because are statistics extracted + // from the points in the vector) - pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_2_MEAN_INTENSITY] = - point_in_sensor_frame.data_n[DATA_N_0_INTENSITY]; + // in data_n[0] we have the point intensity, so nothing to change + // in data_n[1] we will store the intensity variance in the elevation cloud cell pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_1_INTENSITY_VARIANCE] = point_in_sensor_frame.data_n[DATA_N_1_INTENSITY_VARIANCE]; + // in data_n[2] we store the mean z value in the elevation cell + pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_2_Z_MEAN] = point_in_sensor_frame.data_n[DATA_N_2_Z_MEAN]; + + // in data_n[3] we store the z variance in the elevation cell + pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_3_Z_VARIANCE] = + point_in_sensor_frame.data_n[DATA_N_3_Z_VARIANCE]; + + // TODO: we copy the mean intensity value in the channel reserved for the color, we do this because + // we have detected a problem with pcl conversions: when passing the point cloud through a ROS topic, + // channels c2 and c3 get corrupted, so we avoid to use them, we will investigate this problem in the + // future (hopefully) + // pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_2_MEAN_INTENSITY] = + // point_in_sensor_frame.data_n[DATA_N_0_INTENSITY]; + pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_0_RGB_CAST_INTO_FLOAT] = + point_in_sensor_frame.data_n[DATA_N_0_INTENSITY]; + + // std::cout << "Intensity in elevation cloud: mean = " << point_in_sensor_frame.data_n[DATA_N_0_INTENSITY] // << " var = " // << point_in_sensor_frame.data_n[DATA_N_1_INTENSITY_VARIANCE] // << std::endl; // -// std::cout << "Intensity in pcl cloud: point = " -// << pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_0_INTENSITY] << " mean = " -// << pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_2_MEAN_INTENSITY] << " var = " -// << pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_1_INTENSITY_VARIANCE] << std::endl; +// std::cout << "Intensity in pcl cloud: point = " << pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_0_INTENSITY] +// << " mean = " << pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_0_RGB_CAST_INTO_FLOAT] +// << " var = " << pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_1_INTENSITY_VARIANCE] << std::endl; - pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_2_Z_MEAN] = point_in_sensor_frame.data_n[DATA_N_2_Z_MEAN]; - pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_3_Z_VARIANCE] = - point_in_sensor_frame.data_n[DATA_N_3_Z_VARIANCE]; + // once we have all the common values stored, only rest to compute the class and score, that will be + // packaged into the data_c[1] field + float mahalanobis_distance = mahalanobisDistance(reference_in_sensor_frame, + pcl_cloud_ptr->points[*point_iterator]); +// if (std::isnan(mahalanobis_distance)) +// { +// std::cout << "posterior pred sigma = " << prediction_std_dev << " uncertainty = " +// << prediction_std_dev * filtering_configuration.mahalanobis_threshold << " mahalanobis distance = " +// << mahalanobis_distance << std::endl; +// +// std::getchar(); +// } float score = 0.995 - (mahalanobis_distance / filtering_configuration.mahalanobis_threshold); // we use 0.995 instead of 1.0 to avoid overflowing the class field if (score < 0.0) @@ -1039,9 +1059,12 @@ void CKf_Based_Terrain_Analysis::fastLabelPointcloudUsingGroundModel( if (score > filtering_configuration.score_threshold) { - pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_GROUND; - pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_GROUND; - pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_GROUND; + // TODO: when passing the point cloud through a ROS topic, + // channels c2 and c3 get corrupted, so we avoid to use them, we are temporarily the c0 channel + // which is the one storing RGB values packed as a float, so colour is disabled at the moment +// pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_GROUND; +// pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_GROUND; +// pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_GROUND; pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_1_ID_CLASS] = (float)CLASS_GROUND + score; } @@ -1050,11 +1073,17 @@ void CKf_Based_Terrain_Analysis::fastLabelPointcloudUsingGroundModel( if ((pcl_cloud_ptr->points[*point_iterator].z - point_in_sensor_frame.z) < filtering_configuration.robot_height) { - pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_OBSTACLE; - pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_OBSTACLE; - pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_OBSTACLE; - - pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_1_ID_CLASS] = (float)CLASS_OBSTACLE + score; + // TODO: when passing the point cloud through a ROS topic, + // channels c2 and c3 get corrupted, so we avoid to use them, we are temporarily the c0 channel + // which is the one storing RGB values packed as a float, so colour is disabled at the moment +// pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_OBSTACLE; +// pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_OBSTACLE; +// pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_OBSTACLE; + + // We don't use score with obstacle points, if they are considered obstacles, we believe that their + // probability of being ground is zero, the class label is used to distinguish between general obstacles + // and overhanging obstacles + pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_1_ID_CLASS] = (float)CLASS_OBSTACLE + 0.0; // if (flag_reduce_mahalanobis_thres_if_an_obstacle_is_found) // flag_obstacle_found = true; @@ -1062,12 +1091,16 @@ void CKf_Based_Terrain_Analysis::fastLabelPointcloudUsingGroundModel( else { //std::cout << "Overhanging obstacle detected!" << std::endl; - pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_OVERHANGING_OBSTACLE; - pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_OVERHANGING_OBSTACLE; - pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_OVERHANGING_OBSTACLE; + + // TODO: when passing the point cloud through a ROS topic, + // channels c2 and c3 get corrupted, so we avoid to use them, we are temporarily the c0 channel + // which is the one storing RGB values packed as a float, so colour is disabled at the moment +// pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_OVERHANGING_OBSTACLE; +// pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_OVERHANGING_OBSTACLE; +// pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_OVERHANGING_OBSTACLE; pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_1_ID_CLASS] = (float)CLASS_OVERHANGING_OBSTACLE - + score; + + 0.0; } } } @@ -1082,41 +1115,64 @@ void CKf_Based_Terrain_Analysis::fastLabelPointcloudUsingGroundModel( for (std::vector<int>::const_iterator point_iterator = index_iterator->begin(); point_iterator != index_iterator->end(); ++point_iterator) { - pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_2_MEAN_INTENSITY] = - point_in_sensor_frame.data_n[DATA_N_0_INTENSITY]; + // We now copy the data that is common to every point in the vector (because are statistics extracted + // from the points in the vector) + + // in data_n[0] we have the point intensity, so nothing to change + // in data_n[1] we will store the intensity variance in the elevation cloud cell pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_1_INTENSITY_VARIANCE] = point_in_sensor_frame.data_n[DATA_N_1_INTENSITY_VARIANCE]; - pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_2_Z_MEAN] = - point_in_sensor_frame.data_n[DATA_N_2_Z_MEAN]; + // in data_n[2] we store the mean z value in the elevation cell + pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_2_Z_MEAN] = point_in_sensor_frame.data_n[DATA_N_2_Z_MEAN]; + + // in data_n[3] we store the z variance in the elevation cell pcl_cloud_ptr->points[*point_iterator].data_n[DATA_N_3_Z_VARIANCE] = point_in_sensor_frame.data_n[DATA_N_3_Z_VARIANCE]; + // TODO: we copy the mean intensity value in the channel reserved for the color, we do this because + // we have detected a problem with pcl conversions: when passing the point cloud through a ROS topic, + // channels c2 and c3 get corrupted, so we avoid to use them, we will investigate this problem in the + // future (hopefully) + // pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_2_MEAN_INTENSITY] = + // point_in_sensor_frame.data_n[DATA_N_0_INTENSITY]; + pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_0_RGB_CAST_INTO_FLOAT] = + point_in_sensor_frame.data_n[DATA_N_0_INTENSITY]; + if ((pcl_cloud_ptr->points[*point_iterator].z - point_in_sensor_frame.z) < filtering_configuration.ground_threshold_in_not_analyzed_areas) { - pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_GROUND; // We use instead the r g b channels directly - pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_GROUND; - pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_GROUND; - - float score = 0.5; // we don't have too much confidence in these points, because they are not analyzed + // TODO: when passing the point cloud through a ROS topic, + // channels c2 and c3 get corrupted, so we avoid to use them, we are temporarily the c0 channel + // which is the one storing RGB values packed as a float, so colour is disabled at the moment +// pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_GROUND; // We use instead the r g b channels directly +// pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_GROUND; +// pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_GROUND; + + float score = 0.0; // we don't have too much confidence in these points, because they are not analyzed pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_1_ID_CLASS] = (float)CLASS_GROUND + score; } else if ((pcl_cloud_ptr->points[*point_iterator].z - point_in_sensor_frame.z) < filtering_configuration.robot_height) { - pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_OBSTACLE; - pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_OBSTACLE; - pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_OBSTACLE; + // TODO: when passing the point cloud through a ROS topic, + // channels c2 and c3 get corrupted, so we avoid to use them, we are temporarily the c0 channel + // which is the one storing RGB values packed as a float, so colour is disabled at the moment +// pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_OBSTACLE; +// pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_OBSTACLE; +// pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_OBSTACLE; float score = 0.0; pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_1_ID_CLASS] = (float)CLASS_OBSTACLE + score; } else { - pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_OVERHANGING_OBSTACLE; - pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_OVERHANGING_OBSTACLE; - pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_OVERHANGING_OBSTACLE; + // TODO: when passing the point cloud through a ROS topic, + // channels c2 and c3 get corrupted, so we avoid to use them, we are temporarily the c0 channel + // which is the one storing RGB values packed as a float, so colour is disabled at the moment +// pcl_cloud_ptr->points[*point_iterator].r = R_CLASS_OVERHANGING_OBSTACLE; +// pcl_cloud_ptr->points[*point_iterator].g = G_CLASS_OVERHANGING_OBSTACLE; +// pcl_cloud_ptr->points[*point_iterator].b = B_CLASS_OVERHANGING_OBSTACLE; float score = 0.0; pcl_cloud_ptr->points[*point_iterator].data_c[DATA_C_1_ID_CLASS] = (float)CLASS_OVERHANGING_OBSTACLE @@ -1159,7 +1215,7 @@ void CKf_Based_Terrain_Analysis::groundSegmentation( //std::cout << "Starting ground segmentation!!" << std::endl; //std::cout << "Initializing pointcloud: Number of points in pcl_cloud = " << pcl_cloud.points.size() << std::endl; - // We copy the input in a pointer fashion (maybe it could be optimized) + // We copy the input in a pointer fashion (TODO: maybe it could be optimized) pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr pcl_cloud_ptr(new pcl::PointCloud<pcl::PointXYZRGBNormal>); *pcl_cloud_ptr = pcl_cloud; @@ -1240,6 +1296,7 @@ void CKf_Based_Terrain_Analysis::groundSegmentation( ground_dense_reconstruction_pcl_cloud = *elevation_cloud_ptr; } + // (TODO: maybe it could be optimized) ground_references_pcl_cloud.clear(); ground_references_pcl_cloud = *ground_reference_cloud_ptr;