Apollo 10.0
自动驾驶开放平台
spatio_temporal_ground_detector.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2018 The Apollo Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
18
19#include "cyber/common/file.h"
20
25#include "modules/perception/pointcloud_ground_detection/ground_detector/proto/spatio_temporal_ground_detector_config.pb.h"
26
29
30namespace apollo {
31namespace perception {
32namespace lidar {
33
35
37 const GroundDetectorInitOptions& options) {
38 std::string config_file =
39 GetConfigFile(options.config_path, options.config_file);
40
41 // get config params
43 ACHECK(GetProtoFromFile(config_file, &config_params))
44 << "Failed to parse SpatioTemporalGroundDetectorConfig config file.";
45 ground_thres_ = config_params.ground_thres();
46 use_roi_ = config_params.use_roi();
47 use_semantic_ground_ = config_params.use_semantic_ground();
48 single_ground_detect_ = config_params.single_ground_detect();
49 use_ground_service_ = config_params.use_ground_service();
50 near_range_dist_ = config_params.near_range_dist();
51 near_range_ground_thres_ = config_params.near_range_ground_thres();
52 middle_range_dist_ = config_params.middle_range_dist();
53 middle_range_ground_thres_ = config_params.middle_range_ground_thres();
54 parsing_height_buffer_ = config_params.parsing_height_buffer();
55 debug_output_ = config_params.debug_output();
56
58 param_->roi_region_rad_x = config_params.roi_rad_x();
59 param_->roi_region_rad_y = config_params.roi_rad_y();
60 param_->roi_region_rad_z = config_params.roi_rad_z();
61 param_->nr_grids_coarse = config_params.small_grid_size();
62 param_->nr_grids_fine = config_params.big_grid_size();
63 grid_size_ = config_params.small_grid_size();
64
65 param_->roi_near_rad = config_params.near_range();
66 param_->sample_region_z_lower = config_params.near_z_min();
67 ori_sample_z_lower_ = config_params.near_z_min();
68 param_->sample_region_z_upper = config_params.near_z_max();
69 ori_sample_z_upper_ = config_params.near_z_max();
70 param_->planefit_filter_threshold = config_params.z_compare_thres();
71 param_->planefit_orien_threshold = config_params.planefit_orien_threshold();
73 config_params.planefit_dist_thres_near();
75 param_->candidate_filter_threshold = config_params.smooth_z_thres();
76 param_->nr_inliers_min_threshold = config_params.inliers_min_threshold();
77 param_->nr_smooth_iter = config_params.nr_smooth_iter();
78 param_->use_math_optimize = config_params.use_math_optimize();
79 param_->debug_output = config_params.debug_output();
80 param_->single_frame_detect = config_params.single_ground_detect();
81
82 pfdetector_ = new algorithm::PlaneFitGroundDetector(*param_);
83 pfdetector_->Init();
84
85 point_attribute_.resize(default_point_size_);
86 point_indices_temp_.resize(default_point_size_);
87 data_.resize(default_point_size_ * 3);
88 ground_height_signed_.resize(default_point_size_);
89
90 ground_service_content_.Init(
91 config_params.roi_rad_x(), config_params.roi_rad_y(),
92 config_params.small_grid_size(), config_params.small_grid_size());
93 return true;
94}
95
97 LidarFrame* frame) {
98 // check input
99 if (frame == nullptr) {
100 AERROR << "Input null frame ptr.";
101 return false;
102 }
103 if (frame->cloud.get() == nullptr || frame->world_cloud.get() == nullptr) {
104 AERROR << "Input null frame cloud.";
105 return false;
106 }
107 if (frame->cloud->empty() || frame->world_cloud->empty()) {
108 AERROR << "Input none points.";
109 return false;
110 }
111
112 unsigned int data_id = 0;
113 unsigned int valid_point_num = 0;
114 unsigned int valid_point_num_cur = 0;
115 size_t i = 0;
116 size_t num_points = 0;
117 size_t num_points_all = 0;
118 int index = 0;
119 unsigned int nr_points_element = 3;
120 float z_dis = 0.0f;
121
122 cloud_center_(0) = frame->lidar2world_pose(0, 3);
123 cloud_center_(1) = frame->lidar2world_pose(1, 3);
124 cloud_center_(2) = frame->lidar2world_pose(2, 3);
125
126 // check output
127 frame->non_ground_indices.indices.clear();
128
129 if (frame->roi_indices.indices.empty()) {
130 use_roi_ = false;
131 }
132
133 if (use_roi_) {
134 num_points = frame->roi_indices.indices.size();
135 } else {
136 num_points = frame->world_cloud->size();
137 }
138
139 // reallocate memory if points num > the preallocated size
140 num_points_all = num_points;
141
142 if (num_points_all > default_point_size_) {
143 default_point_size_ = num_points * 2;
144 point_attribute_.resize(default_point_size_);
145 point_indices_temp_.resize(default_point_size_);
146 data_.resize(default_point_size_ * 3);
147 ground_height_signed_.resize(default_point_size_);
148 }
149
150 // copy point data, filtering lower points under ground
151 // and use semantic filter
152 if (use_roi_) {
153 for (i = 0; i < num_points; ++i) {
154 index = frame->roi_indices.indices[i];
155 if (use_semantic_ground_ && static_cast<PointSemanticLabel>(
156 frame->cloud->points_semantic_label(index) & 15) !=
158 point_attribute_[i] = std::make_pair(index, -1);
159 continue;
160 }
161 point_attribute_[i] = std::make_pair(index, valid_point_num);
162 point_indices_temp_[valid_point_num++] = index;
163 if (single_ground_detect_) {
164 const auto& pt = frame->cloud->at(index);
165 data_[data_id++] = static_cast<float>(pt.x);
166 data_[data_id++] = static_cast<float>(pt.y);
167 data_[data_id++] = static_cast<float>(pt.z);
168 } else {
169 const auto& pt = frame->world_cloud->at(index);
170 data_[data_id++] = static_cast<float>(pt.x - cloud_center_(0));
171 data_[data_id++] = static_cast<float>(pt.y - cloud_center_(1));
172 data_[data_id++] = static_cast<float>(pt.z - cloud_center_(2));
173 }
174 }
175 } else {
176 for (i = 0; i < num_points; ++i) {
177 if (use_semantic_ground_ && static_cast<PointSemanticLabel>(
178 frame->cloud->points_semantic_label(i) & 15) !=
180 point_attribute_[i] = std::make_pair(i, -1);
181 continue;
182 }
183 point_attribute_[i] = std::make_pair(i, valid_point_num);
184 point_indices_temp_[valid_point_num++] = static_cast<int>(i);
185 if (single_ground_detect_) {
186 const auto& pt = frame->cloud->at(i);
187 data_[data_id++] = static_cast<float>(pt.x);
188 data_[data_id++] = static_cast<float>(pt.y);
189 data_[data_id++] = static_cast<float>(pt.z);
190 } else {
191 const auto& pt = frame->world_cloud->at(i);
192 data_[data_id++] = static_cast<float>(pt.x - cloud_center_(0));
193 data_[data_id++] = static_cast<float>(pt.y - cloud_center_(1));
194 data_[data_id++] = static_cast<float>(pt.z - cloud_center_(2));
195 }
196 }
197 }
198
199 CHECK_GE(num_points, valid_point_num);
200 CHECK_EQ(data_id, valid_point_num * 3);
201 base::PointIndices& non_ground_indices = frame->non_ground_indices;
202
203 AINFO << "spatial temporal seg: use roi " << use_roi_ << " roi points "
204 << num_points << " and input of ground detector: " << valid_point_num;
205
206 pfdetector_->ResetParams(ori_sample_z_lower_, ori_sample_z_upper_);
207 if (use_semantic_ground_) {
208 pfdetector_->UpdateParams(frame->parsing_ground_height,
209 parsing_height_buffer_, frame->timestamp);
210 }
211 if (!pfdetector_->Detect(data_.data(), ground_height_signed_.data(),
212 valid_point_num, nr_points_element)) {
213 ADEBUG << "failed to call ground detector!";
214 non_ground_indices.indices.insert(
215 non_ground_indices.indices.end(), point_indices_temp_.begin(),
216 point_indices_temp_.begin() + valid_point_num);
217 return false;
218 }
219
220 // valid_point_num_cur = valid_point_num;
221 // for (i = 0; i < valid_point_num_cur; ++i) {
222 // z_dis = ground_height_signed_.data()[i];
223 // frame->cloud->mutable_points_height()->at(point_indices_temp_[i]) =
224 // z_dis;
225 // frame->world_cloud->mutable_points_height()->at(point_indices_temp_[i])=
226 // z_dis;
227 // if (algorithm::IAbs(z_dis) > ground_thres_) {
228 // non_ground_indices.indices.push_back(i);
229 // } else {
230 // frame->cloud->mutable_points_label()->at(point_indices_temp_[i]) =
231 // static_cast<uint8_t>(LidarPointLabel::GROUND);
232 // frame->world_cloud->mutable_points_label()->at(point_indices_temp_[i])
233 // = static_cast<uint8_t>(LidarPointLabel::GROUND);
234 // }
235 // }
236 size_t ground_z_value_count = 0;
237 float ground_z_value = 0.0;
238 if (origin_ground_z_array_.size() >= ground_z_average_frame) {
239 origin_ground_z_array_.pop_front();
240 }
241 auto valid_index = [&](int row, int col) {
242 if (row >= 0 && row < grid_size_ && col >= 0 && col < grid_size_) {
243 return true;
244 }
245 return false;
246 };
247 for (i = 0; i < num_points; ++i) {
248 index = frame->roi_indices.indices[i];
249 // in valid_num
250 size_t pc_index = point_attribute_[i].first;
251 size_t count = point_attribute_[i].second;
252
253 float pc[3];
254 if (single_ground_detect_) {
255 const auto& pt = frame->cloud->at(pc_index);
256 pc[0] = pt.x;
257 pc[1] = pt.y;
258 pc[2] = pt.z;
259 } else {
260 const auto& pt = frame->world_cloud->at(pc_index);
261 pc[0] = pt.x - cloud_center_(0);
262 pc[1] = pt.y - cloud_center_(1);
263 pc[2] = pt.z - cloud_center_(2);
264 }
265 if (count == -1) {
266 int cur_row, cur_col = 0;
267 std::vector<std::pair<int, int>> neighbors;
268 pfdetector_->Pc2Voxel(pc[0], pc[1], pc[2], &cur_row, &cur_col);
269 neighbors.push_back(std::make_pair(cur_row, cur_col));
270 neighbors.push_back(std::make_pair(cur_row - 1, cur_col));
271 neighbors.push_back(std::make_pair(cur_row + 1, cur_col));
272 neighbors.push_back(std::make_pair(cur_row, cur_col - 1));
273 neighbors.push_back(std::make_pair(cur_row, cur_col + 1));
274 float min_z = std::numeric_limits<float>::max();
275 for (size_t k = 0; k < neighbors.size(); k++) {
276 int row = neighbors[k].first;
277 int col = neighbors[k].second;
278 if (!valid_index(row, col)) {
279 continue;
280 }
281 const algorithm::GroundPlaneLiDAR* plane =
282 pfdetector_->GetGroundPlane(row, col);
283 if (plane->IsValid()) {
285 plane->params, pc);
286 min_z = std::fabs(z_dis) < min_z ? std::fabs(z_dis) : min_z;
287 }
288 }
289 z_dis = min_z;
290 } else {
291 z_dis = ground_height_signed_.data()[count];
292 }
293 frame->cloud->mutable_points_height()->at(pc_index) = z_dis;
294 frame->world_cloud->mutable_points_height()->at(pc_index) = z_dis;
295
296 const auto& ppp = frame->cloud->at(pc_index);
297 Eigen::Vector3d pc_novatel =
298 frame->lidar2novatel_extrinsics * Eigen::Vector3d(ppp.x, ppp.y, ppp.z);
299 float threshold = ground_thres_;
300 if (pc_novatel(1) > 0 && pc_novatel(1) < near_range_dist_ &&
301 pc_novatel(0) > FLAGS_x_back - 0.1 &&
302 pc_novatel(0) < FLAGS_x_front + 0.1) {
303 threshold = near_range_ground_thres_;
304 }
305 if (pc_novatel(1) >= near_range_dist_ &&
306 pc_novatel(1) < middle_range_dist_ &&
307 pc_novatel(0) > FLAGS_x_back - 0.1 &&
308 pc_novatel(0) < FLAGS_x_front + 0.1) {
309 threshold = middle_range_ground_thres_;
310 }
311
312 // if (algorithm::IAbs(z_dis) > threshold) {
313 if (z_dis > threshold) {
314 non_ground_indices.indices.push_back(i);
315 } else {
316 frame->cloud->mutable_points_label()->at(pc_index) =
317 static_cast<uint8_t>(LidarPointLabel::GROUND);
318 frame->world_cloud->mutable_points_label()->at(pc_index) =
319 static_cast<uint8_t>(LidarPointLabel::GROUND);
320 if (sqrt(ppp.x * ppp.x + ppp.y * ppp.y) < 8 && fabs(z_dis) < 0.1) {
321 ++ground_z_value_count;
322 ground_z_value += ppp.z;
323 }
324 }
325 }
326 AINFO << "succeed to call ground detector with non ground points "
327 << non_ground_indices.indices.size();
328
329 float oriHeight = ground_z_value /
330 (static_cast<float>(ground_z_value_count) * 1.0f);
331 origin_ground_z_array_.push_back(oriHeight);
332 float ori_height = 0.0;
333 for (auto value : origin_ground_z_array_) {
334 ori_height += value;
335 }
336 frame->original_ground_z = ori_height /
337 (static_cast<float>(origin_ground_z_array_.size()) * 1.0f);
338 AINFO << "This frame " << std::to_string(frame->timestamp)
339 <<" origin ground height is " << frame->original_ground_z;
340
341 if (debug_output_) {
342 std::ofstream out1;
343 out1.open("semantic/" + std::to_string(frame->timestamp) + ".txt");
344 if (out1.is_open()) {
345 for (size_t i = 0; i < frame->cloud->size(); i++) {
346 int index = static_cast<int>(static_cast<PointSemanticLabel>(
347 frame->cloud->points_semantic_label(i) & 15));
348 int label_index = static_cast<uint8_t>(
349 frame->cloud->points_label(i));
350 if (single_ground_detect_) {
351 const auto& pt = frame->cloud->at(i);
352 out1 << pt.x << ", " << pt.y << ", " << pt.z << ", "
353 << pt.intensity << ", " << index << ", " << label_index
354 << std::endl;
355 } else {
356 const auto& pt = frame->world_cloud->at(i);
357 out1 << pt.x - cloud_center_(0) << ", "
358 << pt.y - cloud_center_(1) << ", "
359 << pt.z - cloud_center_(2) << ", " << pt.intensity
360 << ", " << index << ", " << label_index << std::endl;
361 }
362 }
363 }
364 out1.close();
365 }
366
367 if (use_ground_service_) {
368 auto ground_service = SceneManager::Instance().Service("GroundService");
369 if (ground_service != nullptr) {
370 ground_service_content_.grid_center_ = cloud_center_;
371 ground_service_content_.grid_.Reset();
372 GroundNode* node_ptr = ground_service_content_.grid_.DataPtr();
373 unsigned int rows = pfdetector_->GetGridDimY();
374 unsigned int cols = pfdetector_->GetGridDimX();
375 unsigned int index = 0;
376 for (unsigned int r = 0; r < rows; ++r) {
377 for (unsigned int c = 0; c < cols; ++c) {
378 const algorithm::GroundPlaneLiDAR* plane =
379 pfdetector_->GetGroundPlane(r, c);
380 if (plane->IsValid()) {
381 index = r * cols + c;
382 GroundNode* node = node_ptr + index;
383 node->params(0) = plane->params[0];
384 node->params(1) = plane->params[1];
385 node->params(2) = plane->params[2];
386 node->params(3) = plane->params[3];
387 node->confidence = 1.0;
388 }
389 }
390 }
391 ground_service->UpdateServiceContent(ground_service_content_);
392 } else {
393 AINFO << "Failed to find ground service and cannot update.";
394 }
395 }
396 return true;
397}
398
400
401} // namespace lidar
402} // namespace perception
403} // namespace apollo
#define PERCEPTION_REGISTER_GROUNDDETECTOR(name)
const GroundPlaneLiDAR * GetGroundPlane(int r, int c) const
Definition i_ground.cc:1694
void UpdateParams(float parsing_ground_z, float buffer, double timestamp)
Definition i_ground.cc:1589
bool Detect(const float *point_cloud, float *height_above_ground, unsigned int nr_points, unsigned int nr_point_elements)
Definition i_ground.cc:1599
void ResetParams(float ori_z_lower, float ori_z_upper)
Definition i_ground.cc:1582
void Pc2Voxel(float x, float y, float z, int *row, int *col)
Definition i_ground.cc:1667
bool Init(double roi_x, double roi_y, uint32_t rows, uint32_t cols)
SceneServicePtr Service(const std::string &name)
bool Detect(const GroundDetectorOptions &options, LidarFrame *frame) override
Detect ground point
bool Init(const GroundDetectorInitOptions &options=GroundDetectorInitOptions()) override
Init ground detector
#define ACHECK(cond)
Definition log.h:80
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
bool GetProtoFromFile(const std::string &file_name, google::protobuf::Message *message)
Parses the content of the file specified by the file_name as a representation of protobufs,...
Definition file.cc:132
T IPlaneToPointSignedDistanceWUnitNorm(const T *pi, const T *p)
Definition i_plane.h:102
std::string GetConfigFile(const std::string &config_path, const std::string &config_file)
Definition util.cc:80
class register implement
Definition arena_queue.h:37
std::shared_ptr< base::AttributePointCloud< base::PointD > > world_cloud
Definition lidar_frame.h:37
std::shared_ptr< base::AttributePointCloud< base::PointF > > cloud
Definition lidar_frame.h:35