FilterCurvature.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  * ------------------------------------------------------------------------- */
15 #include <mrpt/containers/yaml.h>
16 
17 //#define DEBUG_GL
18 
19 #ifdef DEBUG_GL
20 #include <mrpt/img/color_maps.h>
21 #include <mrpt/opengl/CPointCloudColoured.h>
22 #include <mrpt/opengl/Scene.h>
23 #endif
24 
26 
27 using namespace mp2p_icp_filters;
28 
29 void FilterCurvature::Parameters::load_from_yaml(const mrpt::containers::yaml& c)
30 {
31  MCP_LOAD_REQ(c, input_pointcloud_layer);
32 
33  MCP_LOAD_REQ(c, max_cosine);
34  MCP_LOAD_REQ(c, min_clearance);
35  MCP_LOAD_REQ(c, max_gap);
36 
37  MCP_LOAD_OPT(c, output_layer_larger_curvature);
38  MCP_LOAD_OPT(c, output_layer_smaller_curvature);
39  MCP_LOAD_OPT(c, output_layer_other);
40 }
41 
43 
44 void FilterCurvature::initialize(const mrpt::containers::yaml& c)
45 {
46  MRPT_LOG_DEBUG_STREAM("Loading these params:\n" << c);
48 }
49 
51 {
52  MRPT_START
53 
54  // In:
55  const auto& pcPtr = inOut.point_layer(params_.input_pointcloud_layer);
56  ASSERTMSG_(
57  pcPtr,
58  mrpt::format(
59  "Input point cloud layer '%s' was not found.", params_.input_pointcloud_layer.c_str()));
60 
61  const auto& pc = *pcPtr;
62 
63  // Outputs:
64  // Create if new: Append to existing layer, if already existed.
65  mrpt::maps::CPointsMap::Ptr outPcLarger = GetOrCreatePointLayer(
67  /*allow empty name for nullptr*/
68  true,
69  /* create cloud of the same type */
70  pcPtr->GetRuntimeClass()->className);
71  if (outPcLarger) outPcLarger->reserve(outPcLarger->size() + pc.size() / 10);
72 
73  mrpt::maps::CPointsMap::Ptr outPcSmaller = GetOrCreatePointLayer(
75  /*allow empty name for nullptr*/
76  true,
77  /* create cloud of the same type */
78  pcPtr->GetRuntimeClass()->className);
79  if (outPcSmaller) outPcSmaller->reserve(outPcSmaller->size() + pc.size() / 10);
80 
81  mrpt::maps::CPointsMap::Ptr outPcOther = GetOrCreatePointLayer(
83  /*allow empty name for nullptr*/
84  true,
85  /* create cloud of the same type */
86  pcPtr->GetRuntimeClass()->className);
87  if (outPcOther) outPcOther->reserve(outPcOther->size() + pc.size() / 10);
88 
89  ASSERTMSG_(
90  outPcLarger || outPcSmaller,
91  "At least one 'output_layer_larger_curvature' or "
92  "'output_layer_smaller_curvature' output layers must be provided.");
93 
94  const auto& xs = pc.getPointsBufferRef_x();
95  const auto& ys = pc.getPointsBufferRef_y();
96  const auto& zs = pc.getPointsBufferRef_z();
97  const auto* ptrRings = pc.getPointsBufferRef_ring();
98  if (!ptrRings || ptrRings->empty())
99  {
100  THROW_EXCEPTION_FMT(
101  "Error: this filter needs the input layer '%s' to has a 'ring' "
102  "point channel.",
104  }
105 
106  const auto& ringPerPt = *ptrRings;
107  ASSERT_EQUAL_(ringPerPt.size(), xs.size());
108 
109  const size_t N = xs.size();
110 
111  const uint16_t nRings = 1 + *std::max_element(ringPerPt.begin(), ringPerPt.end());
112 
113  const auto estimPtsPerRing = N / nRings;
114 
115  MRPT_LOG_DEBUG_STREAM("nRings: " << nRings << " estimPtsPerRing: " << estimPtsPerRing);
116  ASSERT_(nRings > 0 && nRings < 5000 /*something wrong?*/);
117 
118  std::vector<std::vector<size_t>> idxPerRing;
119  idxPerRing.resize(nRings);
120  for (auto& r : idxPerRing) r.reserve(estimPtsPerRing);
121 
122 #ifdef DEBUG_GL
123  auto glPts = mrpt::opengl::CPointCloudColoured::Create();
124  glPts->setPointSize(4.0f);
125  auto glRawPts = mrpt::opengl::CPointCloudColoured::Create();
126  glRawPts->setPointSize(1.0f);
127 #endif
128 
129  for (size_t i = 0; i < N; i++)
130  {
131  auto& trg = idxPerRing.at(ringPerPt[i]);
132 
133 #ifdef DEBUG_GL
134  auto ringId = ringPerPt[i];
135  auto col = mrpt::img::colormap(mrpt::img::cmJET, static_cast<double>(ringId) / nRings);
136  glRawPts->insertPoint({xs[i], ys[i], zs[i], col.R, col.G, col.B});
137 #endif
138 
139  if (!trg.empty())
140  {
141  // filter: minimum distance:
142  auto li = trg.back();
143  const auto lastPt = mrpt::math::TPoint3Df(xs[li], ys[li], zs[li]);
144  const auto pt = mrpt::math::TPoint3Df(xs[i], ys[i], zs[i]);
145  const auto d = pt - lastPt;
146 
147  if (mrpt::max3(std::abs(d.x), std::abs(d.y), std::abs(d.z)) < params_.min_clearance)
148  continue;
149  }
150 
151  // accept the point:
152  trg.push_back(i);
153 
154 #ifdef DEBUG_GL
155  glPts->insertPoint({xs[i], ys[i], zs[i], col.R, col.G, col.B});
156 #endif
157  }
158 
159 #ifdef DEBUG_GL
160  {
161  static int iter = 0;
162  mrpt::opengl::Scene scene;
163  scene.insert(glRawPts);
164  scene.insert(glPts);
165  scene.saveToFile(mrpt::format("debug_curvature_%04i.3Dscene", iter++));
166  }
167 #endif
168 
169  const float maxGapSqr = mrpt::square(params_.max_gap);
170 
171  size_t counterLarger = 0, counterLess = 0;
172 
173  for (size_t ri = 0; ri < nRings; ri++)
174  {
175  const auto& idxs = idxPerRing.at(ri);
176 
177  if (idxs.size() <= 3)
178  {
179  // If we have too few points, just accept them as they are so few we
180  // cannot run the clasification method below.
181  for (size_t idx = 0; idx < idxs.size(); idx++)
182  {
183  const size_t i = idxs[idx];
184  counterLarger++;
185  if (outPcLarger) outPcLarger->insertPointFrom(pc, i);
186  }
187  continue;
188  }
189 
190  // Regular algorithm:
191  for (size_t idx = 0; idx < idxs.size(); idx++)
192  {
193  const size_t im1 = idxs[idx > 0 ? idx - 1 : idxs.size() - 1];
194  const size_t i = idxs[idx];
195  const size_t ip1 = idxs[idx < idxs.size() - 1 ? idx + 1 : 0];
196 
197  const auto pt = mrpt::math::TPoint3Df(xs[i], ys[i], zs[i]);
198  const auto ptm1 = mrpt::math::TPoint3Df(xs[im1], ys[im1], zs[im1]);
199  const auto ptp1 = mrpt::math::TPoint3Df(xs[ip1], ys[ip1], zs[ip1]);
200 
201  if ((pt - ptm1).sqrNorm() > maxGapSqr || (pt - ptp1).sqrNorm() > maxGapSqr)
202  {
203  // count borders as large curvature, if this is the edge
204  // of the discontinuity that is closer to the sensor (assumed to
205  // be close to the origin!)
206  if (pt.sqrNorm() < ptm1.sqrNorm())
207  {
208  counterLarger++;
209  if (outPcLarger) outPcLarger->insertPointFrom(pc, i);
210  }
211  else
212  {
213  if (outPcOther) outPcOther->insertPointFrom(pc, i);
214  }
215  continue;
216  }
217 
218  const auto v1 = (pt - ptm1);
219  const auto v2 = (ptp1 - pt);
220  const auto v1n = v1.norm();
221  const auto v2n = v2.norm();
222 
223  const float score = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
224 
225  if (std::abs(score) < params_.max_cosine * v1n * v2n)
226  {
227  counterLarger++;
228  if (outPcLarger) outPcLarger->insertPointFrom(pc, i);
229  }
230  else
231  {
232  counterLess++;
233  if (outPcSmaller) outPcSmaller->insertPointFrom(pc, i);
234  }
235  }
236  }
237 
238  MRPT_LOG_DEBUG_STREAM(
239  "[FilterCurvature] Raw input points=" << N << " larger_curvature=" << counterLarger
240  << " smaller_curvature=" << counterLess);
241 
242  MRPT_END
243 }
mp2p_icp_filters::FilterCurvature::params_
Parameters params_
Definition: FilterCurvature.h:66
mp2p_icp_filters::FilterCurvature::Parameters::max_gap
float max_gap
Definition: FilterCurvature.h:62
mp2p_icp_filters::FilterCurvature::Parameters::input_pointcloud_layer
std::string input_pointcloud_layer
Definition: FilterCurvature.h:46
mp2p_icp_filters::FilterCurvature
Definition: FilterCurvature.h:30
kitti-run-seq.f
string f
Definition: kitti-run-seq.py:12
mp2p_icp_filters::FilterCurvature::Parameters::load_from_yaml
void load_from_yaml(const mrpt::containers::yaml &c)
Definition: FilterCurvature.cpp:29
mp2p_icp_filters::FilterCurvature::Parameters::output_layer_larger_curvature
std::string output_layer_larger_curvature
Definition: FilterCurvature.h:50
IMPLEMENTS_MRPT_OBJECT
IMPLEMENTS_MRPT_OBJECT(FilterDecimateVoxelsQuadratic, mp2p_icp_filters::FilterBase, mp2p_icp_filters) using namespace mp2p_icp_filters
mp2p_icp_filters::FilterCurvature::Parameters::output_layer_smaller_curvature
std::string output_layer_smaller_curvature
Definition: FilterCurvature.h:54
mp2p_icp_filters::FilterCurvature::Parameters::min_clearance
float min_clearance
Definition: FilterCurvature.h:61
mp2p_icp_filters::FilterCurvature::FilterCurvature
FilterCurvature()
mp2p_icp_filters::FilterBase
Definition: FilterBase.h:46
mp2p_icp_filters::FilterCurvature::filter
void filter(mp2p_icp::metric_map_t &inOut) const override
Definition: FilterCurvature.cpp:50
d
d
mp2p_icp::metric_map_t::point_layer
mrpt::maps::CPointsMap::Ptr point_layer(const layer_name_t &name) const
Definition: metricmap.cpp:607
mp2p_icp_filters::GetOrCreatePointLayer
mrpt::maps::CPointsMap::Ptr GetOrCreatePointLayer(mp2p_icp::metric_map_t &m, const std::string &layerName, bool allowEmptyName=true, const std::string &classForLayerCreation="mrpt::maps::CSimplePointsMap")
Definition: GetOrCreatePointLayer.cpp:15
FilterCurvature.h
Classifies a sorted input point cloud by local curvature.
boost::posix_time
GetOrCreatePointLayer.h
Auxiliary function GetOrCreatePointLayer.
mp2p_icp::metric_map_t
Generic container of pointcloud(s), extracted features and other maps.
Definition: metricmap.h:55
mp2p_icp_filters::FilterCurvature::Parameters::max_cosine
float max_cosine
Definition: FilterCurvature.h:60
mp2p_icp_filters::FilterCurvature::Parameters::output_layer_other
std::string output_layer_other
Definition: FilterCurvature.h:58
mp2p_icp_filters
Definition: FilterAdjustTimestamps.h:19
mp2p_icp_filters::FilterCurvature::initialize
void initialize(const mrpt::containers::yaml &c) override
Definition: FilterCurvature.cpp:44


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