Apollo 11.0
自动驾驶开放平台
apollo::perception::lidar::SpatioTemporalGroundDetector类 参考

#include <spatio_temporal_ground_detector.h>

类 apollo::perception::lidar::SpatioTemporalGroundDetector 继承关系图:
apollo::perception::lidar::SpatioTemporalGroundDetector 的协作图:

Public 成员函数

 SpatioTemporalGroundDetector ()=default
 
 ~SpatioTemporalGroundDetector ()
 
bool Init (const GroundDetectorInitOptions &options=GroundDetectorInitOptions()) override
 Init ground detector
 
bool Detect (const GroundDetectorOptions &options, LidarFrame *frame) override
 Detect ground point
 
std::string Name () const override
 Get class name
 
- Public 成员函数 继承自 apollo::perception::lidar::BaseGroundDetector
 BaseGroundDetector ()=default
 
virtual ~BaseGroundDetector ()=default
 

详细描述

在文件 spatio_temporal_ground_detector.h 第 34 行定义.

构造及析构函数说明

◆ SpatioTemporalGroundDetector()

apollo::perception::lidar::SpatioTemporalGroundDetector::SpatioTemporalGroundDetector ( )
default

◆ ~SpatioTemporalGroundDetector()

apollo::perception::lidar::SpatioTemporalGroundDetector::~SpatioTemporalGroundDetector ( )
inline

在文件 spatio_temporal_ground_detector.h 第 37 行定义.

37 {
38 if (pfdetector_ != nullptr) {
39 delete pfdetector_;
40 }
41 if (param_ != nullptr) {
42 delete param_;
43 }
44 }

成员函数说明

◆ Detect()

bool apollo::perception::lidar::SpatioTemporalGroundDetector::Detect ( const GroundDetectorOptions &  options,
LidarFrame *  frame 
)
overridevirtual

Detect ground point

参数
options
framelocation to save non_ground_point indices and point height
返回
true
false

实现了 apollo::perception::lidar::BaseGroundDetector.

在文件 spatio_temporal_ground_detector.cc 第 101 行定义.

