Base ConstraintBuilder2D on correspondence cost function (#1088)

- Base `ConstraintBuilder2D` and `FastCorrelativeScanMatcher2D` on correspondence cost function instead of probabilities
- No changes in the options of `ConstraintBuilder2D` and `FastCorrelativeScanMatcher2D`
- Add properties `min/max_correspondence_cost` to `Grid2D` and `proto::Grid2D`
- Provide backwards compatibility for `proto::Grid2D`
 - Step towards [RFC 0019](https://github.com/googlecartographer/rfcs/blob/master/text/0019-probability-grid-and-submap2d-restructuring.md)
master
Kevin Daun 2018-04-19 11:59:28 +02:00 committed by Wally B. Feed
parent f4937b5cc6
commit 20c80068b2
9 changed files with 106 additions and 79 deletions

View File

@ -20,11 +20,16 @@
namespace cartographer { namespace cartographer {
namespace mapping { namespace mapping {
Grid2D::Grid2D(const MapLimits& limits) Grid2D::Grid2D(const MapLimits& limits, float min_correspondence_cost,
float max_correspondence_cost)
: limits_(limits), : limits_(limits),
correspondence_cost_cells_( correspondence_cost_cells_(
limits_.cell_limits().num_x_cells * limits_.cell_limits().num_y_cells, limits_.cell_limits().num_x_cells * limits_.cell_limits().num_y_cells,
kUnknownCorrespondenceValue) {} kUnknownCorrespondenceValue),
min_correspondence_cost_(min_correspondence_cost),
max_correspondence_cost_(max_correspondence_cost) {
CHECK_LT(min_correspondence_cost_, max_correspondence_cost_);
}
Grid2D::Grid2D(const proto::Grid2D& proto) Grid2D::Grid2D(const proto::Grid2D& proto)
: limits_(proto.limits()), correspondence_cost_cells_() { : limits_(proto.limits()), correspondence_cost_cells_() {
@ -39,6 +44,19 @@ Grid2D::Grid2D(const proto::Grid2D& proto)
CHECK_LE(cell, std::numeric_limits<uint16>::max()); CHECK_LE(cell, std::numeric_limits<uint16>::max());
correspondence_cost_cells_.push_back(cell); correspondence_cost_cells_.push_back(cell);
} }
if (proto.min_correspondence_cost() == 0.f &&
proto.max_correspondence_cost() == 0.f) {
LOG(WARNING)
<< "proto::Grid2D: max_correspondence_cost and min_correspondence_cost "
"are initialized with 0 indicating an older version of the "
"protobuf format. Loading default values.";
min_correspondence_cost_ = kMinCorrespondenceCost;
max_correspondence_cost_ = kMaxCorrespondenceCost;
} else {
min_correspondence_cost_ = proto.min_correspondence_cost();
max_correspondence_cost_ = proto.max_correspondence_cost();
}
CHECK_LT(min_correspondence_cost_, max_correspondence_cost_);
} }
// Finishes the update sequence. // Finishes the update sequence.
@ -51,21 +69,14 @@ void Grid2D::FinishUpdate() {
} }
} }
// Sets the probability of the cell at 'cell_index' to the given // Returns the correspondence cost of the cell with 'cell_index'.
// 'probability'. Only allowed if the cell was unknown before.
void Grid2D::SetCorrespondenceCost(const Eigen::Array2i& cell_index,
const float correspondence_cost) {
LOG(FATAL) << "Not implemented";
}
// Returns the probability of the cell with 'cell_index'.
float Grid2D::GetCorrespondenceCost(const Eigen::Array2i& cell_index) const { float Grid2D::GetCorrespondenceCost(const Eigen::Array2i& cell_index) const {
if (!limits().Contains(cell_index)) return kMaxCorrespondenceCost; if (!limits().Contains(cell_index)) return kMaxCorrespondenceCost;
return ValueToCorrespondenceCost( return ValueToCorrespondenceCost(
correspondence_cost_cells()[ToFlatIndex(cell_index)]); correspondence_cost_cells()[ToFlatIndex(cell_index)]);
} }
// Returns true if the probability at the specified index is known. // Returns true if the correspondence cost at the specified index is known.
bool Grid2D::IsKnown(const Eigen::Array2i& cell_index) const { bool Grid2D::IsKnown(const Eigen::Array2i& cell_index) const {
return limits_.Contains(cell_index) && return limits_.Contains(cell_index) &&
correspondence_cost_cells_[ToFlatIndex(cell_index)] != correspondence_cost_cells_[ToFlatIndex(cell_index)] !=
@ -136,6 +147,8 @@ proto::Grid2D Grid2D::ToProto() const {
box->set_min_x(known_cells_box().min().x()); box->set_min_x(known_cells_box().min().x());
box->set_min_y(known_cells_box().min().y()); box->set_min_y(known_cells_box().min().y());
} }
result.set_min_correspondence_cost(min_correspondence_cost_);
result.set_max_correspondence_cost(max_correspondence_cost_);
return result; return result;
} }

