Apollo 11.0
自动驾驶开放平台
flood_fill.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 *****************************************************************************/
17#include "cyber/common/log.h"
18
19namespace apollo {
20namespace perception {
21namespace lidar {
22
23namespace {
24const int kNumDirections = 8;
25const int di[kNumDirections] = {+1, 0, -1, 0, +1, +1, -1, -1};
26const int dj[kNumDirections] = {0, +1, 0, -1, +1, -1, +1, -1};
27const int kEmptyGridLabel = -1;
28const int kNonEmptyGridLabel = -2;
29} // namespace
30
31int FloodFill::Pos(float x, float y) const {
32 const int irow = static_cast<int>((y + _offset_y) / _cell_size);
33 if (!IsValidRowIndex(irow)) {
34 return -1;
35 }
36 const int jcol = static_cast<int>((x + _offset_x) / _cell_size);
37 if (!IsValidColIndex(jcol)) {
38 return -1;
39 }
40 return irow * _grid_num_cols + jcol;
41}
42
43bool FloodFill::Pos2d(float x, float y, int* irow, int* jcol) const {
44 *irow = static_cast<int>((y + _offset_y) / _cell_size);
45 if (!IsValidRowIndex(*irow)) {
46 return false;
47 }
48 *jcol = static_cast<int>((x + _offset_x) / _cell_size);
49 if (!IsValidColIndex(*jcol)) {
50 return false;
51 }
52 return true;
53}
54
56 CHECK_GT(_grid_radius, 0.0);
57 CHECK_GT(_cell_size, 0.0);
58 // .1 calculate grid size
59 // max_grid_size = 2.f *_grid_radius /_cell_size;
60 _num_points = static_cast<int>(cloud->size());
61 const double min_grid_radius = _grid_radius / 10.0;
62 float min_x = static_cast<float>(-min_grid_radius);
63 float min_y = static_cast<float>(-min_grid_radius);
64 float max_x = static_cast<float>(min_grid_radius);
65 float max_y = static_cast<float>(min_grid_radius);
66
67 for (size_t i = 0; i < cloud->size(); ++i) {
68 auto pt = (*cloud)[i];
69 max_x = std::max(max_x, pt.x);
70 min_x = std::min(min_x, pt.x);
71 max_y = std::max(max_y, pt.y);
72 min_y = std::min(min_y, pt.y);
73 }
74 CHECK_LE(min_x, max_x);
75 CHECK_LE(min_y, max_y);
76 // .2 move origin to the left bottom corner
77 const float lower_x = std::max(min_x, -_grid_radius);
78 const float lower_y = std::max(min_y, -_grid_radius);
79 const float upper_x = std::min(max_x, _grid_radius);
80 const float upper_y = std::min(max_y, _grid_radius);
81 _offset_x = -lower_x;
82 _offset_y = -lower_y;
83 _grid_num_rows = static_cast<int>(ceil((upper_y - lower_y) / _cell_size)) + 1;
84 _grid_num_cols = static_cast<int>(ceil((upper_x - lower_x) / _cell_size)) + 1;
85 CHECK_GT(_grid_num_rows, 0);
86 CHECK_GT(_grid_num_cols, 0);
87 _grid_size = _grid_num_rows * _grid_num_cols;
88 // .3 locate points into grid
89 _point_cloud_grid_idx.assign(_num_points, -1);
90 _label.assign(_grid_size, kEmptyGridLabel);
91 for (int i = 0; i < _num_points; ++i) {
92 const int idx = Pos((*cloud)[i].x, (*cloud)[i].y);
93 if (idx >= 0) {
94 _point_cloud_grid_idx[i] = idx;
95 _label[idx] = kNonEmptyGridLabel;
96 }
97 }
98}
99
100int FloodFill::GetConnectedComponents() {
101 int num_components = 0;
102 for (int idx = 0; idx < _grid_size; ++idx) {
103 auto& label = _label[idx];
104 if (label == kNonEmptyGridLabel) {
105 label = num_components;
106 DfsColoring(idx / _grid_num_cols, idx % _grid_num_cols, num_components);
107 ++num_components;
108 }
109 }
110 return num_components;
111}
112
113void FloodFill::DfsColoring(int i, int j, int curr_component) {
114 // recursively label the neighbors
115 for (int direction = 0; direction < kNumDirections; ++direction) {
116 const int i2 = i + di[direction];
117 const int j2 = j + dj[direction];
118 if (IsValidRowIndex(i2) && IsValidColIndex(j2)) {
119 auto& label = _label[i2 * _grid_num_cols + j2];
120 if (label == kNonEmptyGridLabel) {
121 label = curr_component;
122 DfsColoring(i2, j2, curr_component);
123 }
124 }
125 }
126}
127
130 std::vector<std::vector<int>>* segments_indices,
131 std::vector<int>* num_cells_per_segment) {
132 CHECK_NOTNULL(segments_indices);
133 CHECK_NOTNULL(num_cells_per_segment);
134 // .1 build grid
135 BuildGrid(cloud);
136 // .2 get connected components
137 const int num_segments = GetConnectedComponents();
138 CHECK_GE(num_segments, 0);
139 // .3 write result
140 segments_indices->clear();
141 segments_indices->resize(num_segments);
142 num_cells_per_segment->clear();
143 num_cells_per_segment->resize(num_segments, 0);
144 for (int i = 0; i < _grid_size; ++i) {
145 if (_label[i] != kEmptyGridLabel) {
146 (*num_cells_per_segment)[_label[i]]++;
147 }
148 }
149 for (int i = 0; i < _num_points; ++i) {
150 const int idx = _point_cloud_grid_idx[i];
151 if (idx >= 0) {
152 (*segments_indices)[_label[idx]].push_back(i);
153 }
154 }
155}
156} // namespace lidar
157} // namespace perception
158} // namespace apollo
bool Pos2d(float x, float y, int *irow, int *jcol) const
Get row and col position
Definition flood_fill.cc:43
int Pos(float x, float y) const
Get row and col position
Definition flood_fill.cc:31
void GetSegments(base::PointFCloudConstPtr cloud, std::vector< std::vector< int > > *segments_indices, std::vector< int > *num_cells_per_segment)
Get the segments
void BuildGrid(base::PointFCloudConstPtr cloud)
Build grid based on point cloud
Definition flood_fill.cc:55
std::shared_ptr< const PointFCloud > PointFCloudConstPtr
class register implement
Definition arena_queue.h:37