18 const sensor_msgs::msg::PointCloud2::SharedPtr& trimmed_point_cloud,
19 sensor_msgs::msg::PointCloud2::SharedPtr& ground_removed_point_cloud,
25 ground_removed_point_cloud->header = trimmed_point_cloud->header;
26 ground_removed_point_cloud->height = 1;
27 ground_removed_point_cloud->is_bigendian = trimmed_point_cloud->is_bigendian;
28 ground_removed_point_cloud->is_dense =
true;
29 ground_removed_point_cloud->point_step = trimmed_point_cloud->point_step;
30 ground_removed_point_cloud->row_step = 0;
31 ground_removed_point_cloud->fields = trimmed_point_cloud->fields;
32 ground_removed_point_cloud->width = 0;
33 ground_removed_point_cloud->data.resize(trimmed_point_cloud->width *
34 trimmed_point_cloud->point_step);
40 for (
size_t slice_idx = 0; slice_idx <
slices_->size(); ++slice_idx) {
41 process_slice(trimmed_point_cloud, ground_removed_point_cloud, slice_idx, ground_grid);
45 ground_removed_point_cloud->data.resize(ground_removed_point_cloud->width *
51 const sensor_msgs::msg::PointCloud2::SharedPtr& trimmed_point_cloud,
52 sensor_msgs::msg::PointCloud2::SharedPtr& ground_removed_point_cloud,
size_t slice_idx,
55 double previous_ground_point_x = 0.0;
56 double previous_ground_point_y = 0.0;
59 auto& cloud_data = trimmed_point_cloud->data;
60 auto& output_data = ground_removed_point_cloud->data;
62 std::vector<int> ground_indices;
63 std::vector<double> ground_distances;
66 for (
int ring_idx =
::NUM_RINGS - 1; ring_idx >= 0; --ring_idx) {
67 const auto& ring =
slices_->at(slice_idx).rings[ring_idx];
68 if (ring.indices.empty()) {
72 int lowest_ground_idx_in_ring = -1;
73 float previous_ground_point_distance =
74 std::hypot(previous_ground_point_x, previous_ground_point_y);
76 for (
int idx : ring.indices) {
81 float current_ground_point_distance = std::hypot(pt_x, pt_y);
84 (current_ground_point_distance - previous_ground_point_distance <
85 (-5 - (0.15 * ring_idx)) ||
86 current_ground_point_distance - previous_ground_point_distance >
87 (5 + (0.15 * ring_idx)))) {
90 }
else if (current_ground_point_distance <= previous_ground_point_distance) {
92 size_t write_idx = ground_removed_point_cloud->width;
96 ground_removed_point_cloud->width++;
99 float dz = pt_z - previous_ground_point_z;
100 float dr = current_ground_point_distance - previous_ground_point_distance;
105 float slope = std::abs(dz / dr);
109 ground_indices.push_back(idx);
110 ground_distances.push_back(current_ground_point_distance);
113 size_t write_idx = ground_removed_point_cloud->width;
117 ground_removed_point_cloud->width++;
124 if (!ground_indices.empty()) {
125 int num_points =
static_cast<int>(ground_distances.size());
126 int top_k = std::max<int>(1, num_points / 10);
129 std::nth_element(ground_distances.begin(), ground_distances.end() - top_k,
130 ground_distances.end());
133 std::vector<double> top_farthest(ground_distances.end() - top_k, ground_distances.end());
134 std::sort(top_farthest.begin(), top_farthest.end());
135 double r_ref = top_farthest[top_farthest.size() / 2];
138 for (
int idx : ground_indices) {
142 double r = std::hypot(gx, gy);
149 if (r < r_ref - threshold) {
151 size_t write_idx = ground_removed_point_cloud->width;
155 ground_removed_point_cloud->width++;
159 if (lowest_ground_idx_in_ring == -1 ||
160 gz < *
reinterpret_cast<const float*
>(
162 lowest_ground_idx_in_ring = idx;
167 if (lowest_ground_idx_in_ring != -1) {
168 previous_ground_point_x =
169 *
reinterpret_cast<float*
>(&cloud_data[
LidarPoint::PointX(lowest_ground_idx_in_ring)]);
170 previous_ground_point_y =
171 *
reinterpret_cast<float*
>(&cloud_data[
LidarPoint::PointY(lowest_ground_idx_in_ring)]);
172 previous_ground_point_z =
173 *
reinterpret_cast<float*
>(&cloud_data[
LidarPoint::PointZ(lowest_ground_idx_in_ring)]);
176 ground_indices.clear();
177 ground_distances.clear();
183 const sensor_msgs::msg::PointCloud2::SharedPtr& input_cloud)
const {
186 for (
auto& ring : slice.rings) {
187 ring.indices.clear();
191 const size_t num_points = input_cloud->width * input_cloud->height;
192 if (num_points == 0) {
196 const auto& cloud = input_cloud->data;
197 double slice_angle_rad =
grid_angle_ * (M_PI / 180.0);
201 double min_azimuth = -(fov_rad / 2.0);
203 for (
size_t i = 0; i < num_points; ++i) {
208 double azimuth = std::atan2(y, x);
209 double relative_azimuth = azimuth - min_azimuth;
211 if (relative_azimuth < 0 || relative_azimuth >= fov_rad) {
215 int slice_idx =
static_cast<int>(relative_azimuth / slice_angle_rad);
217 if (slice_idx >= 0 && slice_idx <
static_cast<int>(
slices_->size())) {
218 slices_->at(slice_idx).rings[ring].indices.push_back(i);