Near-neighbor Point Cloud Downsampling/Decimation

194 views Asked by At

I'm looking for a way to downsample a point cloud based on the proximity of points to their neighbors (from what I can tell, this is synonymous with "decimation"). While I am currently using PyVista as my main library, I'm not seeing any class/methods that seem to achieve what I am looking for since the decimate method that does belong to the PolyDataFilter class is only for points that have been meshed (and I want to decimate my point cloud before meshing).

Without developing my own method from scratch, how can I achieve this decimation?

1

There are 1 answers

2
Bane Sullivan On

PyVista developer here ;)

I think you may want to try the clean() filter in PyVista (sort of only available for PolyData types -- which your point cloud would be). We actually have a snippet of code internal to the glyph() filter that demonstrates this when needing to downslample points in this fashion for glyphing many geometries as a representative sample of large vector field. The example in our docs demonstrates this with a toy data set. But you aren't glyphing! So below is a snippet that hopefully works for your use case. The key here is going to be the merge_tol argument for determining proximity. Please refer to our active documentation for using this.

import pyvista as pv
import numpy as np

source_points = np.random.rand(10_000, 3)
dense = pv.PolyData(source_points)

# Recomend reading PyVista's docs on how to use this parameter
# the gist: tolerance is in terms of fraction of bounding box diagonal length (0-1)
tolerance = 0.05

# This can take some time for large point clouds
small = dense.clean(
    point_merging=True,
    merge_tol=tolerance,
    lines_to_points=False,
    polys_to_lines=False,
    strips_to_polys=False,
    inplace=False,
    absolute=False,
    progress_bar=True,  # eh, not sure why its non-interactive
)

Then plot it of course, cuz this is PyVista!

pl = pv.Plotter(shape=(1, 2))
pl.add_mesh(dense, render_points_as_spheres=True)
pl.subplot(0, 1)
pl.add_mesh(small, render_points_as_spheres=True)
pl.link_views()
pl.view_isometric()
pl.show()

comparison of dense and downsampled point clouds

from what I can tell, this is synonymous with "decimation"

Hm, the terminology here is definitely confusing. In PyVista, decimation is currently reserved for reducing the number of triangles in a mesh. I think "downsampling" is the best term for this and agree that it is not obvious the "clean" filter would be what you need (PRs for improving our documentation are always welcome)