Matcher_Points_Base.cpp
Go to the documentation of this file.
1 /* -------------------------------------------------------------------------
2  * A repertory of multi primitive-to-primitive (MP2P) ICP algorithms in C++
3  * Copyright (C) 2018-2024 Jose Luis Blanco, University of Almeria
4  * See LICENSE for license information.
5  * ------------------------------------------------------------------------- */
14 #include <mrpt/random/random_shuffle.h>
15 
16 #include <chrono>
17 #include <numeric> // iota
18 #include <random>
19 
20 using namespace mp2p_icp;
21 
23  const metric_map_t& pcGlobal, const metric_map_t& pcLocal,
24  const mrpt::poses::CPose3D& localPose, [[maybe_unused]] const MatchContext& mc, MatchState& ms,
25  Pairings& out) const
26 {
27  MRPT_START
28 
29  out = Pairings();
30 
31  // Analyze point cloud layers, one by one:
32  for (const auto& glLayerKV : pcGlobal.layers)
33  {
34  const auto& glLayerName = glLayerKV.first;
35 
36  // List of local layers to match against (and optional weights)
37  std::map<std::string, std::optional<double>> localLayers;
38 
39  if (!weight_pt2pt_layers.empty())
40  {
41  const auto itGlob = weight_pt2pt_layers.find(glLayerName);
42  // If we have weights and this layer is not listed, Skip it:
43  if (itGlob == weight_pt2pt_layers.end()) continue;
44 
45  for (const auto& kv : itGlob->second) localLayers[kv.first] = kv.second;
46  }
47  else
48  {
49  // Default: match by identical layer names:
50  localLayers[glLayerName] = {};
51  }
52 
53  for (const auto& localWeight : localLayers)
54  {
55  const auto& localLayerName = localWeight.first;
56  const bool hasWeight = localWeight.second.has_value();
57 
58  // Look for a matching layer in "local":
59  auto itLocal = pcLocal.layers.find(localLayerName);
60  if (itLocal == pcLocal.layers.end())
61  {
62  // Silently ignore it:
63  if (!hasWeight)
64  continue;
65  else
66  THROW_EXCEPTION_FMT(
67  "Local pointcloud layer '%s' not found matching global "
68  "layer '%s'",
69  localLayerName.c_str(), glLayerName.c_str());
70  }
71 
72  const mrpt::maps::CMetricMap::Ptr& glLayer = glLayerKV.second;
73  ASSERT_(glLayer);
74 
75  const mrpt::maps::CMetricMap::Ptr& lcLayerMap = itLocal->second;
76  ASSERT_(lcLayerMap);
77  const auto lcLayer = mp2p_icp::MapToPointsMap(*lcLayerMap);
78  if (!lcLayer)
79  THROW_EXCEPTION_FMT(
80  "Local layer map must be a point cloud, but found type "
81  "'%s'",
82  lcLayerMap->GetRuntimeClass()->className);
83 
84  const size_t nBefore = out.paired_pt2pt.size();
85 
86  // Ensure we have the KD-tree parameters desired by the user:
87  if (kdtree_leaf_max_points_.has_value())
88  {
89  if (auto glLayerPts = mp2p_icp::MapToPointsMap(*glLayer);
90  glLayerPts &&
91  glLayerPts->kdtree_search_params.leaf_max_size != *kdtree_leaf_max_points_)
92  {
93  glLayerPts->kdtree_search_params.leaf_max_size = *kdtree_leaf_max_points_;
94  glLayerPts->mark_as_modified(); // rebuild kd-tree index
95  }
96  }
97 
98  // matcher implementation:
99  implMatchOneLayer(*glLayer, *lcLayer, localPose, ms, glLayerName, localLayerName, out);
100 
101  const size_t nAfter = out.paired_pt2pt.size();
102 
103  if (hasWeight && nAfter != nBefore)
104  {
105  const double w = localWeight.second.value();
106  out.point_weights.emplace_back(nAfter - nBefore, w);
107  }
108  }
109  }
110  return true;
111  MRPT_END
112 }
113 
114 void Matcher_Points_Base::initialize(const mrpt::containers::yaml& params)
115 {
116  Matcher::initialize(params);
117 
118  if (params.has("pointLayerMatches"))
119  {
120  auto& p = params["pointLayerMatches"];
121 
122  weight_pt2pt_layers.clear();
123  ASSERT_(p.isSequence());
124 
125  // - {global: "raw", local: "decimated", weight: 1.0}
126  // - {global: "raw", local: "decimated", weight: 1.0}
127  // ...
128 
129  for (const auto& entry : p.asSequence())
130  {
131  ASSERT_(entry.isMap());
132  const auto& em = entry.asMap();
133 
134  ASSERT_(em.count("global"));
135  ASSERT_(em.count("local"));
136 
137  const std::string globalLayer = em.at("global").as<std::string>();
138  const std::string localLayer = em.at("local").as<std::string>();
139  const double w = em.count("weight") != 0 ? em.at("weight").as<double>() : 1.0;
140 
141  weight_pt2pt_layers[globalLayer][localLayer] = w;
142  }
143  }
144 
146  params.getOrDefault("maxLocalPointsPerLayer", maxLocalPointsPerLayer_);
147 
148  localPointsSampleSeed_ = params.getOrDefault("localPointsSampleSeed", localPointsSampleSeed_);
149 
151  params.getOrDefault("allowMatchAlreadyMatchedPoints", allowMatchAlreadyMatchedPoints_);
152 
153  allowMatchAlreadyMatchedGlobalPoints_ = params.getOrDefault(
154  "allowMatchAlreadyMatchedGlobalPoints", allowMatchAlreadyMatchedGlobalPoints_);
155 
156  if (auto val = params.getOrDefault("kdtree_leaf_max_points", 0); val > 0)
158 
159  bounding_box_intersection_check_epsilon_ = params.getOrDefault(
160  "bounding_box_intersection_check_epsilon", bounding_box_intersection_check_epsilon_);
161 }
162 
164  const mrpt::maps::CPointsMap& pcLocal, const mrpt::poses::CPose3D& localPose,
165  const std::size_t maxLocalPoints, const uint64_t localPointsSampleSeed)
166 {
167  MRPT_START
169 
170  const auto lambdaKeepBBox = [&](float x, float y, float z)
171  {
172  mrpt::keep_max(r.localMax.x, x);
173  mrpt::keep_max(r.localMax.y, y);
174  mrpt::keep_max(r.localMax.z, z);
175 
176  mrpt::keep_min(r.localMin.x, x);
177  mrpt::keep_min(r.localMin.y, y);
178  mrpt::keep_min(r.localMin.z, z);
179  };
180 
181  const auto& lxs = pcLocal.getPointsBufferRef_x();
182  const auto& lys = pcLocal.getPointsBufferRef_y();
183  const auto& lzs = pcLocal.getPointsBufferRef_z();
184 
185  const size_t nLocalPoints = pcLocal.size();
186 
187  if (maxLocalPoints == 0 || nLocalPoints <= maxLocalPoints)
188  {
189  // All points:
190  r.x_locals.resize(nLocalPoints);
191  r.y_locals.resize(nLocalPoints);
192  r.z_locals.resize(nLocalPoints);
193 
194  for (size_t i = 0; i < nLocalPoints; i++)
195  {
196  localPose.composePoint(
197  lxs[i], lys[i], lzs[i], r.x_locals[i], r.y_locals[i], r.z_locals[i]);
198  lambdaKeepBBox(r.x_locals[i], r.y_locals[i], r.z_locals[i]);
199  }
200  }
201  else
202  {
203  // random subset:
204  r.idxs.emplace(maxLocalPoints);
205  std::iota(r.idxs->begin(), r.idxs->end(), 0);
206 
207  const unsigned int seed = localPointsSampleSeed != 0
208  ? localPointsSampleSeed
209  : std::chrono::system_clock::now().time_since_epoch().count();
210 
211  mrpt::random::partial_shuffle(
212  r.idxs->begin(), r.idxs->end(), std::default_random_engine(seed), maxLocalPoints);
213 
214  r.x_locals.resize(maxLocalPoints);
215  r.y_locals.resize(maxLocalPoints);
216  r.z_locals.resize(maxLocalPoints);
217 
218  for (size_t ri = 0; ri < maxLocalPoints; ri++)
219  {
220  const auto i = (*r.idxs)[ri];
221  localPose.composePoint(
222  lxs[i], lys[i], lzs[i], r.x_locals[ri], r.y_locals[ri], r.z_locals[ri]);
223  lambdaKeepBBox(r.x_locals[ri], r.y_locals[ri], r.z_locals[ri]);
224  }
225  }
226 
227  return r;
228  MRPT_END
229 }
mp2p_icp::Matcher_Points_Base::kdtree_leaf_max_points_
std::optional< std::size_t > kdtree_leaf_max_points_
Definition: Matcher_Points_Base.h:59
mp2p_icp
Definition: covariance.h:17
mp2p_icp::Matcher_Points_Base::bounding_box_intersection_check_epsilon_
double bounding_box_intersection_check_epsilon_
Definition: Matcher_Points_Base.h:63
mp2p_icp::Matcher_Points_Base::TransformedLocalPointCloud
Definition: Matcher_Points_Base.h:90
mp2p_icp::Matcher_Points_Base::allowMatchAlreadyMatchedGlobalPoints_
bool allowMatchAlreadyMatchedGlobalPoints_
Definition: Matcher_Points_Base.h:56
mp2p_icp::Pairings
Definition: Pairings.h:76
mp2p_icp::Matcher_Points_Base::weight_pt2pt_layers
std::map< std::string, std::map< std::string, double > > weight_pt2pt_layers
Definition: Matcher_Points_Base.h:45
mp2p_icp::Matcher_Points_Base::allowMatchAlreadyMatchedPoints_
bool allowMatchAlreadyMatchedPoints_
Definition: Matcher_Points_Base.h:52
test.x
x
Definition: test.py:4
testing::internal::string
::std::string string
Definition: gtest.h:1979
mp2p_icp::Matcher_Points_Base::implMatchOneLayer
virtual void implMatchOneLayer(const mrpt::maps::CMetricMap &pcGlobal, const mrpt::maps::CPointsMap &pcLocal, const mrpt::poses::CPose3D &localPose, MatchState &ms, const layer_name_t &globalName, const layer_name_t &localName, Pairings &out) const =0
mp2p_icp::Matcher_Points_Base::initialize
void initialize(const mrpt::containers::yaml &params) override
Definition: Matcher_Points_Base.cpp:114
mp2p_icp::MatchState
Definition: Matcher.h:37
kitti-batch-convert.out
string out
Definition: kitti-batch-convert.py:7
mp2p_icp::MatchContext
Definition: Matcher.h:29
mp2p_icp::MapToPointsMap
const mrpt::maps::CPointsMap * MapToPointsMap(const mrpt::maps::CMetricMap &map)
Definition: metricmap.cpp:624
Matcher_Points_Base.h
Pointcloud matcher auxiliary class for iterating over point layers.
mp2p_icp::Matcher_Points_Base::localPointsSampleSeed_
uint64_t localPointsSampleSeed_
Definition: Matcher_Points_Base.h:48
mp2p_icp::Matcher_Points_Base::impl_match
bool impl_match(const metric_map_t &pcGlobal, const metric_map_t &pcLocal, const mrpt::poses::CPose3D &localPose, const MatchContext &mc, MatchState &ms, Pairings &out) const override final
Definition: Matcher_Points_Base.cpp:22
mp2p_icp::metric_map_t
Generic container of pointcloud(s), extracted features and other maps.
Definition: metricmap.h:55
mp2p_icp::Matcher_Points_Base::maxLocalPointsPerLayer_
uint64_t maxLocalPointsPerLayer_
Definition: Matcher_Points_Base.h:47
mp2p_icp::metric_map_t::layers
std::map< layer_name_t, mrpt::maps::CMetricMap::Ptr > layers
Definition: metricmap.h:82
mp2p_icp::Matcher_Points_Base::transform_local_to_global
static TransformedLocalPointCloud transform_local_to_global(const mrpt::maps::CPointsMap &pcLocal, const mrpt::poses::CPose3D &localPose, const std::size_t maxLocalPoints=0, const uint64_t localPointsSampleSeed=0)
Definition: Matcher_Points_Base.cpp:163
mp2p_icp::Matcher::initialize
virtual void initialize(const mrpt::containers::yaml &params)
Definition: mp2p_icp/src/Matcher.cpp:20


mp2p_icp
Author(s):
autogenerated on Mon May 26 2025 02:45:49