Matcher_Points_DistanceThreshold.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/core/exceptions.h>
15 #include <mrpt/core/round.h>
16 #include <mrpt/version.h>
17 
18 #if defined(MP2P_HAS_TBB)
19 #include <tbb/blocked_range.h>
20 #include <tbb/parallel_reduce.h>
21 #endif
22 
24 
25 using namespace mp2p_icp;
26 
28 {
29  mrpt::system::COutputLogger::setLoggerName(
30  "Matcher_Points_DistanceThreshold");
31 }
32 
34  const mrpt::containers::yaml& params)
35 {
37 
41 }
42 
44  const mrpt::maps::CMetricMap& pcGlobalMap,
45  const mrpt::maps::CPointsMap& pcLocal,
46  const mrpt::poses::CPose3D& localPose, MatchState& ms,
47  const layer_name_t& globalName, const layer_name_t& localName,
48  Pairings& out) const
49 {
50  MRPT_START
51 
53 
54  ASSERT_(pairingsPerPoint >= 1);
55  ASSERT_GT_(threshold, .0);
56  ASSERT_GE_(thresholdAngularDeg, .0);
57 
58  const mrpt::maps::NearestNeighborsCapable& nnGlobal =
59  *mp2p_icp::MapToNN(pcGlobalMap, true /*throw if cannot convert*/);
60 
61  out.potential_pairings += pcLocal.size() * pairingsPerPoint;
62 
63  // Empty maps? Nothing to do
64  if (pcGlobalMap.isEmpty() || pcLocal.empty()) return;
65 
67  pcLocal, localPose, maxLocalPointsPerLayer_, localPointsSampleSeed_);
68 
69  // Try to do matching only if the bounding boxes have some overlap:
70  if (!pcGlobalMap.boundingBox().intersection(
71  {tl.localMin, tl.localMax},
73  return;
74 
75  // Prepare output: no correspondences initially:
76  out.paired_pt2pt.reserve(out.paired_pt2pt.size() + pcLocal.size());
77 
78  // Loop for each point in local map:
79  // --------------------------------------------------
80  const float maxDistForCorrespondenceSquared = mrpt::square(threshold);
81  const float angularThresholdFactorSquared =
82  mrpt::square(mrpt::DEG2RAD(thresholdAngularDeg));
83 
84  const auto& lxs = pcLocal.getPointsBufferRef_x();
85  const auto& lys = pcLocal.getPointsBufferRef_y();
86  const auto& lzs = pcLocal.getPointsBufferRef_z();
87  const size_t nLocalPts = lxs.size();
88 
89  // Make sure the 3D kd-trees (if used internally) are up to date, from this
90  // single-thread call before entering into parallelization:
91  nnGlobal.nn_prepare_for_3d_queries();
92 
93  const auto lambdaAddPair =
94  [this, &ms, &globalName, &localName, &lxs, &lys, &lzs](
95  mrpt::tfest::TMatchingPairList& outPairs, const size_t localIdx,
96  const mrpt::math::TPoint3Df& globalPt, const uint64_t globalIdxOrID,
97  const float errSqr)
98  {
99  // Filter out if global alread assigned, in another matcher up the
100  // pipeline, for example.
102  ms.globalPairedBitField.point_layers.at(globalName)[globalIdxOrID])
103  return; // skip, global point already paired.
104 
105  // Save new correspondence:
106  auto& p = outPairs.emplace_back();
107 
108  p.globalIdx = globalIdxOrID;
109  p.localIdx = localIdx;
110  p.global = globalPt;
111  p.local = {lxs[localIdx], lys[localIdx], lzs[localIdx]};
112 
113  p.errorSquareAfterTransformation = errSqr;
114 
115  // Mark local & global points as already paired:
117  {
118  ms.localPairedBitField.point_layers[localName].mark_as_set(
119  localIdx);
120  ms.globalPairedBitField.point_layers[globalName].mark_as_set(
121  globalIdxOrID);
122  }
123  };
124 
125 #if defined(MP2P_HAS_TBB)
126  // For the TBB lambdas:
127  // TBB call structure based on the beautiful implementation in KISS-ICP.
128  using Result = mrpt::tfest::TMatchingPairList;
129 
130  auto newPairs = tbb::parallel_reduce(
131  // Range
132  tbb::blocked_range<size_t>{0, nLocalPts},
133  // Identity
134  Result(),
135  // 1st lambda: Parallel computation
136  [&](const tbb::blocked_range<size_t>& r, Result res) -> Result
137  {
138  res.reserve(r.size());
139  std::vector<uint64_t> neighborIndices;
140  std::vector<float> neighborSqrDists;
141  std::vector<mrpt::math::TPoint3Df> neighborPts;
142  for (size_t i = r.begin(); i < r.end(); i++)
143  {
144  const size_t localIdx = tl.idxs.has_value() ? (*tl.idxs)[i] : i;
145 
147  ms.localPairedBitField.point_layers.at(localName)[localIdx])
148  continue; // skip, already paired.
149 
150  // For speed-up:
151  const float lx = tl.x_locals[i], ly = tl.y_locals[i],
152  lz = tl.z_locals[i];
153 
154  const float localNormSqr =
155  mrpt::square(lx) + mrpt::square(ly) + mrpt::square(lz);
156 
157  // Use a KD-tree to look for the nearnest neighbor(s) of
158  // (x_local, y_local, z_local) in the global map.
159  if (pairingsPerPoint == 1)
160  {
161  neighborIndices.resize(1);
162  neighborSqrDists.resize(1);
163  neighborPts.resize(1);
164 
165  if (!nnGlobal.nn_single_search(
166  {lx, ly, lz}, // Look closest to this guy
167  neighborPts[0], neighborSqrDists[0],
168  neighborIndices[0]))
169  {
170  neighborIndices.clear();
171  neighborSqrDists.clear();
172  neighborPts.clear();
173  }
174  }
175  else
176  {
177  // Use nn_radius_search() which provides a maximum search
178  // distance:
179  nnGlobal.nn_radius_search(
180  {lx, ly, lz}, // Look closest to this guy
181  maxDistForCorrespondenceSquared, neighborPts,
182  neighborSqrDists, neighborIndices, pairingsPerPoint);
183  }
184 
185  // Distance below the threshold??
186  for (size_t k = 0; k < neighborIndices.size(); k++)
187  {
188  const auto tentativeErrSqr = neighborSqrDists.at(k);
189 
190  const float finalThresSqr =
191  maxDistForCorrespondenceSquared +
192  angularThresholdFactorSquared * localNormSqr;
193 
194  if (tentativeErrSqr >= finalThresSqr)
195  break; // skip this and the rest.
196 
197  lambdaAddPair(
198  res, localIdx, neighborPts.at(k), neighborIndices.at(k),
199  tentativeErrSqr);
200  }
201  }
202  return res;
203  },
204  // 2nd lambda: Parallel reduction
205  [](Result a, const Result& b) -> Result
206  {
207  a.insert(
208  a.end(), std::make_move_iterator(b.begin()),
209  std::make_move_iterator(b.end()));
210  return a;
211  });
212 
213  out.paired_pt2pt.insert(
214  out.paired_pt2pt.end(), std::make_move_iterator(newPairs.begin()),
215  std::make_move_iterator(newPairs.end()));
216 #else
217 
218  out.paired_pt2pt.reserve(nLocalPts);
219 
220  std::vector<uint64_t> neighborIndices;
221  std::vector<float> neighborSqrDists;
222  std::vector<mrpt::math::TPoint3Df> neighborPts;
223 
224  for (size_t i = 0; i < nLocalPts; i++)
225  {
226  const size_t localIdx = tl.idxs.has_value() ? (*tl.idxs)[i] : i;
227 
229  ms.localPairedBitField.point_layers.at(localName)[localIdx])
230  continue; // skip, already paired.
231 
232  // For speed-up:
233  const float lx = tl.x_locals[i], ly = tl.y_locals[i],
234  lz = tl.z_locals[i];
235 
236  const float localNormSqr =
237  mrpt::square(lx) + mrpt::square(ly) + mrpt::square(lz);
238 
239  // Use a KD-tree to look for the nearnest neighbor(s) of
240  // (x_local, y_local, z_local) in the global map.
241  if (pairingsPerPoint == 1)
242  {
243  neighborIndices.resize(1);
244  neighborSqrDists.resize(1);
245  neighborPts.resize(1);
246 
247  if (!nnGlobal.nn_single_search(
248  {lx, ly, lz}, // Look closest to this guy
249  neighborPts[0], neighborSqrDists[0], neighborIndices[0]))
250  {
251  neighborIndices.clear();
252  neighborSqrDists.clear();
253  neighborPts.clear();
254  }
255  }
256  else
257  {
258  nnGlobal.nn_multiple_search(
259  {lx, ly, lz}, // Look closest to this guy
260  pairingsPerPoint, neighborPts, neighborSqrDists,
261  neighborIndices);
262  }
263 
264  // Distance below the threshold??
265  for (size_t k = 0; k < neighborIndices.size(); k++)
266  {
267  const auto tentativeErrSqr = neighborSqrDists.at(k);
268 
269  const float finalThresSqr =
270  maxDistForCorrespondenceSquared +
271  angularThresholdFactorSquared * localNormSqr;
272 
273  if (tentativeErrSqr >= finalThresSqr)
274  break; // skip this and the rest.
275 
276  lambdaAddPair(
277  out.paired_pt2pt, localIdx, neighborPts.at(k),
278  neighborIndices.at(k), tentativeErrSqr);
279  }
280  }
281 #endif
282 
283  MRPT_END
284 }
mp2p_icp::Matcher_Points_DistanceThreshold::initialize
void initialize(const mrpt::containers::yaml &params) override
Definition: Matcher_Points_DistanceThreshold.cpp:33
mp2p_icp::Parameterizable::checkAllParametersAreRealized
void checkAllParametersAreRealized() const
Definition: Parameterizable.cpp:138
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
Definition: Matcher.h:73
DECLARE_PARAMETER_OPT
#define DECLARE_PARAMETER_OPT(__yaml, __variable)
Definition: Parameterizable.h:164
mp2p_icp::Matcher_Points_Base::TransformedLocalPointCloud::y_locals
mrpt::aligned_std_vector< float > y_locals
Definition: Matcher_Points_Base.h:100
test.res
res
Definition: test.py:11
mp2p_icp::Matcher_Points_Base::allowMatchAlreadyMatchedGlobalPoints_
bool allowMatchAlreadyMatchedGlobalPoints_
Definition: Matcher_Points_Base.h:56
mp2p_icp::Pairings
Definition: Pairings.h:78
mp2p_icp::layer_name_t
std::string layer_name_t
Definition: layer_name_t.h:22
mp2p_icp::Matcher_Points_Base::allowMatchAlreadyMatchedPoints_
bool allowMatchAlreadyMatchedPoints_
Definition: Matcher_Points_Base.h:52
mp2p_icp::Matcher_Points_DistanceThreshold::Matcher_Points_DistanceThreshold
Matcher_Points_DistanceThreshold()
Definition: Matcher_Points_DistanceThreshold.cpp:27
mp2p_icp::Matcher_Points_DistanceThreshold::pairingsPerPoint
uint32_t pairingsPerPoint
Definition: Matcher_Points_DistanceThreshold.h:55
mp2p_icp::Matcher_Points_DistanceThreshold::thresholdAngularDeg
double thresholdAngularDeg
Definition: Matcher_Points_DistanceThreshold.h:54
DECLARE_PARAMETER_REQ
#define DECLARE_PARAMETER_REQ(__yaml, __variable)
Definition: Parameterizable.h:175
mp2p_icp::Matcher_Points_DistanceThreshold
Definition: Matcher_Points_DistanceThreshold.h:30
mp2p_icp::Matcher_Points_DistanceThreshold::threshold
double threshold
Definition: Matcher_Points_DistanceThreshold.h:53
mp2p_icp::Matcher_Points_Base::TransformedLocalPointCloud::idxs
std::optional< std::vector< std::size_t > > idxs
Definition: Matcher_Points_Base.h:97
mp2p_icp::Matcher_Points_DistanceThreshold::implMatchOneLayer
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 override
Definition: Matcher_Points_DistanceThreshold.cpp:43
mp2p_icp::Matcher_Points_Base::initialize
void initialize(const mrpt::containers::yaml &params) override
Definition: Matcher_Points_Base.cpp:120
mp2p_icp::Matcher_Points_Base::TransformedLocalPointCloud::z_locals
mrpt::aligned_std_vector< float > z_locals
Definition: Matcher_Points_Base.h:100
mp2p_icp::MatchState
Definition: Matcher.h:37
kitti-batch-convert.out
string out
Definition: kitti-batch-convert.py:7
Matcher_Points_DistanceThreshold.h
Pointcloud matcher: fixed distance thresholds.
mp2p_icp::Matcher_Points_Base::localPointsSampleSeed_
uint64_t localPointsSampleSeed_
Definition: Matcher_Points_Base.h:48
IMPLEMENTS_MRPT_OBJECT
IMPLEMENTS_MRPT_OBJECT(QualityEvaluator_RangeImageSimilarity, QualityEvaluator, mp2p_icp) using namespace mp2p_icp
mp2p_icp::MatchState::globalPairedBitField
pointcloud_bitfield_t globalPairedBitField
Like localPairedBitField for the global map.
Definition: Matcher.h:50
mp2p_icp::pointcloud_bitfield_t::point_layers
std::map< layer_name_t, DenseOrSparseBitField > point_layers
Definition: pointcloud_bitfield.h:82
mp2p_icp::Matcher_Points_Base::maxLocalPointsPerLayer_
uint64_t maxLocalPointsPerLayer_
Definition: Matcher_Points_Base.h:47
mp2p_icp::MatchState::localPairedBitField
pointcloud_bitfield_t localPairedBitField
Definition: Matcher.h:47
mp2p_icp::MapToNN
const mrpt::maps::NearestNeighborsCapable * MapToNN(const mrpt::maps::CMetricMap &map, bool throwIfNotImplemented)
Definition: metricmap.cpp:686
mp2p_icp::Matcher_Points_Base::TransformedLocalPointCloud::x_locals
mrpt::aligned_std_vector< float > x_locals
Definition: Matcher_Points_Base.h:100
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
Author(s):
autogenerated on Thu Dec 26 2024 03:48:12