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


mp2p_icp
Author(s):
autogenerated on Thu Oct 17 2024 02:45:33