View File

@ -27,23 +27,24 @@ namespace mapping {
class Grid2D { class Grid2D {
public: public:
explicit Grid2D(const MapLimits& limits); explicit Grid2D(const MapLimits& limits, float min_correspondence_cost,
float max_correspondence_cost);
explicit Grid2D(const proto::Grid2D& proto); explicit Grid2D(const proto::Grid2D& proto);
// Returns the limits of this ProbabilityGrid. // Returns the limits of this Grid2D.
const MapLimits& limits() const { return limits_; } const MapLimits& limits() const { return limits_; }
// Finishes the update sequence. // Finishes the update sequence.
void FinishUpdate(); void FinishUpdate();
// Sets the correspondence cost of the cell at 'cell_index' to the given
// 'correspondence_cost'. Only allowed if the cell was unknown before.
void SetCorrespondenceCost(const Eigen::Array2i& cell_index,
const float correspondence_cost);
// Returns the correspondence cost of the cell with 'cell_index'. // Returns the correspondence cost of the cell with 'cell_index'.
float GetCorrespondenceCost(const Eigen::Array2i& cell_index) const; float GetCorrespondenceCost(const Eigen::Array2i& cell_index) const;
// Returns the minimum possible correspondence cost.
float GetMinCorrespondenceCost() const { return min_correspondence_cost_; }
// Returns the maximum possible correspondence cost.
float GetMaxCorrespondenceCost() const { return max_correspondence_cost_; }
// Returns true if the probability at the specified index is known. // Returns true if the probability at the specified index is known.
bool IsKnown(const Eigen::Array2i& cell_index) const; bool IsKnown(const Eigen::Array2i& cell_index) const;
@ -80,6 +81,8 @@ class Grid2D {
private: private:
MapLimits limits_; MapLimits limits_;
std::vector<uint16> correspondence_cost_cells_; std::vector<uint16> correspondence_cost_cells_;
float min_correspondence_cost_;
float max_correspondence_cost_;
std::vector<int> update_indices_; std::vector<int> update_indices_;
// Bounding box of known cells to efficiently compute cropping limits. // Bounding box of known cells to efficiently compute cropping limits.

View File

@ -22,7 +22,8 @@
namespace cartographer { namespace cartographer {
namespace mapping { namespace mapping {
ProbabilityGrid::ProbabilityGrid(const MapLimits& limits) : Grid2D(limits) {} ProbabilityGrid::ProbabilityGrid(const MapLimits& limits)
: Grid2D(limits, kMinCorrespondenceCost, kMaxCorrespondenceCost) {}
ProbabilityGrid::ProbabilityGrid(const proto::Grid2D& proto) : Grid2D(proto) { ProbabilityGrid::ProbabilityGrid(const proto::Grid2D& proto) : Grid2D(proto) {
CHECK(proto.has_probability_grid_2d()); CHECK(proto.has_probability_grid_2d());

View File

@ -35,4 +35,6 @@ message Grid2D {
oneof grid { oneof grid {
ProbabilityGrid probability_grid_2d = 4; ProbabilityGrid probability_grid_2d = 4;
} }
float min_correspondence_cost = 6;
float max_correspondence_cost = 7;
} }

View File

@ -130,7 +130,7 @@ void ConstraintBuilder2D::WhenDone(
} }
void ConstraintBuilder2D::ScheduleSubmapScanMatcherConstructionAndQueueWorkItem( void ConstraintBuilder2D::ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
const SubmapId& submap_id, const ProbabilityGrid* const submap, const SubmapId& submap_id, const Grid2D* const grid,
const std::function<void()>& work_item) { const std::function<void()>& work_item) {
if (submap_scan_matchers_[submap_id].fast_correlative_scan_matcher != if (submap_scan_matchers_[submap_id].fast_correlative_scan_matcher !=
nullptr) { nullptr) {
@ -139,18 +139,18 @@ void ConstraintBuilder2D::ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
submap_queued_work_items_[submap_id].push_back(work_item); submap_queued_work_items_[submap_id].push_back(work_item);
if (submap_queued_work_items_[submap_id].size() == 1) { if (submap_queued_work_items_[submap_id].size() == 1) {
thread_pool_->Schedule( thread_pool_->Schedule(
[=]() { ConstructSubmapScanMatcher(submap_id, submap); }); [=]() { ConstructSubmapScanMatcher(submap_id, grid); });
} }
} }
} }
void ConstraintBuilder2D::ConstructSubmapScanMatcher( void ConstraintBuilder2D::ConstructSubmapScanMatcher(const SubmapId& submap_id,
const SubmapId& submap_id, const ProbabilityGrid* const submap) { const Grid2D* const grid) {
auto submap_scan_matcher = auto submap_scan_matcher =
common::make_unique<scan_matching::FastCorrelativeScanMatcher2D>( common::make_unique<scan_matching::FastCorrelativeScanMatcher2D>(
*submap, options_.fast_correlative_scan_matcher_options()); *grid, options_.fast_correlative_scan_matcher_options());
common::MutexLocker locker(&mutex_); common::MutexLocker locker(&mutex_);
submap_scan_matchers_[submap_id] = {submap, std::move(submap_scan_matcher)}; submap_scan_matchers_[submap_id] = {grid, std::move(submap_scan_matcher)};
for (const std::function<void()>& work_item : for (const std::function<void()>& work_item :
submap_queued_work_items_[submap_id]) { submap_queued_work_items_[submap_id]) {
thread_pool_->Schedule(work_item); thread_pool_->Schedule(work_item);
@ -227,8 +227,8 @@ void ConstraintBuilder2D::ComputeConstraint(
ceres::Solver::Summary unused_summary; ceres::Solver::Summary unused_summary;
ceres_scan_matcher_.Match(pose_estimate.translation(), pose_estimate, ceres_scan_matcher_.Match(pose_estimate.translation(), pose_estimate,
constant_data->filtered_gravity_aligned_point_cloud, constant_data->filtered_gravity_aligned_point_cloud,
*submap_scan_matcher->probability_grid, *submap_scan_matcher->grid, &pose_estimate,
&pose_estimate, &unused_summary); &unused_summary);
const transform::Rigid2d constraint_transform = const transform::Rigid2d constraint_transform =
ComputeSubmapPose(*submap).inverse() * pose_estimate; ComputeSubmapPose(*submap).inverse() * pose_estimate;

View File

@ -105,7 +105,7 @@ class ConstraintBuilder2D {
private: private:
struct SubmapScanMatcher { struct SubmapScanMatcher {
const ProbabilityGrid* probability_grid; const Grid2D* grid;
std::unique_ptr<scan_matching::FastCorrelativeScanMatcher2D> std::unique_ptr<scan_matching::FastCorrelativeScanMatcher2D>
fast_correlative_scan_matcher; fast_correlative_scan_matcher;
}; };
@ -113,12 +113,11 @@ class ConstraintBuilder2D {
// Either schedules the 'work_item', or if needed, schedules the scan matcher // Either schedules the 'work_item', or if needed, schedules the scan matcher
// construction and queues the 'work_item'. // construction and queues the 'work_item'.
void ScheduleSubmapScanMatcherConstructionAndQueueWorkItem( void ScheduleSubmapScanMatcherConstructionAndQueueWorkItem(
const SubmapId& submap_id, const ProbabilityGrid* submap, const SubmapId& submap_id, const Grid2D* grid,
const std::function<void()>& work_item) REQUIRES(mutex_); const std::function<void()>& work_item) REQUIRES(mutex_);
// Constructs the scan matcher for a 'submap', then schedules its work items. // Constructs the scan matcher for a 'submap', then schedules its work items.
void ConstructSubmapScanMatcher(const SubmapId& submap_id, void ConstructSubmapScanMatcher(const SubmapId& submap_id, const Grid2D* grid)
const ProbabilityGrid* submap)
EXCLUDES(mutex_); EXCLUDES(mutex_);
// Returns the scan matcher for a submap, which has to exist. // Returns the scan matcher for a submap, which has to exist.

View File

@ -25,7 +25,7 @@
#include "Eigen/Geometry" #include "Eigen/Geometry"
#include "cartographer/common/make_unique.h" #include "cartographer/common/make_unique.h"
#include "cartographer/common/math.h" #include "cartographer/common/math.h"
#include "cartographer/mapping/2d/probability_grid.h" #include "cartographer/mapping/2d/grid_2d.h"
#include "cartographer/sensor/point_cloud.h" #include "cartographer/sensor/point_cloud.h"
#include "cartographer/transform/transform.h" #include "cartographer/transform/transform.h"
#include "glog/logging.h" #include "glog/logging.h"
@ -89,11 +89,13 @@ CreateFastCorrelativeScanMatcherOptions2D(
} }
PrecomputationGrid2D::PrecomputationGrid2D( PrecomputationGrid2D::PrecomputationGrid2D(
const ProbabilityGrid& probability_grid, const CellLimits& limits, const Grid2D& grid, const CellLimits& limits, const int width,
const int width, std::vector<float>* reusable_intermediate_grid) std::vector<float>* reusable_intermediate_grid)
: offset_(-width + 1, -width + 1), : offset_(-width + 1, -width + 1),
wide_limits_(limits.num_x_cells + width - 1, wide_limits_(limits.num_x_cells + width - 1,
limits.num_y_cells + width - 1), limits.num_y_cells + width - 1),
min_score_(1.f - grid.GetMaxCorrespondenceCost()),
max_score_(1.f - grid.GetMinCorrespondenceCost()),
cells_(wide_limits_.num_x_cells * wide_limits_.num_y_cells) { cells_(wide_limits_.num_x_cells * wide_limits_.num_y_cells) {
CHECK_GE(width, 1); CHECK_GE(width, 1);
CHECK_GE(limits.num_x_cells, 1); CHECK_GE(limits.num_x_cells, 1);
@ -106,26 +108,26 @@ PrecomputationGrid2D::PrecomputationGrid2D(
for (int y = 0; y != limits.num_y_cells; ++y) { for (int y = 0; y != limits.num_y_cells; ++y) {
SlidingWindowMaximum current_values; SlidingWindowMaximum current_values;
current_values.AddValue( current_values.AddValue(
probability_grid.GetProbability(Eigen::Array2i(0, y))); 1.f - std::abs(grid.GetCorrespondenceCost(Eigen::Array2i(0, y))));
for (int x = -width + 1; x != 0; ++x) { for (int x = -width + 1; x != 0; ++x) {
intermediate[x + width - 1 + y * stride] = current_values.GetMaximum(); intermediate[x + width - 1 + y * stride] = current_values.GetMaximum();
if (x + width < limits.num_x_cells) { if (x + width < limits.num_x_cells) {
current_values.AddValue( current_values.AddValue(1.f - std::abs(grid.GetCorrespondenceCost(
probability_grid.GetProbability(Eigen::Array2i(x + width, y))); Eigen::Array2i(x + width, y))));
} }
} }
for (int x = 0; x < limits.num_x_cells - width; ++x) { for (int x = 0; x < limits.num_x_cells - width; ++x) {
intermediate[x + width - 1 + y * stride] = current_values.GetMaximum(); intermediate[x + width - 1 + y * stride] = current_values.GetMaximum();
current_values.RemoveValue( current_values.RemoveValue(
probability_grid.GetProbability(Eigen::Array2i(x, y))); 1.f - std::abs(grid.GetCorrespondenceCost(Eigen::Array2i(x, y))));
current_values.AddValue( current_values.AddValue(1.f - std::abs(grid.GetCorrespondenceCost(
probability_grid.GetProbability(Eigen::Array2i(x + width, y))); Eigen::Array2i(x + width, y))));
} }
for (int x = std::max(limits.num_x_cells - width, 0); for (int x = std::max(limits.num_x_cells - width, 0);
x != limits.num_x_cells; ++x) { x != limits.num_x_cells; ++x) {
intermediate[x + width - 1 + y * stride] = current_values.GetMaximum(); intermediate[x + width - 1 + y * stride] = current_values.GetMaximum();
current_values.RemoveValue( current_values.RemoveValue(
probability_grid.GetProbability(Eigen::Array2i(x, y))); 1.f - std::abs(grid.GetCorrespondenceCost(Eigen::Array2i(x, y))));
} }
current_values.CheckIsEmpty(); current_values.CheckIsEmpty();
} }
@ -159,38 +161,37 @@ PrecomputationGrid2D::PrecomputationGrid2D(
} }
uint8 PrecomputationGrid2D::ComputeCellValue(const float probability) const { uint8 PrecomputationGrid2D::ComputeCellValue(const float probability) const {
const int cell_value = const int cell_value = common::RoundToInt(
common::RoundToInt((probability - kMinProbability) * (probability - min_score_) * (255.f / (max_score_ - min_score_)));
(255.f / (kMaxProbability - kMinProbability)));
CHECK_GE(cell_value, 0); CHECK_GE(cell_value, 0);
CHECK_LE(cell_value, 255); CHECK_LE(cell_value, 255);
return cell_value; return cell_value;
} }
PrecomputationGridStack2D::PrecomputationGridStack2D( PrecomputationGridStack2D::PrecomputationGridStack2D(
const ProbabilityGrid& probability_grid, const Grid2D& grid,
const proto::FastCorrelativeScanMatcherOptions2D& options) { const proto::FastCorrelativeScanMatcherOptions2D& options) {
CHECK_GE(options.branch_and_bound_depth(), 1); CHECK_GE(options.branch_and_bound_depth(), 1);
const int max_width = 1 << (options.branch_and_bound_depth() - 1); const int max_width = 1 << (options.branch_and_bound_depth() - 1);
precomputation_grids_.reserve(options.branch_and_bound_depth()); precomputation_grids_.reserve(options.branch_and_bound_depth());
std::vector<float> reusable_intermediate_grid; std::vector<float> reusable_intermediate_grid;
const CellLimits limits = probability_grid.limits().cell_limits(); const CellLimits limits = grid.limits().cell_limits();
reusable_intermediate_grid.reserve((limits.num_x_cells + max_width - 1) * reusable_intermediate_grid.reserve((limits.num_x_cells + max_width - 1) *
limits.num_y_cells); limits.num_y_cells);
for (int i = 0; i != options.branch_and_bound_depth(); ++i) { for (int i = 0; i != options.branch_and_bound_depth(); ++i) {
const int width = 1 << i; const int width = 1 << i;
precomputation_grids_.emplace_back(probability_grid, limits, width, precomputation_grids_.emplace_back(grid, limits, width,
&reusable_intermediate_grid); &reusable_intermediate_grid);
} }
} }
FastCorrelativeScanMatcher2D::FastCorrelativeScanMatcher2D( FastCorrelativeScanMatcher2D::FastCorrelativeScanMatcher2D(
const ProbabilityGrid& probability_grid, const Grid2D& grid,
const proto::FastCorrelativeScanMatcherOptions2D& options) const proto::FastCorrelativeScanMatcherOptions2D& options)
: options_(options), : options_(options),
limits_(probability_grid.limits()), limits_(grid.limits()),
precomputation_grid_stack_(common::make_unique<PrecomputationGridStack2D>( precomputation_grid_stack_(
probability_grid, options)) {} common::make_unique<PrecomputationGridStack2D>(grid, options)) {}
FastCorrelativeScanMatcher2D::~FastCorrelativeScanMatcher2D() {} FastCorrelativeScanMatcher2D::~FastCorrelativeScanMatcher2D() {}
@ -324,7 +325,7 @@ void FastCorrelativeScanMatcher2D::ScoreCandidates(
xy_index.y() + candidate.y_index_offset); xy_index.y() + candidate.y_index_offset);
sum += precomputation_grid.GetValue(proposed_xy_index); sum += precomputation_grid.GetValue(proposed_xy_index);
} }
candidate.score = PrecomputationGrid2D::ToProbability( candidate.score = precomputation_grid.ToScore(
sum / static_cast<float>(discrete_scans[candidate.scan_index].size())); sum / static_cast<float>(discrete_scans[candidate.scan_index].size()));
} }
std::sort(candidates->begin(), candidates->end(), std::sort(candidates->begin(), candidates->end(),

View File

@ -30,10 +30,9 @@
#include "Eigen/Core" #include "Eigen/Core"
#include "cartographer/common/port.h" #include "cartographer/common/port.h"
#include "cartographer/mapping/2d/probability_grid.h" #include "cartographer/mapping/2d/grid_2d.h"
#include "cartographer/mapping/2d/scan_matching/proto/fast_correlative_scan_matcher_options_2d.pb.h" #include "cartographer/mapping/2d/scan_matching/proto/fast_correlative_scan_matcher_options_2d.pb.h"
#include "cartographer/mapping/internal/2d/scan_matching/correlative_scan_matcher_2d.h" #include "cartographer/mapping/internal/2d/scan_matching/correlative_scan_matcher_2d.h"
#include "cartographer/mapping/probability_values.h"
#include "cartographer/sensor/point_cloud.h" #include "cartographer/sensor/point_cloud.h"
namespace cartographer { namespace cartographer {
@ -49,12 +48,11 @@ CreateFastCorrelativeScanMatcherOptions2D(
// y0 <= y < y0. // y0 <= y < y0.
class PrecomputationGrid2D { class PrecomputationGrid2D {
public: public:
PrecomputationGrid2D(const ProbabilityGrid& probability_grid, PrecomputationGrid2D(const Grid2D& grid, const CellLimits& limits, int width,
const CellLimits& limits, int width,
std::vector<float>* reusable_intermediate_grid); std::vector<float>* reusable_intermediate_grid);
// Returns a value between 0 and 255 to represent probabilities between // Returns a value between 0 and 255 to represent probabilities between
// kMinProbability and kMaxProbability. // min_score and max_score.
int GetValue(const Eigen::Array2i& xy_index) const { int GetValue(const Eigen::Array2i& xy_index) const {
const Eigen::Array2i local_xy_index = xy_index - offset_; const Eigen::Array2i local_xy_index = xy_index - offset_;
// The static_cast<unsigned> is for performance to check with 2 comparisons // The static_cast<unsigned> is for performance to check with 2 comparisons
@ -72,10 +70,9 @@ class PrecomputationGrid2D {
return cells_[local_xy_index.x() + local_xy_index.y() * stride]; return cells_[local_xy_index.x() + local_xy_index.y() * stride];
} }
// Maps values from [0, 255] to [kMinProbability, kMaxProbability]. // Maps values from [0, 255] to [min_score, max_score].
static float ToProbability(float value) { float ToScore(float value) const {
return kMinProbability + return min_score_ + value * ((max_score_ - min_score_) / 255.f);
value * ((kMaxProbability - kMinProbability) / 255.f);
} }
private: private:
@ -88,6 +85,9 @@ class PrecomputationGrid2D {
// Size of the precomputation grid. // Size of the precomputation grid.
const CellLimits wide_limits_; const CellLimits wide_limits_;
const float min_score_;
const float max_score_;
// Probabilites mapped to 0 to 255. // Probabilites mapped to 0 to 255.
std::vector<uint8> cells_; std::vector<uint8> cells_;
}; };
@ -95,7 +95,7 @@ class PrecomputationGrid2D {
class PrecomputationGridStack2D { class PrecomputationGridStack2D {
public: public:
PrecomputationGridStack2D( PrecomputationGridStack2D(
const ProbabilityGrid& probability_grid, const Grid2D& grid,
const proto::FastCorrelativeScanMatcherOptions2D& options); const proto::FastCorrelativeScanMatcherOptions2D& options);
const PrecomputationGrid2D& Get(int index) { const PrecomputationGrid2D& Get(int index) {
@ -112,7 +112,7 @@ class PrecomputationGridStack2D {
class FastCorrelativeScanMatcher2D { class FastCorrelativeScanMatcher2D {
public: public:
FastCorrelativeScanMatcher2D( FastCorrelativeScanMatcher2D(
const ProbabilityGrid& probability_grid, const Grid2D& grid,
const proto::FastCorrelativeScanMatcherOptions2D& options); const proto::FastCorrelativeScanMatcherOptions2D& options);
~FastCorrelativeScanMatcher2D(); ~FastCorrelativeScanMatcher2D();
@ -120,7 +120,7 @@ class FastCorrelativeScanMatcher2D {
FastCorrelativeScanMatcher2D& operator=(const FastCorrelativeScanMatcher2D&) = FastCorrelativeScanMatcher2D& operator=(const FastCorrelativeScanMatcher2D&) =
delete; delete;
// Aligns 'point_cloud' within the 'probability_grid' given an // Aligns 'point_cloud' within the 'grid' given an
// 'initial_pose_estimate'. If a score above 'min_score' (excluding equality) // 'initial_pose_estimate'. If a score above 'min_score' (excluding equality)
// is possible, true is returned, and 'score' and 'pose_estimate' are updated // is possible, true is returned, and 'score' and 'pose_estimate' are updated
// with the result. // with the result.
@ -128,7 +128,7 @@ class FastCorrelativeScanMatcher2D {
const sensor::PointCloud& point_cloud, float min_score, const sensor::PointCloud& point_cloud, float min_score,
float* score, transform::Rigid2d* pose_estimate) const; float* score, transform::Rigid2d* pose_estimate) const;
// Aligns 'point_cloud' within the full 'probability_grid', i.e., not // Aligns 'point_cloud' within the full 'grid', i.e., not
// restricted to the configured search window. If a score above 'min_score' // restricted to the configured search window. If a score above 'min_score'
// (excluding equality) is possible, true is returned, and 'score' and // (excluding equality) is possible, true is returned, and 'score' and
// 'pose_estimate' are updated with the result. // 'pose_estimate' are updated with the result.

View File

@ -41,13 +41,17 @@ TEST(PrecomputationGridTest, CorrectValues) {
std::uniform_int_distribution<int> distribution(0, 255); std::uniform_int_distribution<int> distribution(0, 255);
ProbabilityGrid probability_grid( ProbabilityGrid probability_grid(
MapLimits(0.05, Eigen::Vector2d(5., 5.), CellLimits(250, 250))); MapLimits(0.05, Eigen::Vector2d(5., 5.), CellLimits(250, 250)));
std::vector<float> reusable_intermediate_grid;
PrecomputationGrid2D precomputation_grid_dummy(
probability_grid, probability_grid.limits().cell_limits(), 1,
&reusable_intermediate_grid);
for (const Eigen::Array2i& xy_index : for (const Eigen::Array2i& xy_index :
XYIndexRangeIterator(Eigen::Array2i(50, 50), Eigen::Array2i(249, 249))) { XYIndexRangeIterator(Eigen::Array2i(50, 50), Eigen::Array2i(249, 249))) {
probability_grid.SetProbability( probability_grid.SetProbability(
xy_index, PrecomputationGrid2D::ToProbability(distribution(prng))); xy_index, precomputation_grid_dummy.ToScore(distribution(prng)));
} }
std::vector<float> reusable_intermediate_grid; reusable_intermediate_grid.clear();
for (const int width : {1, 2, 3, 8}) { for (const int width : {1, 2, 3, 8}) {
PrecomputationGrid2D precomputation_grid( PrecomputationGrid2D precomputation_grid(
probability_grid, probability_grid.limits().cell_limits(), width, probability_grid, probability_grid.limits().cell_limits(), width,
@ -62,10 +66,10 @@ TEST(PrecomputationGridTest, CorrectValues) {
probability_grid.GetProbability(xy_index + Eigen::Array2i(x, y))); probability_grid.GetProbability(xy_index + Eigen::Array2i(x, y)));
} }
} }
EXPECT_NEAR(max_score, EXPECT_NEAR(
PrecomputationGrid2D::ToProbability( max_score,
precomputation_grid.GetValue(xy_index)), precomputation_grid.ToScore(precomputation_grid.GetValue(xy_index)),
1e-4); 1e-4);
} }
} }
} }
@ -75,13 +79,17 @@ TEST(PrecomputationGridTest, TinyProbabilityGrid) {
std::uniform_int_distribution<int> distribution(0, 255); std::uniform_int_distribution<int> distribution(0, 255);
ProbabilityGrid probability_grid( ProbabilityGrid probability_grid(
MapLimits(0.05, Eigen::Vector2d(0.1, 0.1), CellLimits(4, 4))); MapLimits(0.05, Eigen::Vector2d(0.1, 0.1), CellLimits(4, 4)));
std::vector<float> reusable_intermediate_grid;
PrecomputationGrid2D precomputation_grid_dummy(
probability_grid, probability_grid.limits().cell_limits(), 1,
&reusable_intermediate_grid);
for (const Eigen::Array2i& xy_index : for (const Eigen::Array2i& xy_index :
XYIndexRangeIterator(probability_grid.limits().cell_limits())) { XYIndexRangeIterator(probability_grid.limits().cell_limits())) {
probability_grid.SetProbability( probability_grid.SetProbability(
xy_index, PrecomputationGrid2D::ToProbability(distribution(prng))); xy_index, precomputation_grid_dummy.ToScore(distribution(prng)));
} }
std::vector<float> reusable_intermediate_grid; reusable_intermediate_grid.clear();
for (const int width : {1, 2, 3, 8, 200}) { for (const int width : {1, 2, 3, 8, 200}) {
PrecomputationGrid2D precomputation_grid( PrecomputationGrid2D precomputation_grid(
probability_grid, probability_grid.limits().cell_limits(), width, probability_grid, probability_grid.limits().cell_limits(), width,
@ -96,10 +104,10 @@ TEST(PrecomputationGridTest, TinyProbabilityGrid) {
probability_grid.GetProbability(xy_index + Eigen::Array2i(x, y))); probability_grid.GetProbability(xy_index + Eigen::Array2i(x, y)));
} }
} }
EXPECT_NEAR(max_score, EXPECT_NEAR(
PrecomputationGrid2D::ToProbability( max_score,
precomputation_grid.GetValue(xy_index)), precomputation_grid.ToScore(precomputation_grid.GetValue(xy_index)),
1e-4); 1e-4);
} }
} }
} }