From 3e50ed76c42da225004df41b21d282df1864c602 Mon Sep 17 00:00:00 2001 From: Bradley J Chambers Date: Mon, 12 Jun 2017 11:55:01 -0400 Subject: [PATCH] Add VoxelCenterNearestNeighborFilter and VoxelCentroidNearestNeighborFilter For each populated voxel, use the coordinates of the voxel center or centroid respectively to find the nearest neighbor in the input PointView and append it to the output PointView. --- .../filters.voxelcenternearestneighbor.rst | 49 ++++++++ .../filters.voxelcentroidnearestneighbor.rst | 47 ++++++++ filters/VoxelCenterNearestNeighborFilter.cpp | 107 ++++++++++++++++++ filters/VoxelCenterNearestNeighborFilter.hpp | 75 ++++++++++++ .../VoxelCentroidNearestNeighborFilter.cpp | 107 ++++++++++++++++++ .../VoxelCentroidNearestNeighborFilter.hpp | 75 ++++++++++++ pdal/StageFactory.cpp | 4 + 7 files changed, 464 insertions(+) create mode 100644 doc/stages/filters.voxelcenternearestneighbor.rst create mode 100644 doc/stages/filters.voxelcentroidnearestneighbor.rst create mode 100644 filters/VoxelCenterNearestNeighborFilter.cpp create mode 100644 filters/VoxelCenterNearestNeighborFilter.hpp create mode 100644 filters/VoxelCentroidNearestNeighborFilter.cpp create mode 100644 filters/VoxelCentroidNearestNeighborFilter.hpp diff --git a/doc/stages/filters.voxelcenternearestneighbor.rst b/doc/stages/filters.voxelcenternearestneighbor.rst new file mode 100644 index 0000000000..c33751be5f --- /dev/null +++ b/doc/stages/filters.voxelcenternearestneighbor.rst @@ -0,0 +1,49 @@ +.. _filters.voxelcenternearestneighbor: + +=============================================================================== +filters.voxelcenternearestneighbor +=============================================================================== + +VoxelCenterNearestNeighbor is a voxel-based sampling filter. The input point +cloud is divided into 3D voxels at the given cell size. For each populated +voxel, the coordinates of the voxel center are used as the query point in a 3D +nearest neighbor search. The nearest neighbor is then added to the output point +cloud, along with any existing dimensions. + +.. note:: + + This is similar to the existing :ref:`filters.voxelgrid`. However, in the + case of the VoxelGrid, the centroid of the points falling within the voxel + is added to the output point cloud. The drawback with this approach is that + all dimensional data is lost, and the sampled cloud now consists of only XYZ + coordinates. + +Example +------- + + +.. code-block:: json + + { + "pipeline":[ + "input.las", + { + "type":"filters.voxelcenternearestneighbor", + "cell":10.0 + }, + "output.las" + ] + } + + +.. seealso:: + + :ref:`filters.voxelcentroidnearestneighbor` offers a similar solution, using + as the query point the centroid of all points falling within the voxel as + opposed to the voxel center coordinates. + +Options +------------------------------------------------------------------------------- + +cell + Cell size in the X, Y, and Z dimension. [Default: **1.0**] diff --git a/doc/stages/filters.voxelcentroidnearestneighbor.rst b/doc/stages/filters.voxelcentroidnearestneighbor.rst new file mode 100644 index 0000000000..21c4c906c7 --- /dev/null +++ b/doc/stages/filters.voxelcentroidnearestneighbor.rst @@ -0,0 +1,47 @@ +.. _filters.voxelcentroidnearestneighbor: + +=============================================================================== +filters.voxelcentroidnearestneighbor +=============================================================================== + +VoxelCentroidNearestNeighbor is a voxel-based sampling filter. The input point +cloud is divided into 3D voxels at the given cell size. For each populated +voxel, the centroid of the points within that voxel is computed. This centroid +is used as the query point in a 3D nearest neighbor search. The nearest neighbor +is then added to the output point cloud, along with any existing dimensions. + +.. note:: + + This is similar to the existing :ref:`filters.voxelgrid`. However, in the + case of the VoxelGrid, the centroid itself is added to the output point + cloud. The drawback with this approach is that all dimensional data is lost, + and the sampled cloud now consists of only XYZ coordinates. + +Example +------- + + +.. code-block:: json + + { + "pipeline":[ + "input.las", + { + "type":"filters.voxelcentroidnearestneighbor", + "cell":10.0 + }, + "output.las" + ] + } + + +.. seealso:: + + :ref:`filters.voxelcenternearestneighbor` offers a similar solution, using + the voxel center as opposed to the voxel centroid for the query point. + +Options +------------------------------------------------------------------------------- + +cell + Cell size in the X, Y, and Z dimension. [Default: **1.0**] diff --git a/filters/VoxelCenterNearestNeighborFilter.cpp b/filters/VoxelCenterNearestNeighborFilter.cpp new file mode 100644 index 0000000000..baa39038cd --- /dev/null +++ b/filters/VoxelCenterNearestNeighborFilter.cpp @@ -0,0 +1,107 @@ +/****************************************************************************** + * Copyright (c) 2017, Bradley J Chambers (brad.chambers@gmail.com) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + ****************************************************************************/ + +#include "VoxelCenterNearestNeighborFilter.hpp" + +#include +#include + +#include +#include +#include +#include + +namespace pdal +{ + +static PluginInfo const s_info = + PluginInfo("filters.voxelcenternearestneighbor", + "Voxel Center Nearest Neighbor Filter", + "http://pdal.io/stages/filters.voxelcenternearestneighbor.html"); + +CREATE_STATIC_PLUGIN(1, 0, VoxelCenterNearestNeighborFilter, Filter, s_info) + +std::string VoxelCenterNearestNeighborFilter::getName() const +{ + return s_info.name; +} + +void VoxelCenterNearestNeighborFilter::addArgs(ProgramArgs& args) +{ + args.add("cell", "Cell size", m_cell, 1.0); +} + +PointViewSet VoxelCenterNearestNeighborFilter::run(PointViewPtr view) +{ + BOX3D bounds; + view->calculateBounds(bounds); + + KD3Index kdi(*view); + kdi.build(); + + // Make an initial pass through the input PointView to detect populated + // voxels. + std::set> populated_voxels; + for (PointId id = 0; id < view->size(); ++id) + { + double y = view->getFieldAs(Dimension::Id::Y, id); + double x = view->getFieldAs(Dimension::Id::X, id); + double z = view->getFieldAs(Dimension::Id::Z, id); + size_t r = static_cast(floor(y - bounds.miny) / m_cell); + size_t c = static_cast(floor(x - bounds.minx) / m_cell); + size_t d = static_cast(floor(z - bounds.minz) / m_cell); + populated_voxels.emplace(std::make_tuple(r, c, d)); + } + + // Make a second pass through the populated voxels to find the nearest + // neighbor to each voxel center. + PointViewPtr output = view->makeNew(); + for (auto const& t : populated_voxels) + { + auto& r = std::get<0>(t); + auto& c = std::get<1>(t); + auto& d = std::get<2>(t); + double y = bounds.miny + (r + 0.5) * m_cell; + double x = bounds.minx + (c + 0.5) * m_cell; + double z = bounds.minz + (d + 0.5) * m_cell; + std::vector neighbors = kdi.neighbors(x, y, z, 1); + output->appendPoint(*view, neighbors[0]); + } + + PointViewSet viewSet; + viewSet.insert(output); + return viewSet; +} + +} // namespace pdal diff --git a/filters/VoxelCenterNearestNeighborFilter.hpp b/filters/VoxelCenterNearestNeighborFilter.hpp new file mode 100644 index 0000000000..4d93f8c7a3 --- /dev/null +++ b/filters/VoxelCenterNearestNeighborFilter.hpp @@ -0,0 +1,75 @@ +/****************************************************************************** + * Copyright (c) 2017, Bradley J Chambers (brad.chambers@gmail.com) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + ****************************************************************************/ + +#pragma once + +#include +#include + +#include +#include + +extern "C" int32_t VoxelCenterNearestNeighborFilter_ExitFunc(); +extern "C" PF_ExitFunc VoxelCenterNearestNeighborFilter_InitPlugin(); + +namespace pdal +{ + +class PointLayout; +class PointView; + +class PDAL_DLL VoxelCenterNearestNeighborFilter : public Filter +{ +public: + VoxelCenterNearestNeighborFilter() : Filter() + { + } + + static void* create(); + static int32_t destroy(void*); + std::string getName() const; + +private: + double m_cell; + + virtual void addArgs(ProgramArgs& args); + virtual PointViewSet run(PointViewPtr view); + + VoxelCenterNearestNeighborFilter& + operator=(const VoxelCenterNearestNeighborFilter&); // not implemented + VoxelCenterNearestNeighborFilter( + const VoxelCenterNearestNeighborFilter&); // not implemented +}; + +} // namespace pdal diff --git a/filters/VoxelCentroidNearestNeighborFilter.cpp b/filters/VoxelCentroidNearestNeighborFilter.cpp new file mode 100644 index 0000000000..e8ce1564e0 --- /dev/null +++ b/filters/VoxelCentroidNearestNeighborFilter.cpp @@ -0,0 +1,107 @@ +/****************************************************************************** + * Copyright (c) 2017, Bradley J Chambers (brad.chambers@gmail.com) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + ****************************************************************************/ + +#include "VoxelCentroidNearestNeighborFilter.hpp" + +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace pdal +{ + +static PluginInfo const s_info = PluginInfo( + "filters.voxelcentroidnearestneighbor", + "Voxel Centroid Nearest Neighbor Filter", + "http://pdal.io/stages/filters.voxelcentroidnearestneighbor.html"); + +CREATE_STATIC_PLUGIN(1, 0, VoxelCentroidNearestNeighborFilter, Filter, s_info) + +std::string VoxelCentroidNearestNeighborFilter::getName() const +{ + return s_info.name; +} + +void VoxelCentroidNearestNeighborFilter::addArgs(ProgramArgs& args) +{ + args.add("cell", "Cell size", m_cell, 1.0); +} + +PointViewSet VoxelCentroidNearestNeighborFilter::run(PointViewPtr view) +{ + BOX3D bounds; + view->calculateBounds(bounds); + + KD3Index kdi(*view); + kdi.build(); + + // Make an initial pass through the input PointView to index PointIds by + // row, column, and depth. + std::map, std::vector> + populated_voxel_ids; + for (PointId id = 0; id < view->size(); ++id) + { + double y = view->getFieldAs(Dimension::Id::Y, id); + double x = view->getFieldAs(Dimension::Id::X, id); + double z = view->getFieldAs(Dimension::Id::Z, id); + size_t r = static_cast(floor(y - bounds.miny) / m_cell); + size_t c = static_cast(floor(x - bounds.minx) / m_cell); + size_t d = static_cast(floor(z - bounds.minz) / m_cell); + populated_voxel_ids[std::make_tuple(r, c, d)].push_back(id); + } + + // Make a second pass through the populated voxels to compute the voxel + // centroid and to find its nearest neighbor. + PointViewPtr output = view->makeNew(); + for (auto const& t : populated_voxel_ids) + { + Eigen::Vector3f centroid = eigen::computeCentroid(*view, t.second); + std::vector neighbors = + kdi.neighbors(centroid[0], centroid[1], centroid[2], 1); + output->appendPoint(*view, neighbors[0]); + } + + PointViewSet viewSet; + viewSet.insert(output); + return viewSet; +} + +} // namespace pdal diff --git a/filters/VoxelCentroidNearestNeighborFilter.hpp b/filters/VoxelCentroidNearestNeighborFilter.hpp new file mode 100644 index 0000000000..49cb949b50 --- /dev/null +++ b/filters/VoxelCentroidNearestNeighborFilter.hpp @@ -0,0 +1,75 @@ +/****************************************************************************** + * Copyright (c) 2017, Bradley J Chambers (brad.chambers@gmail.com) + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following + * conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + ****************************************************************************/ + +#pragma once + +#include +#include + +#include +#include + +extern "C" int32_t VoxelCentroidNearestNeighborFilter_ExitFunc(); +extern "C" PF_ExitFunc VoxelCentroidNearestNeighborFilter_InitPlugin(); + +namespace pdal +{ + +class PointLayout; +class PointView; + +class PDAL_DLL VoxelCentroidNearestNeighborFilter : public Filter +{ +public: + VoxelCentroidNearestNeighborFilter() : Filter() + { + } + + static void* create(); + static int32_t destroy(void*); + std::string getName() const; + +private: + double m_cell; + + virtual void addArgs(ProgramArgs& args); + virtual PointViewSet run(PointViewPtr view); + + VoxelCentroidNearestNeighborFilter& + operator=(const VoxelCentroidNearestNeighborFilter&); // not implemented + VoxelCentroidNearestNeighborFilter( + const VoxelCentroidNearestNeighborFilter&); // not implemented +}; + +} // namespace pdal diff --git a/pdal/StageFactory.cpp b/pdal/StageFactory.cpp index d01dc9dc40..c76da30174 100644 --- a/pdal/StageFactory.cpp +++ b/pdal/StageFactory.cpp @@ -74,6 +74,8 @@ #include #include #include +#include +#include // readers #include @@ -277,6 +279,8 @@ StageFactory::StageFactory(bool no_plugins) PluginManager::initializePlugin(SplitterFilter_InitPlugin); PluginManager::initializePlugin(StatsFilter_InitPlugin); PluginManager::initializePlugin(TransformationFilter_InitPlugin); + PluginManager::initializePlugin(VoxelCenterNearestNeighborFilter_InitPlugin); + PluginManager::initializePlugin(VoxelCentroidNearestNeighborFilter_InitPlugin); // readers PluginManager::initializePlugin(BpfReader_InitPlugin);