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,
25  [[maybe_unused]] const MatchContext& mc, MatchState& ms,
26  Pairings& out) const
27 {
28  MRPT_START
29 
30  out = Pairings();
31 
32  // Analyze point cloud layers, one by one:
33  for (const auto& glLayerKV : pcGlobal.layers)
34  {
35  const auto& glLayerName = glLayerKV.first;
36 
37  // List of local layers to match against (and optional weights)
38  std::map<std::string, std::optional<double>> localLayers;
39 
40  if (!weight_pt2pt_layers.empty())
41  {
42  const auto itGlob = weight_pt2pt_layers.find(glLayerName);
43  // If we have weights and this layer is not listed, Skip it:
44  if (itGlob == weight_pt2pt_layers.end()) continue;
45 
46  for (const auto& kv : itGlob->second)
47  localLayers[kv.first] = kv.second;
48  }
49  else
50  {
51  // Default: match by identical layer names:
52  localLayers[glLayerName] = {};
53  }
54 
55  for (const auto& localWeight : localLayers)
56  {
57  const auto& localLayerName = localWeight.first;
58  const bool hasWeight = localWeight.second.has_value();
59 
60  // Look for a matching layer in "local":
61  auto itLocal = pcLocal.layers.find(localLayerName);
62  if (itLocal == pcLocal.layers.end())
63  {
64  // Silently ignore it:
65  if (!hasWeight)
66  continue;
67  else
68  THROW_EXCEPTION_FMT(
69  "Local pointcloud layer '%s' not found matching global "
70  "layer '%s'",
71  localLayerName.c_str(), glLayerName.c_str());
72  }
73 
74  const mrpt::maps::CMetricMap::Ptr& glLayer = glLayerKV.second;
75  ASSERT_(glLayer);
76 
77  const mrpt::maps::CMetricMap::Ptr& lcLayerMap = itLocal->second;
78  ASSERT_(lcLayerMap);
79  const auto lcLayer = mp2p_icp::MapToPointsMap(*lcLayerMap);
80  if (!lcLayer)
81  THROW_EXCEPTION_FMT(
82  "Local layer map must be a point cloud, but found type "
83  "'%s'",
84  lcLayerMap->GetRuntimeClass()->className);
85 
86  const size_t nBefore = out.paired_pt2pt.size();
87 
88  // Ensure we have the KD-tree parameters desired by the user:
89  if (kdtree_leaf_max_points_.has_value())
90  {
91  if (auto glLayerPts = mp2p_icp::MapToPointsMap(*glLayer);
92  glLayerPts &&
93  glLayerPts->kdtree_search_params.leaf_max_size !=
95  {
96  glLayerPts->kdtree_search_params.leaf_max_size =
98  glLayerPts->mark_as_modified(); // rebuild kd-tree index
99  }
100  }
101 
102  // matcher implementation:
104  *glLayer, *lcLayer, localPose, ms, glLayerName, localLayerName,
105  out);
106 
107  const size_t nAfter = out.paired_pt2pt.size();
108 
109  if (hasWeight && nAfter != nBefore)
110  {
111  const double w = localWeight.second.value();
112  out.point_weights.emplace_back(nAfter - nBefore, w);
113  }
114  }
115  }
116  return true;
117  MRPT_END
118 }
119 
120 void Matcher_Points_Base::initialize(const mrpt::containers::yaml& params)
121 {
122  Matcher::initialize(params);
123 
124  if (params.has("pointLayerMatches"))
125  {
126  auto& p = params["pointLayerMatches"];
127 
128  weight_pt2pt_layers.clear();
129  ASSERT_(p.isSequence());
130 
131  // - {global: "raw", local: "decimated", weight: 1.0}
132  // - {global: "raw", local: "decimated", weight: 1.0}
133  // ...
134 
135  for (const auto& entry : p.asSequence())
136  {
137  ASSERT_(entry.isMap());
138  const auto& em = entry.asMap();
139 
140  ASSERT_(em.count("global"));
141  ASSERT_(em.count("local"));
142 
143  const std::string globalLayer = em.at("global").as<std::string>();
144  const std::string localLayer = em.at("local").as<std::string>();
145  const double w =
146  em.count("weight") != 0 ? em.at("weight").as<double>() : 1.0;
147 
148  weight_pt2pt_layers[globalLayer][localLayer] = w;
149  }
150  }
151 
153  params.getOrDefault("maxLocalPointsPerLayer", maxLocalPointsPerLayer_);
154 
156  params.getOrDefault("localPointsSampleSeed", localPointsSampleSeed_);
157 
158  allowMatchAlreadyMatchedPoints_ = params.getOrDefault(
159  "allowMatchAlreadyMatchedPoints", allowMatchAlreadyMatchedPoints_);
160 
161  allowMatchAlreadyMatchedGlobalPoints_ = params.getOrDefault(
162  "allowMatchAlreadyMatchedGlobalPoints",
164 
165  if (auto val = params.getOrDefault("kdtree_leaf_max_points", 0); val > 0)
167 
168  bounding_box_intersection_check_epsilon_ = params.getOrDefault(
169  "bounding_box_intersection_check_epsilon",
171 }
172 
175  const mrpt::maps::CPointsMap& pcLocal,
176  const mrpt::poses::CPose3D& localPose, const std::size_t maxLocalPoints,
177  const uint64_t localPointsSampleSeed)
178 {
179  MRPT_START
181 
182  const auto lambdaKeepBBox = [&](float x, float y, float z) {
183  mrpt::keep_max(r.localMax.x, x);
184  mrpt::keep_max(r.localMax.y, y);
185  mrpt::keep_max(r.localMax.z, z);
186 
187  mrpt::keep_min(r.localMin.x, x);
188  mrpt::keep_min(r.localMin.y, y);
189  mrpt::keep_min(r.localMin.z, z);
190  };
191 
192  const auto& lxs = pcLocal.getPointsBufferRef_x();
193  const auto& lys = pcLocal.getPointsBufferRef_y();
194  const auto& lzs = pcLocal.getPointsBufferRef_z();
195 
196  const size_t nLocalPoints = pcLocal.size();
197 
198  if (maxLocalPoints == 0 || nLocalPoints <= maxLocalPoints)
199  {
200  // All points:
201  r.x_locals.resize(nLocalPoints);
202  r.y_locals.resize(nLocalPoints);
203  r.z_locals.resize(nLocalPoints);
204 
205  for (size_t i = 0; i < nLocalPoints; i++)
206  {
207  localPose.composePoint(
208  lxs[i], lys[i], lzs[i], r.x_locals[i], r.y_locals[i],
209  r.z_locals[i]);
210  lambdaKeepBBox(r.x_locals[i], r.y_locals[i], r.z_locals[i]);
211  }
212  }
213  else
214  {
215  // random subset:
216  r.idxs.emplace(maxLocalPoints);
217  std::iota(r.idxs->begin(), r.idxs->end(), 0);
218 
219  const unsigned int seed =
220  localPointsSampleSeed != 0
221  ? localPointsSampleSeed
222  : std::chrono::system_clock::now().time_since_epoch().count();
223 
224  mrpt::random::partial_shuffle(
225  r.idxs->begin(), r.idxs->end(), std::default_random_engine(seed),
226  maxLocalPoints);
227 
228  r.x_locals.resize(maxLocalPoints);
229  r.y_locals.resize(maxLocalPoints);
230  r.z_locals.resize(maxLocalPoints);
231 
232  for (size_t ri = 0; ri < maxLocalPoints; ri++)
233  {
234  const auto i = (*r.idxs)[ri];
235  localPose.composePoint(
236  lxs[i], lys[i], lzs[i], r.x_locals[ri], r.y_locals[ri],
237  r.z_locals[ri]);
238  lambdaKeepBBox(r.x_locals[ri], r.y_locals[ri], r.z_locals[ri]);
239  }
240  }
241 
242  return r;
243  MRPT_END
244 }
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:78
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:120
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:648
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:49
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:76
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:174
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 Thu Dec 26 2024 03:48:12