24 #include "Eigen/Geometry" 28 #include "cartographer/mapping_3d/scan_matching/proto/fast_correlative_scan_matcher_options.pb.h" 30 #include "glog/logging.h" 33 namespace mapping_3d {
34 namespace scan_matching {
36 proto::FastCorrelativeScanMatcherOptions
39 proto::FastCorrelativeScanMatcherOptions options;
40 options.set_branch_and_bound_depth(
41 parameter_dictionary->
GetInt(
"branch_and_bound_depth"));
42 options.set_full_resolution_depth(
43 parameter_dictionary->
GetInt(
"full_resolution_depth"));
44 options.set_rotational_histogram_size(
45 parameter_dictionary->
GetInt(
"rotational_histogram_size"));
46 options.set_min_rotational_score(
47 parameter_dictionary->
GetDouble(
"min_rotational_score"));
48 options.set_linear_xy_search_window(
49 parameter_dictionary->
GetDouble(
"linear_xy_search_window"));
50 options.set_linear_z_search_window(
51 parameter_dictionary->
GetDouble(
"linear_z_search_window"));
52 options.set_angular_search_window(
53 parameter_dictionary->
GetDouble(
"angular_search_window"));
61 const proto::FastCorrelativeScanMatcherOptions& options) {
62 CHECK_GE(options.branch_and_bound_depth(), 1);
63 CHECK_GE(options.full_resolution_depth(), 1);
66 Eigen::Array3i last_width = Eigen::Array3i::Ones();
67 for (
int depth = 1; depth != options.branch_and_bound_depth(); ++depth) {
68 const bool half_resolution = depth >= options.full_resolution_depth();
69 const Eigen::Array3i next_width = ((1 << depth) * Eigen::Array3i::Ones());
70 const int full_voxels_per_high_resolution_voxel =
71 1 << std::max(0, depth - options.full_resolution_depth());
72 const Eigen::Array3i shift =
73 (next_width - last_width +
74 (full_voxels_per_high_resolution_voxel - 1)) /
75 full_voxels_per_high_resolution_voxel;
78 last_width = next_width;
94 const std::vector<mapping::TrajectoryNode>& nodes,
95 const proto::FastCorrelativeScanMatcherOptions& options)
97 resolution_(hybrid_grid.resolution()),
98 width_in_voxels_(hybrid_grid.grid_size()),
99 precomputation_grid_stack_(
101 rotational_scan_matcher_(nodes,
options_.rotational_histogram_size()) {}
115 coarse_point_cloud, fine_point_cloud,
116 min_score, score, pose_estimate);
120 const Eigen::Quaterniond& gravity_alignment,
126 float max_point_distance = 0.f;
127 for (
const Eigen::Vector3f& point : coarse_point_cloud) {
128 max_point_distance = std::max(max_point_distance, point.norm());
130 const int linear_window_size =
134 linear_window_size, M_PI};
136 coarse_point_cloud, fine_point_cloud,
137 min_score, score, pose_estimate);
146 CHECK_NOTNULL(score);
147 CHECK_NOTNULL(pose_estimate);
150 search_parameters, coarse_point_cloud, fine_point_cloud,
151 initial_pose_estimate.
cast<
float>());
153 const std::vector<Candidate> lowest_resolution_candidates =
157 search_parameters, discrete_scans, lowest_resolution_candidates,
159 if (best_candidate.
score > min_score) {
160 *score = best_candidate.
score;
164 Eigen::Quaternionf::Identity()) *
165 discrete_scans[best_candidate.
scan_index].pose)
176 std::vector<std::vector<Eigen::Array3i>> cell_indices_per_depth;
178 std::vector<Eigen::Array3i> full_resolution_cell_indices;
179 for (
const Eigen::Vector3f& point :
181 full_resolution_cell_indices.push_back(original_grid.
GetCellIndex(point));
183 const int full_resolution_depth = std::min(
options_.full_resolution_depth(),
185 CHECK_GE(full_resolution_depth, 1);
186 for (
int i = 0; i != full_resolution_depth; ++i) {
187 cell_indices_per_depth.push_back(full_resolution_cell_indices);
189 const int low_resolution_depth =
190 options_.branch_and_bound_depth() - full_resolution_depth;
191 CHECK_GE(low_resolution_depth, 0);
192 const Eigen::Array3i search_window_start(
196 for (
int i = 0; i != low_resolution_depth; ++i) {
197 const int reduction_exponent = i + 1;
198 const Eigen::Array3i low_resolution_search_window_start(
199 search_window_start[0] >> reduction_exponent,
200 search_window_start[1] >> reduction_exponent,
201 search_window_start[2] >> reduction_exponent);
202 cell_indices_per_depth.emplace_back();
203 for (
const Eigen::Array3i& cell_index : full_resolution_cell_indices) {
204 const Eigen::Array3i cell_at_start = cell_index + search_window_start;
205 const Eigen::Array3i low_resolution_cell_at_start(
206 cell_at_start[0] >> reduction_exponent,
207 cell_at_start[1] >> reduction_exponent,
208 cell_at_start[2] >> reduction_exponent);
209 cell_indices_per_depth.back().push_back(
210 low_resolution_cell_at_start - low_resolution_search_window_start);
221 std::vector<DiscreteScan> result;
225 for (
const Eigen::Vector3f& point : coarse_point_cloud) {
226 const float range = point.norm();
227 max_scan_range = std::max(range, max_scan_range);
229 const float kSafetyMargin = 1.f - 1e-2f;
230 const float angular_step_size =
237 std::vector<float> angles;
238 for (
int rz = -angular_window_size; rz <= angular_window_size; ++rz) {
239 angles.push_back(rz * angular_step_size);
243 for (
size_t i = 0; i != angles.size(); ++i) {
244 if (scores[i] <
options_.min_rotational_score()) {
247 const Eigen::Vector3f angle_axis(0.f, 0.f, angles[i]);
261 std::vector<Candidate>
264 const int num_discrete_scans)
const {
266 const int num_lowest_resolution_linear_xy_candidates =
269 const int num_lowest_resolution_linear_z_candidates =
272 const int num_candidates =
274 common::Power(num_lowest_resolution_linear_xy_candidates, 2) *
275 num_lowest_resolution_linear_z_candidates;
276 std::vector<Candidate> candidates;
277 candidates.reserve(num_candidates);
278 for (
int scan_index = 0; scan_index != num_discrete_scans; ++scan_index) {
283 y += linear_step_size) {
286 x += linear_step_size) {
287 candidates.emplace_back(scan_index, Eigen::Array3i(x, y, z));
292 CHECK_EQ(candidates.size(), num_candidates);
297 const int depth,
const std::vector<DiscreteScan>& discrete_scans,
298 std::vector<Candidate>*
const candidates)
const {
299 const int reduction_exponent =
300 std::max(0, depth -
options_.full_resolution_depth() + 1);
301 for (
Candidate& candidate : *candidates) {
303 const DiscreteScan& discrete_scan = discrete_scans[candidate.scan_index];
304 const Eigen::Array3i offset(candidate.offset[0] >> reduction_exponent,
305 candidate.offset[1] >> reduction_exponent,
306 candidate.offset[2] >> reduction_exponent);
308 for (
const Eigen::Array3i& cell_index :
310 const Eigen::Array3i proposed_cell_index = cell_index + offset;
317 std::sort(candidates->begin(), candidates->end(), std::greater<Candidate>());
320 std::vector<Candidate>
323 const std::vector<DiscreteScan>& discrete_scans)
const {
324 std::vector<Candidate> lowest_resolution_candidates =
326 discrete_scans.size());
328 &lowest_resolution_candidates);
329 return lowest_resolution_candidates;
334 const std::vector<DiscreteScan>& discrete_scans,
335 const std::vector<Candidate>& candidates,
const int candidate_depth,
336 float min_score)
const {
337 if (candidate_depth == 0) {
339 return *candidates.begin();
342 Candidate best_high_resolution_candidate(0, Eigen::Array3i::Zero());
343 best_high_resolution_candidate.
score = min_score;
344 for (
const Candidate& candidate : candidates) {
345 if (candidate.score <= min_score) {
348 std::vector<Candidate> higher_resolution_candidates;
349 const int half_width = 1 << (candidate_depth - 1);
350 for (
int z : {0, half_width}) {
354 for (
int y : {0, half_width}) {
355 if (candidate.offset.y() + y >
359 for (
int x : {0, half_width}) {
360 if (candidate.offset.x() + x >
364 higher_resolution_candidates.emplace_back(
365 candidate.scan_index, candidate.offset + Eigen::Array3i(x, y, z));
370 &higher_resolution_candidates);
371 best_high_resolution_candidate = std::max(
372 best_high_resolution_candidate,
374 higher_resolution_candidates, candidate_depth - 1,
375 best_high_resolution_candidate.
score));
377 return best_high_resolution_candidate;
proto::FastCorrelativeScanMatcherOptions CreateFastCorrelativeScanMatcherOptions(common::LuaParameterDictionary *const parameter_dictionary)
std::unique_ptr< PrecomputationGridStack > precomputation_grid_stack_
proto::RangeDataInserterOptions options_
PointCloud TransformPointCloud(const PointCloud &point_cloud, const transform::Rigid3f &transform)
std::vector< Candidate > ComputeLowestResolutionCandidates(const SearchParameters &search_parameters, const std::vector< DiscreteScan > &discrete_scans) const
Candidate BranchAndBound(const SearchParameters &search_parameters, const std::vector< DiscreteScan > &discrete_scans, const std::vector< Candidate > &candidates, int candidate_depth, float min_score) const
Eigen::Array3i GetCellIndex(const Eigen::Vector3f &point) const
const double angular_search_window
static float ToProbability(float value)
int GetInt(const string &key)
int RoundToInt(const float x)
std::vector< Candidate > GenerateLowestResolutionCandidates(const SearchParameters &search_parameters, int num_discrete_scans) const
double GetDouble(const string &key)
constexpr T Power(T base, int exponent)
~FastCorrelativeScanMatcher()
const int linear_xy_window_size
FastCorrelativeScanMatcher(const HybridGrid &hybrid_grid, const std::vector< mapping::TrajectoryNode > &nodes, const proto::FastCorrelativeScanMatcherOptions &options)
std::vector< DiscreteScan > GenerateDiscreteScans(const SearchParameters &search_parameters, const sensor::PointCloud &coarse_point_cloud, const sensor::PointCloud &fine_point_cloud, const transform::Rigid3f &initial_pose) const
const proto::FastCorrelativeScanMatcherOptions options_
const PrecomputationGrid & Get(int depth) const
std::vector< Eigen::Vector3f > PointCloud
const int linear_z_window_size
std::vector< std::vector< Eigen::Array3i > > cell_indices_per_depth
bool MatchWithSearchParameters(const SearchParameters &search_parameters, const transform::Rigid3d &initial_pose_estimate, const sensor::PointCloud &coarse_point_cloud, const sensor::PointCloud &fine_point_cloud, float min_score, float *score, transform::Rigid3d *pose_estimate) const
PrecomputationGrid PrecomputeGrid(const PrecomputationGrid &grid, const bool half_resolution, const Eigen::Array3i &shift)
std::vector< PrecomputationGrid > precomputation_grids_
bool MatchFullSubmap(const Eigen::Quaterniond &gravity_alignment, const sensor::PointCloud &coarse_point_cloud, const sensor::PointCloud &fine_point_cloud, float min_score, float *score, transform::Rigid3d *pose_estimate) const
PrecomputationGridStack(const HybridGrid &hybrid_grid, const proto::FastCorrelativeScanMatcherOptions &options)
PrecomputationGrid ConvertToPrecomputationGrid(const HybridGrid &hybrid_grid)
const int width_in_voxels_
DiscreteScan DiscretizeScan(const SearchParameters &search_parameters, const sensor::PointCloud &point_cloud, const transform::Rigid3f &pose) const
std::vector< float > Match(const sensor::PointCloud &point_cloud, const std::vector< float > &angles) const
_Unique_if< T >::_Single_object make_unique(Args &&...args)
bool Match(const transform::Rigid3d &initial_pose_estimate, const sensor::PointCloud &coarse_point_cloud, const sensor::PointCloud &fine_point_cloud, float min_score, float *score, transform::Rigid3d *pose_estimate) const
void ScoreCandidates(int depth, const std::vector< DiscreteScan > &discrete_scans, std::vector< Candidate > *const candidates) const
RotationalScanMatcher rotational_scan_matcher_