102 {
103 // check input
104 if (frame == nullptr) {
105 AERROR << "Input null frame ptr.";
106 return false;
107 }
108 if (frame->cloud.get() == nullptr || frame->world_cloud.get() == nullptr) {
109 AERROR << "Input null frame cloud.";
110 return false;
111 }
112 if (frame->cloud->empty() || frame->world_cloud->empty()) {
113 AERROR << "Input none points.";
114 return false;
115 }
116
117 unsigned int data_id = 0;
118 unsigned int semantic_data_id = 0;
119 unsigned int valid_point_num = 0;
120 unsigned int valid_point_num_cur = 0;
121 size_t i = 0;
122 size_t num_points = 0;
123 size_t num_points_all = 0;
124 int index = 0;
125 unsigned int nr_points_element = 3;
126 float z_dis = 0.0f;
127
128 cloud_center_(0) = frame->lidar2world_pose(0, 3);
129 cloud_center_(1) = frame->lidar2world_pose(1, 3);
130 cloud_center_(2) = frame->lidar2world_pose(2, 3);
131
132 // check output
133 frame->non_ground_indices.indices.clear();
134
135 if (frame->roi_indices.indices.empty()) {
136 use_roi_ = false;
137 }
138
139 if (use_roi_) {
140 num_points = frame->roi_indices.indices.size();
141 } else {
142 num_points = frame->world_cloud->size();
143 }
144
145 // reallocate memory if points num > the preallocated size
146 num_points_all = num_points;
147
148 if (num_points_all > default_point_size_) {
149 default_point_size_ = num_points * 2;
150 point_attribute_.resize(default_point_size_);
151 point_indices_temp_.resize(default_point_size_);
152 data_.resize(default_point_size_ * 3);
153 semantic_data_.resize(default_point_size_);
154 ground_height_signed_.resize(default_point_size_);
155 }
156
157 // copy point data, filtering lower points under ground
158 // and use semantic filter
159 // compute near-by semantic-ground average value for non-semantic data
160 size_t near_ground_count = 0;
161 float near_ground_z = 0.0;
162 if (use_roi_) {
163 for (i = 0; i < num_points; ++i) {
164 index = frame->roi_indices.indices[i];
165 // if (use_semantic_ground_ && static_cast<PointSemanticLabel>(
166 // frame->cloud->points_semantic_label(index) & 15) !=
167 // PointSemanticLabel::GROUND) {
168 // point_attribute_[i] = std::make_pair(index, -1);
169 // continue;
170 // }
171 point_attribute_[i] = std::make_pair(index, valid_point_num);
172 point_indices_temp_[valid_point_num++] = index;
174 frame->cloud->points_semantic_label(index));
175 if (single_ground_detect_) {
176 const auto& pt = frame->cloud->at(index);
177 data_[data_id++] = static_cast<float>(pt.x);
178 data_[data_id++] = static_cast<float>(pt.y);
179 data_[data_id++] = static_cast<float>(pt.z);
180 semantic_data_[semantic_data_id++] = static_cast<int>(
181 GetSemanticLabel(frame->cloud->points_semantic_label(index)));
182 if (ground_flag &&
183 fabs(pt.x) <= near_range_ && fabs(pt.y) <= near_range_) {
184 near_ground_count++;
185 near_ground_z += pt.z;
186 }
187 } else {
188 const auto& pt = frame->world_cloud->at(index);
189 data_[data_id++] = static_cast<float>(pt.x - cloud_center_(0));
190 data_[data_id++] = static_cast<float>(pt.y - cloud_center_(1));
191 data_[data_id++] = static_cast<float>(pt.z - cloud_center_(2));
192 semantic_data_[semantic_data_id++] = static_cast<int>(
193 GetSemanticLabel(frame->cloud->points_semantic_label(index)));
194 if (ground_flag &&
195 fabs(pt.x - cloud_center_(0)) <= near_range_ &&
196 fabs(pt.y - cloud_center_(1)) <= near_range_) {
197 near_ground_count++;
198 near_ground_z += pt.z;
199 }
200 }
201 }
202 } else {
203 for (i = 0; i < num_points; ++i) {
204 // if (use_semantic_ground_ && static_cast<PointSemanticLabel>(
205 // frame->cloud->points_semantic_label(i) & 15) !=
206 // PointSemanticLabel::GROUND) {
207 // point_attribute_[i] = std::make_pair(i, -1);
208 // continue;
209 // }
210 point_attribute_[i] = std::make_pair(i, valid_point_num);
211 point_indices_temp_[valid_point_num++] = static_cast<int>(i);
213 frame->cloud->points_semantic_label(i));
214 if (single_ground_detect_) {
215 const auto& pt = frame->cloud->at(i);
216 data_[data_id++] = static_cast<float>(pt.x);
217 data_[data_id++] = static_cast<float>(pt.y);
218 data_[data_id++] = static_cast<float>(pt.z);
219 semantic_data_[semantic_data_id++] = static_cast<int>(
220 GetSemanticLabel(frame->cloud->points_semantic_label(index)));
221 if (ground_flag &&
222 fabs(pt.x) <= near_range_ && fabs(pt.y) <= near_range_) {
223 near_ground_count++;
224 near_ground_z += pt.z;
225 }
226 } else {
227 const auto& pt = frame->world_cloud->at(i);
228 data_[data_id++] = static_cast<float>(pt.x - cloud_center_(0));
229 data_[data_id++] = static_cast<float>(pt.y - cloud_center_(1));
230 data_[data_id++] = static_cast<float>(pt.z - cloud_center_(2));
231 semantic_data_[semantic_data_id++] = static_cast<int>(
232 GetSemanticLabel(frame->cloud->points_semantic_label(index)));
233 if (ground_flag &&
234 fabs(pt.x - cloud_center_(0)) <= near_range_ &&
235 fabs(pt.y - cloud_center_(1)) <= near_range_) {
236 near_ground_count++;
237 near_ground_z += pt.z;
238 }
239 }
240 }
241 }
242
243 CHECK_GE(num_points, valid_point_num);
244 CHECK_EQ(data_id, valid_point_num * 3);
245 CHECK_EQ(semantic_data_id, valid_point_num);
246 base::PointIndices& non_ground_indices = frame->non_ground_indices;
247
248 AINFO << "spatial temporal seg: use roi " << use_roi_ << " roi points "
249 << num_points << " and input of ground detector: " << valid_point_num;
250
251 pfdetector_->ResetParams(ori_sample_z_lower_, ori_sample_z_upper_);
252 if (use_semantic_ground_) {
253 if (near_ground_count > 0) {
254 pfdetector_->UpdateParams(near_ground_z * 1.0f / near_ground_count,
255 parsing_height_buffer_, frame->timestamp);
256 } else {
257 pfdetector_->UpdateParams(frame->parsing_ground_height,
258 parsing_height_buffer_, frame->timestamp);
259 }
260 }
261 if (!pfdetector_->Detect(data_.data(), semantic_data_.data(),
262 ground_height_signed_.data(), valid_point_num, nr_points_element)) {
263 ADEBUG << "failed to call ground detector!";
264 non_ground_indices.indices.insert(
265 non_ground_indices.indices.end(), point_indices_temp_.begin(),
266 point_indices_temp_.begin() + valid_point_num);
267 return false;
268 }
269
270 // valid_point_num_cur = valid_point_num;
271 // for (i = 0; i < valid_point_num_cur; ++i) {
272 // z_dis = ground_height_signed_.data()[i];
273 // frame->cloud->mutable_points_height()->at(point_indices_temp_[i]) =
274 // z_dis;
275 // frame->world_cloud->mutable_points_height()->at(point_indices_temp_[i])=
276 // z_dis;
277 // if (algorithm::IAbs(z_dis) > ground_thres_) {
278 // non_ground_indices.indices.push_back(i);
279 // } else {
280 // frame->cloud->mutable_points_label()->at(point_indices_temp_[i]) =
281 // static_cast<uint8_t>(LidarPointLabel::GROUND);
282 // frame->world_cloud->mutable_points_label()->at(point_indices_temp_[i])
283 // = static_cast<uint8_t>(LidarPointLabel::GROUND);
284 // }
285 // }
286 size_t ground_z_value_count = 0;
287 float ground_z_value = 0.0;
288 if (origin_ground_z_array_.size() >= ground_z_average_frame) {
289 origin_ground_z_array_.pop_front();
290 }
291 auto valid_index = [&](int row, int col) {
292 if (row >= 0 && row < grid_size_ && col >= 0 && col < grid_size_) {
293 return true;
294 }
295 return false;
296 };
297 for (i = 0; i < num_points; ++i) {
298 index = frame->roi_indices.indices[i];
299 // in valid_num
300 size_t pc_index = point_attribute_[i].first;
301 size_t count = point_attribute_[i].second;
302
303 float pc[3];
304 if (single_ground_detect_) {
305 const auto& pt = frame->cloud->at(pc_index);
306 pc[0] = pt.x;
307 pc[1] = pt.y;
308 pc[2] = pt.z;
309 } else {
310 const auto& pt = frame->world_cloud->at(pc_index);
311 pc[0] = pt.x - cloud_center_(0);
312 pc[1] = pt.y - cloud_center_(1);
313 pc[2] = pt.z - cloud_center_(2);
314 }
315 // impossible equal -1, but reserve temporarily
316 // in case of other corner case
317 if (count == -1) {
318 int cur_row, cur_col = 0;
319 std::vector<std::pair<int, int>> neighbors;
320 pfdetector_->Pc2Voxel(pc[0], pc[1], pc[2], &cur_row, &cur_col);
321 neighbors.push_back(std::make_pair(cur_row, cur_col));
322 neighbors.push_back(std::make_pair(cur_row - 1, cur_col));
323 neighbors.push_back(std::make_pair(cur_row + 1, cur_col));
324 neighbors.push_back(std::make_pair(cur_row, cur_col - 1));
325 neighbors.push_back(std::make_pair(cur_row, cur_col + 1));
326 float min_z = std::numeric_limits<float>::max();
327 for (size_t k = 0; k < neighbors.size(); k++) {
328 int row = neighbors[k].first;
329 int col = neighbors[k].second;
330 if (!valid_index(row, col)) {
331 continue;
332 }
333 const algorithm::GroundPlaneLiDAR* plane =
334 pfdetector_->GetGroundPlane(row, col);
335 if (plane->IsValid()) {
337 plane->params, pc);
338 min_z = std::fabs(z_dis) < min_z ? std::fabs(z_dis) : min_z;
339 }
340 }
341 z_dis = min_z;
342 } else {
343 z_dis = ground_height_signed_.data()[count];
344 }
345 frame->cloud->mutable_points_height()->at(pc_index) = z_dis;
346 frame->world_cloud->mutable_points_height()->at(pc_index) = z_dis;
347
348 const auto& ppp = frame->cloud->at(pc_index);
349 Eigen::Vector3d pc_novatel =
350 frame->lidar2novatel_extrinsics * Eigen::Vector3d(ppp.x, ppp.y, ppp.z);
351 float threshold = ground_thres_;
352 if (pc_novatel(1) > 0 && pc_novatel(1) < near_range_dist_ &&
353 pc_novatel(0) > FLAGS_x_back - 0.1 &&
354 pc_novatel(0) < FLAGS_x_front + 0.1) {
355 threshold = near_range_ground_thres_;
356 }
357 if (pc_novatel(1) >= near_range_dist_ &&
358 pc_novatel(1) < middle_range_dist_ &&
359 pc_novatel(0) > FLAGS_x_back - 0.1 &&
360 pc_novatel(0) < FLAGS_x_front + 0.1) {
361 threshold = middle_range_ground_thres_;
362 }
363
364 // if (algorithm::IAbs(z_dis) > threshold) {
365 if (z_dis > threshold) {
366 non_ground_indices.indices.push_back(i);
367 } else {
368 frame->cloud->mutable_points_label()->at(pc_index) =
369 static_cast<uint8_t>(LidarPointLabel::GROUND);
370 frame->world_cloud->mutable_points_label()->at(pc_index) =
371 static_cast<uint8_t>(LidarPointLabel::GROUND);
372 if (sqrt(ppp.x * ppp.x + ppp.y * ppp.y) < 8 && fabs(z_dis) < 0.1) {
373 ++ground_z_value_count;
374 ground_z_value += ppp.z;
375 }
376 }
377 }
378 AINFO << "succeed to call ground detector with non ground points "
379 << non_ground_indices.indices.size();
380
381 float oriHeight = ground_z_value /
382 (static_cast<float>(ground_z_value_count) * 1.0f);
383 origin_ground_z_array_.push_back(oriHeight);
384 float ori_height = 0.0;
385 for (auto value : origin_ground_z_array_) {
386 ori_height += value;
387 }
388 frame->original_ground_z = ori_height /
389 (static_cast<float>(origin_ground_z_array_.size()) * 1.0f);
390 AINFO << "This frame " << std::to_string(frame->timestamp)
391 <<" origin ground height is " << frame->original_ground_z;
392
393 if (debug_output_) {
394 std::ofstream out1;
395 out1.open("semantic/" + std::to_string(frame->timestamp) + ".txt");
396 if (out1.is_open()) {
397 for (size_t i = 0; i < frame->cloud->size(); i++) {
398 int parsing_index = static_cast<int>(GetSemanticLabel(
399 frame->cloud->points_semantic_label(i)));
400 int sbr_index = static_cast<int>(GetMotionLabel(
401 frame->cloud->points_semantic_label(i)));
402 int label_index = static_cast<uint8_t>(
403 frame->cloud->points_label(i));
404 if (single_ground_detect_) {
405 const auto& pt = frame->cloud->at(i);
406 out1 << pt.x << ", " << pt.y << ", " << pt.z << ", "
407 << pt.intensity << ", " << parsing_index << ", "
408 << sbr_index << ", " << label_index << std::endl;
409 } else {
410 const auto& pt = frame->world_cloud->at(i);
411 out1 << pt.x - cloud_center_(0) << ", "
412 << pt.y - cloud_center_(1) << ", "
413 << pt.z - cloud_center_(2) << ", " << pt.intensity
414 << ", " << parsing_index << ", " << sbr_index << ", "
415 << label_index << std::endl;
416 }
417 }
418 }
419 out1.close();
420 }
421
422 if (use_ground_service_) {
423 auto ground_service = SceneManager::Instance().Service("GroundService");
424 if (ground_service != nullptr) {
425 ground_service_content_.grid_center_ = cloud_center_;
426 ground_service_content_.grid_.Reset();
427 GroundNode* node_ptr = ground_service_content_.grid_.DataPtr();
428 unsigned int rows = pfdetector_->GetGridDimY();
429 unsigned int cols = pfdetector_->GetGridDimX();
430 unsigned int index = 0;
431 for (unsigned int r = 0; r < rows; ++r) {
432 for (unsigned int c = 0; c < cols; ++c) {
433 const algorithm::GroundPlaneLiDAR* plane =
434 pfdetector_->GetGroundPlane(r, c);
435 if (plane->IsValid()) {
436 index = r * cols + c;
437 GroundNode* node = node_ptr + index;
438 node->params(0) = plane->params[0];
439 node->params(1) = plane->params[1];
440 node->params(2) = plane->params[2];
441 node->params(3) = plane->params[3];
442 node->confidence = 1.0;
443 }
444 }
445 }
446 ground_service->UpdateServiceContent(ground_service_content_);
447 } else {
448 AINFO << "Failed to find ground service and cannot update.";
449 }
450 }
451 return true;
452}
const GroundPlaneLiDAR * GetGroundPlane(int r, int c) const
Definition i_ground.cc:2000
void UpdateParams(float parsing_ground_z, float buffer, double timestamp)
Definition i_ground.cc:1889
bool Detect(const float *point_cloud, const int *semantic_value, float *height_above_ground, unsigned int nr_points, unsigned int nr_point_elements)
Definition i_ground.cc:1899
void ResetParams(float ori_z_lower, float ori_z_upper)
Definition i_ground.cc:1882
void Pc2Voxel(float x, float y, float z, int *row, int *col)
Definition i_ground.cc:1973
SceneServicePtr Service(const std::string &name)
#define ADEBUG
Definition log.h:41
#define AERROR
Definition log.h:44
#define AINFO
Definition log.h:42
T IPlaneToPointSignedDistanceWUnitNorm(const T *pi, const T *p)
Definition i_plane.h:102
PointSemanticLabel GetSemanticLabel(uint8_t value)
bool IsSemanticLabelEqual(PointSemanticLabel label, uint8_t value)
Image< uchar > * threshold(Image< T > *src, int t)
Threshold image
Definition imutil.h:79
PointMotionLabel GetMotionLabel(uint8_t value)

