16 #include <mrpt/containers/yaml.h>
17 #include <mrpt/math/ops_containers.h>
18 #include <mrpt/random/RandomGenerators.h>
21 #include <mrpt/maps/CPointsMapXYZI.h>
22 #include <mrpt/maps/CPointsMapXYZIRT.h>
32 c.has(
"input_pointcloud_layer"),
33 "YAML configuration must have an entry `input_pointcloud_layer` with a "
34 "scalar or sequence.");
38 auto cfgIn = c[
"input_pointcloud_layer"];
47 "YAML configuration must have an entry `input_pointcloud_layer` "
48 "with a scalar or sequence.");
50 for (
const auto&
s : cfgIn.asSequence())
63 if (c.has(
"flatten_to"))
flatten_to = c[
"flatten_to"].as<
double>();
68 mrpt::system::COutputLogger::setLoggerName(
"FilterDecimateVoxels");
75 MRPT_LOG_DEBUG_STREAM(
"Loading these params:\n" << c);
100 std::vector<mrpt::maps::CPointsMap*> pcPtrs;
101 size_t reserveSize = 0;
104 if (
auto itLy = inOut.
layers.find(inputLayer); itLy != inOut.
layers.end())
108 THROW_EXCEPTION_FMT(
"Layer '%s' must be of point cloud type.", inputLayer.c_str());
110 pcPtrs.push_back(pcPtr);
111 reserveSize += pcPtr->size() / 10;
118 THROW_EXCEPTION_FMT(
"Input layer '%s' not found on input map.", inputLayer.c_str());
128 ASSERT_(!pcPtrs.empty());
139 pcPtrs.at(0)->GetRuntimeClass()->className);
141 outPc->reserve(outPc->size() + reserveSize);
147 std::vector<size_t> idxsToRemove;
148 for (
size_t mapIdx = 0; mapIdx < pcPtrs.size(); mapIdx++)
156 idxsToRemove.push_back(mapIdx);
158 const auto& xs = pcPtrs[mapIdx]->getPointsBufferRef_x();
159 const auto& ys = pcPtrs[mapIdx]->getPointsBufferRef_y();
161 for (
size_t i = 0; i < xs.size(); i++)
168 outPc->insertPointFrom(*pcPtrs[mapIdx], i);
171 for (
auto it = idxsToRemove.rbegin(); it != idxsToRemove.rend(); ++it)
172 pcPtrs.erase(pcPtrs.begin() + *it);
177 size_t nonEmptyVoxels = 0;
183 "Has you called initialize() after updating/loading parameters?");
190 for (
const auto& pcPtr : pcPtrs)
192 const auto& pc = *pcPtr;
193 grid.processPointCloud(pc);
196 ASSERT_(sanityPassed);
200 std::set<PointCloudToVoxelGridSingle::indices_t, PointCloudToVoxelGridSingle::IndicesHash>
207 if (!vxl.
pointIdx.has_value())
return;
213 const PointCloudToVoxelGridSingle::indices_t flattenIdx = {idx.cx_, idx.cy_, 0};
216 if (flattenUsedBins.count(flattenIdx) != 0)
return;
219 flattenUsedBins.insert(flattenIdx);
233 "Only one input layer allowed when requiring the non-single "
236 const auto& pc = *pcPtrs.at(0);
240 "Has you called initialize() after updating/loading parameters?");
246 grid.processPointCloud(pc);
248 const auto& xs = pc.getPointsBufferRef_x();
249 const auto& ys = pc.getPointsBufferRef_y();
250 const auto& zs = pc.getPointsBufferRef_z();
252 auto rng = mrpt::random::CRandomGenerator();
255 std::set<PointCloudToVoxelGrid::indices_t, PointCloudToVoxelGrid::IndicesHash>
262 if (vxl.
indices.empty())
return;
265 std::optional<mrpt::math::TPoint3Df> insertPt;
272 auto mean = mrpt::math::TPoint3Df(0, 0, 0);
273 const float inv_n = (1.0f / vxl.indices.size());
274 for (size_t i = 0; i < vxl.indices.size(); i++)
276 const auto pt_idx = vxl.indices[i];
277 mean.x += xs[pt_idx];
278 mean.y += ys[pt_idx];
279 mean.z += zs[pt_idx];
285 std::optional<float> minSqrErr;
286 std::optional<size_t> bestIdx;
288 for (size_t i = 0; i < vxl.indices.size(); i++)
290 const auto pt_idx = vxl.indices[i];
291 const float sqrErr = mrpt::square(xs[pt_idx] - mean.x) +
292 mrpt::square(ys[pt_idx] - mean.y) +
293 mrpt::square(zs[pt_idx] - mean.z);
295 if (!minSqrErr.has_value() || sqrErr < *minSqrErr)
302 insertPtIdx = *bestIdx;
307 insertPt = {mean.x, mean.y, mean.z};
314 ? (rng.drawUniform64bit() % vxl.
indices.size())
317 const auto pt_idx = vxl.
indices.at(idxInVoxel);
318 insertPtIdx = pt_idx;
327 if (flattenUsedBins.count(flattenIdx) != 0)
return;
330 flattenUsedBins.insert(flattenIdx);
333 insertPt.emplace(xs[insertPtIdx], ys[insertPtIdx], zs[insertPtIdx]);
339 outPc->insertPointFast(insertPt->x, insertPt->y, insertPt->z);
342 outPc->insertPointFrom(pc, insertPtIdx);
349 outPc->mark_as_modified();
351 MRPT_LOG_DEBUG_STREAM(
352 "Voxel count=" << nonEmptyVoxels <<
", output_layer=" << params_.output_pointcloud_layer
353 <<
" type=" << outPc->GetRuntimeClass()->className
354 <<
" useSingleGrid=" << (useSingleGrid() ?
"Yes" :
"No"));