Apollo 11.0
自动驾驶开放平台
graph_segmentation.cc
浏览该文件的文档.
1/******************************************************************************
2 * Copyright 2023 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
20
21namespace apollo {
22namespace perception {
23namespace lidar {
24
26 std::string config_file = GetConfigFile(options.config_path, options.config_file);
27 ACHECK(apollo::cyber::common::GetProtoFromFile(config_file, &bg_config_));
28 // get config
29 // grid_width_ = bg_config_.grid_width();
30 // grid_height_ = bg_config_.grid_height();
31 resolution_ = bg_config_.resolution();
32 threshold_ = bg_config_.threshold();
33 min_pt_number_ = bg_config_.min_pt_number();
34 search_radius_ = bg_config_.search_radius();
35 height_threshold_ = bg_config_.height_threshold();
36 semantic_cost_ = bg_config_.semantic_cost();
37
38 // initialize graph segmentor
39 graph_segmentor_.Init(threshold_);
40 // ACHECK(bg_map_.Init(grid_width_, grid_height_, resolution_, height_threshold_));
41
42 ACHECK(bg_map_.Init(
43 bg_config_.xmin(),
44 bg_config_.xmax(),
45 bg_config_.ymin(),
46 bg_config_.ymax(),
47 resolution_,
48 height_threshold_));
49 grid_width_ = static_cast<int>((bg_config_.ymax() - bg_config_.ymin()) * 1.0f / resolution_);
50 grid_height_ = static_cast<int>((bg_config_.xmax() - bg_config_.xmin()) * 1.0f / resolution_);
51
52 // clear background objects
53 bg_objects_.clear();
54
55 AINFO << "graph segmentation config: " << bg_config_.DebugString();
56 return true;
57}
58
60 // clear background objects buffer
61 bg_objects_.clear();
62
63 // reset background map
64 if (!bg_map_.Reset(frame->cloud->size())) {
65 AERROR << "bg_map_ Reset error.";
66 return false;
67 }
68 // update map
69 if (!bg_map_.UpdateMap(frame)) {
70 AERROR << "bg_map_ Update error.";
71 return false;
72 }
73 // cluster
74 if (!Segment(frame)) {
75 AERROR << "Graph Segment error.";
76 return false;
77 }
78 // split
79 if (!Split(frame)) {
80 AERROR << "Split object error.";
81 return false;
82 }
83 // set default value and id for bg_objects_
84 if (!SetBgObjectDefaulVal(frame)) {
85 AERROR << "SetBgObjectDefaulVal error.";
86 return false;
87 }
88
89 // get all background objects
90 frame->segmented_objects.insert(frame->segmented_objects.end(), bg_objects_.begin(), bg_objects_.end());
91 AINFO << "Graph segment, background objects number: " << bg_objects_.size();
92 return true;
93}
94
96 std::vector<algorithm::Edge> edge_set;
97 edge_set.clear();
99 for (int x = 0; x < grid_height_; ++x) {
100 for (int y = 0; y < grid_width_; ++y) {
101 int grid_idx = x * grid_width_ + y;
102 if (!bg_map_.bg_nodes_.at(grid_idx).is_valid) {
103 continue;
104 }
105
106 edge.a = bg_map_.bg_nodes_.at(grid_idx).id;
107 BgNode n1 = bg_map_.bg_nodes_.at(grid_idx);
108
109 // rows
110 for (int ny = y; ny < grid_width_ && ny <= y + search_radius_; ++ny) {
111 int grid_ny = x * grid_width_ + ny;
112 if (bg_map_.bg_nodes_.at(grid_ny).is_valid) {
113 edge.b = bg_map_.bg_nodes_.at(grid_ny).id;
114 BgNode n2 = bg_map_.bg_nodes_.at(grid_ny);
115 edge.w = NodeDistance(n1, x, y, n2, x, ny);
116 edge_set.push_back(edge);
117 }
118 }
119 // next line, next column
120 for (int nx = x + 1; nx < grid_height_ && nx <= x + search_radius_; ++nx) {
121 for (int ny = y; ny < grid_width_ && ny < y + search_radius_; ++ny) {
122 int grid_nxny = nx * grid_width_ + ny;
123 if (bg_map_.bg_nodes_.at(grid_nxny).is_valid) {
124 edge.b = bg_map_.bg_nodes_.at(grid_nxny).id;
125 BgNode n2 = bg_map_.bg_nodes_.at(grid_nxny);
126 edge.w = NodeDistance(n1, x, y, n2, nx, ny);
127 edge_set.push_back(edge);
128 }
129 }
130 }
131 }
132 }
133
134 if (edge_set.size() == 0) {
135 AINFO << "Graph segmentation, edges are empty.";
136 return true;
137 }
138
139 // graph segment
140 graph_segmentor_.SegmentGraph(bg_map_.id(), edge_set.size(), edge_set.data());
141 algorithm::Universe* universe = graph_segmentor_.mutable_universe();
142 std::vector<size_t> mapping(bg_map_.id(), 0);
143 std::map<size_t, size_t> label_map;
144 size_t label = 0;
145 for (int i = 0; i < bg_map_.id(); ++i) {
146 mapping[i] = universe->Find(i);
147 auto iter = label_map.find(mapping[i]);
148 if (iter == label_map.end()) {
149 // key:value --> father:label
150 label_map.emplace(mapping[i], label);
151 mapping[i] = label;
152 label++;
153 } else {
154 mapping[i] = iter->second;
155 }
156 }
157
158 // get point clusters
159 auto original_cloud = frame->cloud;
160 // SppClusterList clusters;
161 clusters_.Reset();
162 clusters_.resize(label_map.size());
163 for (size_t i = 0; i < bg_map_.point_mask_.size(); ++i) {
164 if (!bg_map_.point_mask_.at(i)) {
165 continue;
166 }
167 size_t index = bg_map_.point_idx_.at(i);
168 size_t cluster_label = mapping.at(bg_map_.bg_nodes_.at(index).id);
169 clusters_.AddPointSample(cluster_label, original_cloud->at(i), original_cloud->points_height(i), i);
170 }
172
173 for (int i = 0; i <= clusters_.size() - 1; i++) {
174 clusters_[i]->clear();
175 }
176 clusters_.Reset();
177
178 return true;
179}
180
181float GraphSegmentation::NodeDistance(BgNode n1, int x1, int y1, BgNode n2, int x2, int y2) {
182 float x_diff = static_cast<float>(x1 - x2) * resolution_;
183 float y_diff = static_cast<float>(y1 - y2) * resolution_;
184 float mean_height_diff = n1.mean_height - n2.mean_height;
185 float max_height_diff = n1.max_height - n2.max_height;
186 float mean_intensity = (n1.mean_intensity - n2.mean_intensity) / 255.0;
187 // semantic label
188 int max_label_1 = static_cast<int>(std::distance(
189 n1.pc_semantic_types.begin(), std::max_element(n1.pc_semantic_types.begin(), n1.pc_semantic_types.end())));
190 int max_label_2 = static_cast<int>(std::distance(
191 n2.pc_semantic_types.begin(), std::max_element(n2.pc_semantic_types.begin(), n2.pc_semantic_types.end())));
192 // motion label
193 int max_motion_label_1 = static_cast<int>(std::distance(
194 n1.pc_motion_types.begin(), std::max_element(n1.pc_motion_types.begin(), n1.pc_motion_types.end())));
195 int max_motion_label_2 = static_cast<int>(std::distance(
196 n2.pc_motion_types.begin(), std::max_element(n2.pc_motion_types.begin(), n2.pc_motion_types.end())));
197 // total cost
198 float total_cost = std::sqrt(
199 x_diff * x_diff + y_diff * y_diff + mean_height_diff * mean_height_diff + max_height_diff * max_height_diff
200 + mean_intensity * mean_intensity);
201
202 // semantic coefficient
203 if ((max_label_1 != static_cast<int>(PointSemanticLabel::UNKNOWN))
204 && (max_label_2 != static_cast<int>(PointSemanticLabel::UNKNOWN))) {
205 if (max_label_1 == max_label_2) {
206 total_cost *= bg_config_.same_semantic_coefficient();
207 } else {
208 total_cost *= bg_config_.diff_semantic_coefficient();
209 }
210 }
211
212 // motion coefficient
213 if ((max_motion_label_1 != static_cast<int>(PointMotionLabel::UNKNOWN))
214 && (max_motion_label_2 != static_cast<int>(PointMotionLabel::UNKNOWN))) {
215 if (max_motion_label_1 == max_motion_label_2) {
216 total_cost *= bg_config_.same_motion_coefficient();
217 } else {
218 total_cost *= bg_config_.diff_semantic_coefficient();
219 }
220 }
221
222 return total_cost;
223}
224
226 // point cloud
227 auto original_cloud_ = frame->cloud;
228 auto original_world_cloud_ = frame->world_cloud;
229 // clear background objects
230 bg_objects_.clear();
231 // background object
232 for (size_t i = 0; i < clusters_.size(); ++i) {
233 auto cluster = clusters_[i];
234 if (cluster->point_ids.size() < min_pt_number_) {
235 continue;
236 }
237 base::Object object;
238 object.confidence = cluster->confidence;
239 for (auto idx : cluster->point_ids) {
240 object.lidar_supplement.point_ids.push_back(static_cast<int>(idx));
241 }
242 object.lidar_supplement.num_points_in_roi = cluster->point_ids.size();
243 object.lidar_supplement.cloud.CopyPointCloud(*original_cloud_, cluster->point_ids);
244 object.lidar_supplement.cloud_world.CopyPointCloud(*original_world_cloud_, cluster->point_ids);
245 // copy to background objects
246 std::shared_ptr<base::Object> obj(new base::Object);
247 *obj = object;
248 bg_objects_.push_back(std::move(obj));
249 }
250 // background object builder
251 BgObjectBuilder(&bg_objects_, frame->lidar2novatel_extrinsics);
252}
253
255 std::vector<std::shared_ptr<base::Object>> split_objects;
256 // record object number
257 int before_split_num = bg_objects_.size();
258
259 int valid_number = 0;
260 for (size_t i = 0; i < bg_objects_.size(); i++) {
261 std::shared_ptr<base::Object> obj = bg_objects_.at(i);
262 if (NeedSplit(obj)) {
263 std::vector<base::ObjectPtr> this_split;
264 SplitObject(obj, &this_split, bg_config_.split_distance());
265 BgObjectBuilder(&this_split, frame->lidar2novatel_extrinsics);
266 split_objects.insert(split_objects.end(), this_split.begin(), this_split.end());
267 continue;
268 }
269 bg_objects_.at(valid_number) = obj;
270 valid_number += 1;
271 }
272 int split_number = bg_objects_.size() - valid_number;
273 bg_objects_.resize(valid_number);
274
275 // put all split object to bg_objects_
276 bg_objects_.insert(bg_objects_.end(), split_objects.begin(), split_objects.end());
277 int after_split_num = bg_objects_.size();
278
279 AINFO << "Before split object number: " << before_split_num << ", split number: " << split_number
280 << ", after split number: " << after_split_num;
281 return true;
282}
283
284bool GraphSegmentation::NeedSplit(std::shared_ptr<base::Object> object) {
285 // get length and width
286 float length, width;
287 if (object->size(0) > object->size(1)) {
288 length = object->size(0);
289 width = object->size(1);
290 } else {
291 length = object->size(1);
292 width = object->size(0);
293 }
294 if ((width > kEpsilon) && (length / (width + kEpsilon) > bg_config_.split_aspect_ratio())) {
295 return true;
296 }
297 return false;
298}
299
301 int start_index = frame->segmented_objects.size();
302 for (size_t i = 0; i < bg_objects_.size(); i++) {
303 std::shared_ptr<base::Object> object = bg_objects_.at(i);
304 object->id = start_index++;
305 object->lidar_supplement.is_in_roi = true;
306 object->lidar_supplement.is_background = true;
307 object->lidar_supplement.is_clustered = true;
308 // classification
309 object->type = base::ObjectType::UNKNOWN;
310 object->lidar_supplement.raw_probs.push_back(
311 std::vector<float>(static_cast<int>(base::ObjectType::MAX_OBJECT_TYPE), 0.f));
312 object->lidar_supplement.raw_probs.back()[static_cast<int>(object->type)] = 1.0f;
313 object->lidar_supplement.raw_classification_methods.push_back(Name());
314 // copy to type
315 object->type_probs.assign(
316 object->lidar_supplement.raw_probs.back().begin(), object->lidar_supplement.raw_probs.back().end());
317 // lidar supplement detections
318 object->lidar_supplement.detections.resize(7);
319 for (size_t jj = 0; jj < 7; jj++) {
320 object->lidar_supplement.detections[jj] = 0.0;
321 }
322 }
323 return true;
324}
325
327
328} // namespace lidar
329} // namespace perception
330} // namespace apollo
#define PERCEPTION_REGISTER_LIDARDETECTOR(name)
void Init(const float initial_threshold)
void SegmentGraph(const int num_vertices, const int num_edges, Edge *edges, bool need_sort=true)
bool UpdateMap(LidarFrame *frame)
Update map, update mask and node
bool Init(int width, int height, float resolution, float height_threshold)
Init background map
bool Reset(size_t point_number)
Reset all data
bool SetBgObjectDefaulVal(LidarFrame *frame)
Set the Bacground Object Defaul Value
float NodeDistance(BgNode n1, int x1, int y1, BgNode n2, int x2, int y2)
Compute node distance
bool Segment(LidarFrame *frame)
Graph segment
bool NeedSplit(std::shared_ptr< base::Object > object)
judge if the object need to split
bool Detect(const LidarDetectorOptions &options, LidarFrame *frame) override
Segment pointcloud into objects
bool Split(LidarFrame *frame)
background filter
void GetObjectsFromClusters(LidarFrame *frame)
Get the Objects From Clusters
std::string Name() const override
Get class name
bool Init(const LidarDetectorInitOptions &options=LidarDetectorInitOptions()) override
Init graph segmentation
void AddPointSample(size_t cluster_id, const base::PointF &point, float height, uint32_t point_id)
#define ACHECK(cond)
Definition log.h:80
#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
void SplitObject(const base::ObjectPtr &obj, std::vector< base::ObjectPtr > *split_objs, float split_distance)
split object
bool BgObjectBuilder(std::vector< base::ObjectPtr > *objects, Eigen::Affine3d &lidar2novatel_pose)
background objects builder
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::vector< std::shared_ptr< base::Object > > segmented_objects
Definition lidar_frame.h:53
std::shared_ptr< base::AttributePointCloud< base::PointF > > cloud
Definition lidar_frame.h:35