◆ Init()

bool apollo::perception::lidar::SpatioTemporalGroundDetector::Init ( const GroundDetectorInitOptions &  options = GroundDetectorInitOptions())
overridevirtual

Init ground detector

参数
options
返回
true
false

实现了 apollo::perception::lidar::BaseGroundDetector.

在文件 spatio_temporal_ground_detector.cc 第 37 行定义.

38 {
39 std::string config_file =
40 GetConfigFile(options.config_path, options.config_file);
41
42 // get config params
43 SpatioTemporalGroundDetectorConfig config_params;
44 ACHECK(GetProtoFromFile(config_file, &config_params))
45 << "Failed to parse SpatioTemporalGroundDetectorConfig config file.";
46 ground_thres_ = config_params.ground_thres();
47 use_roi_ = config_params.use_roi();
48 use_semantic_ground_ = config_params.use_semantic_ground();
49 single_ground_detect_ = config_params.single_ground_detect();
50 use_ground_service_ = config_params.use_ground_service();
51 near_range_dist_ = config_params.near_range_dist();
52 near_range_ground_thres_ = config_params.near_range_ground_thres();
53 middle_range_dist_ = config_params.middle_range_dist();
54 middle_range_ground_thres_ = config_params.middle_range_ground_thres();
55 parsing_height_buffer_ = config_params.parsing_height_buffer();
56 debug_output_ = config_params.debug_output();
57
58 param_ = new algorithm::PlaneFitGroundDetectorParam;
59 param_->roi_region_rad_x = config_params.roi_rad_x();
60 param_->roi_region_rad_y = config_params.roi_rad_y();
61 param_->roi_region_rad_z = config_params.roi_rad_z();
62 param_->nr_grids_coarse = config_params.small_grid_size();
63 param_->nr_grids_fine = config_params.big_grid_size();
64 grid_size_ = config_params.small_grid_size();
65
66 param_->roi_near_rad = config_params.near_range();
67 near_range_ = config_params.near_range();
68 param_->sample_region_z_lower = config_params.near_z_min();
69 ori_sample_z_lower_ = config_params.near_z_min();
70 param_->sample_region_z_upper = config_params.near_z_max();
71 ori_sample_z_upper_ = config_params.near_z_max();
72 param_->planefit_filter_threshold = config_params.z_compare_thres();
73 param_->planefit_orien_threshold = config_params.planefit_orien_threshold();
75 config_params.planefit_dist_thres_near();
76 param_->planefit_dist_threshold_far = config_params.planefit_dist_thres_far();
77 param_->candidate_filter_threshold = config_params.smooth_z_thres();
78 param_->nr_inliers_min_threshold = config_params.inliers_min_threshold();
79 param_->nr_smooth_iter = config_params.nr_smooth_iter();
80 param_->use_semantic_info = config_params.use_semantic_ground();
81 param_->use_math_optimize = config_params.use_math_optimize();
82 param_->debug_output = config_params.debug_output();
83 param_->single_frame_detect = config_params.single_ground_detect();
84 param_->semantic_ground_value = static_cast<int>(PointSemanticLabel::GROUND);
85
86 pfdetector_ = new algorithm::PlaneFitGroundDetector(*param_);
87 pfdetector_->Init();
88
89 point_attribute_.resize(default_point_size_);
90 point_indices_temp_.resize(default_point_size_);
91 data_.resize(default_point_size_ * 3);
92 semantic_data_.resize(default_point_size_);
93 ground_height_signed_.resize(default_point_size_);
94
95 ground_service_content_.Init(
96 config_params.roi_rad_x(), config_params.roi_rad_y(),
97 config_params.small_grid_size(), config_params.small_grid_size());
98 return true;
99}
bool Init(double roi_x, double roi_y, uint32_t rows, uint32_t cols)
#define ACHECK(cond)
Definition log.h:80
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
std::string GetConfigFile(const std::string &config_path, const std::string &config_file)
Definition util.cc:80

◆ Name()

std::string apollo::perception::lidar::SpatioTemporalGroundDetector::Name ( ) const
inlineoverridevirtual

Get class name

返回
std::string

实现了 apollo::perception::lidar::BaseGroundDetector.

在文件 spatio_temporal_ground_detector.h 第 68 行定义.

68{ return "SpatioTemporalGroundDetector"; }

该类的文档由以下文件生成: