voxel_filter.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2016 The Cartographer Authors
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 <cmath>
20 
22 
23 namespace cartographer {
24 namespace sensor {
25 
26 namespace {
27 
28 PointCloud FilterByMaxRange(const PointCloud& point_cloud,
29  const float max_range) {
30  PointCloud result;
31  for (const Eigen::Vector3f& point : point_cloud) {
32  if (point.norm() <= max_range) {
33  result.push_back(point);
34  }
35  }
36  return result;
37 }
38 
39 PointCloud AdaptivelyVoxelFiltered(
40  const proto::AdaptiveVoxelFilterOptions& options,
41  const PointCloud& point_cloud) {
42  if (point_cloud.size() <= options.min_num_points()) {
43  // 'point_cloud' is already sparse enough.
44  return point_cloud;
45  }
46  PointCloud result = VoxelFilter(options.max_length()).Filter(point_cloud);
47  if (result.size() >= options.min_num_points()) {
48  // Filtering with 'max_length' resulted in a sufficiently dense point cloud.
49  return result;
50  }
51  // Search for a 'low_length' that is known to result in a sufficiently
52  // dense point cloud. We give up and use the full 'point_cloud' if reducing
53  // the edge length by a factor of 1e-2 is not enough.
54  for (float high_length = options.max_length();
55  high_length > 1e-2f * options.max_length(); high_length /= 2.f) {
56  float low_length = high_length / 2.f;
57  result = VoxelFilter(low_length).Filter(point_cloud);
58  if (result.size() >= options.min_num_points()) {
59  // Binary search to find the right amount of filtering. 'low_length' gave
60  // a sufficiently dense 'result', 'high_length' did not. We stop when the
61  // edge length is at most 10% off.
62  while ((high_length - low_length) / low_length > 1e-1f) {
63  const float mid_length = (low_length + high_length) / 2.f;
64  const PointCloud candidate =
65  VoxelFilter(mid_length).Filter(point_cloud);
66  if (candidate.size() >= options.min_num_points()) {
67  low_length = mid_length;
68  result = candidate;
69  } else {
70  high_length = mid_length;
71  }
72  }
73  return result;
74  }
75  }
76  return result;
77 }
78 
79 } // namespace
80 
82  PointCloud results;
83  for (const Eigen::Vector3f& point : point_cloud) {
84  auto it_inserted = voxel_set_.insert(IndexToKey(GetCellIndex(point)));
85  if (it_inserted.second) {
86  results.push_back(point);
87  }
88  }
89  return results;
90 }
91 
93  TimedPointCloud results;
94  for (const Eigen::Vector4f& point : timed_point_cloud) {
95  auto it_inserted =
96  voxel_set_.insert(IndexToKey(GetCellIndex(point.head<3>())));
97  if (it_inserted.second) {
98  results.push_back(point);
99  }
100  }
101  return results;
102 }
103 
104 std::vector<sensor::TimedPointCloudOriginData::RangeMeasurement>
106  const std::vector<sensor::TimedPointCloudOriginData::RangeMeasurement>&
107  range_measurements) {
108  std::vector<sensor::TimedPointCloudOriginData::RangeMeasurement> results;
109  for (const auto& range_measurement : range_measurements) {
110  auto it_inserted = voxel_set_.insert(
111  IndexToKey(GetCellIndex(range_measurement.point_time.head<3>())));
112  if (it_inserted.second) {
113  results.push_back(range_measurement);
114  }
115  }
116  return results;
117 }
118 
119 VoxelFilter::KeyType VoxelFilter::IndexToKey(const Eigen::Array3i& index) {
120  KeyType k_0(static_cast<uint32>(index[0]));
121  KeyType k_1(static_cast<uint32>(index[1]));
122  KeyType k_2(static_cast<uint32>(index[2]));
123  return (k_0 << 2 * 32) | (k_1 << 1 * 32) | k_2;
124 }
125 
126 Eigen::Array3i VoxelFilter::GetCellIndex(const Eigen::Vector3f& point) const {
127  Eigen::Array3f index = point.array() / resolution_;
128  return Eigen::Array3i(common::RoundToInt(index.x()),
129  common::RoundToInt(index.y()),
130  common::RoundToInt(index.z()));
131 }
132 
133 proto::AdaptiveVoxelFilterOptions CreateAdaptiveVoxelFilterOptions(
134  common::LuaParameterDictionary* const parameter_dictionary) {
135  proto::AdaptiveVoxelFilterOptions options;
136  options.set_max_length(parameter_dictionary->GetDouble("max_length"));
137  options.set_min_num_points(
138  parameter_dictionary->GetNonNegativeInt("min_num_points"));
139  options.set_max_range(parameter_dictionary->GetDouble("max_range"));
140  return options;
141 }
142 
144  const proto::AdaptiveVoxelFilterOptions& options)
145  : options_(options) {}
146 
148  return AdaptivelyVoxelFiltered(
149  options_, FilterByMaxRange(point_cloud, options_.max_range()));
150 }
151 
152 } // namespace sensor
153 } // namespace cartographer
PointCloud Filter(const PointCloud &point_cloud) const
int RoundToInt(const float x)
Definition: port.h:41
AdaptiveVoxelFilter(const proto::AdaptiveVoxelFilterOptions &options)
proto::ProbabilityGridRangeDataInserterOptions2D options_
static KeyType IndexToKey(const Eigen::Array3i &index)
Eigen::Array3i GetCellIndex(const Eigen::Vector3f &point) const
std::vector< Eigen::Vector3f > PointCloud
Definition: point_cloud.h:32
proto::AdaptiveVoxelFilterOptions CreateAdaptiveVoxelFilterOptions(common::LuaParameterDictionary *const parameter_dictionary)
std::vector< Eigen::Vector4f > TimedPointCloud
Definition: point_cloud.h:39
std::bitset< 3 *32 > KeyType
Definition: voxel_filter.h:54
const proto::AdaptiveVoxelFilterOptions options_
Definition: voxel_filter.h:78
std::unordered_set< KeyType > voxel_set_
Definition: voxel_filter.h:61
PointCloud Filter(const PointCloud &point_cloud)
Definition: voxel_filter.cc:81


cartographer
Author(s): The Cartographer Authors
autogenerated on Mon Feb 28 2022 22:00:59