Skip to content

Add NearestToCentroid and NearestToCenter reductions to VoxelDownSample (#6807) - #7560

Open
MostafaFiroozi wants to merge 4 commits into
isl-org:mainfrom
MostafaFiroozi:feature/voxel-downsample-nearest
Open

MostafaFiroozi wants to merge 4 commits into
isl-org:mainfrom
MostafaFiroozi:feature/voxel-downsample-nearest

Conversation

@MostafaFiroozi

Copy link
Copy Markdown

Fixes #6807.

Adds a VoxelReduction enum on PointCloud::VoxelDownSample so callers can pick between the existing centroid averaging and two new keep-a-real-input-point modes:

  • Centroid — the existing behaviour (default), so nothing breaks.
  • NearestToCentroid — after computing the per-voxel centroid, returns the input point closest to it. Attributes are copied through.
  • NearestToCenter — returns the input point closest to the voxel's geometric centre. Attributes are copied through.

These are the same semantics PDAL exposes as VoxelCentroidNearestNeighbor / VoxelCenterNearestNeighbor and that CloudCompare labels "spatial subsampling — nearest to cell centre", so pipelines coming in from those tools now have a direct equivalent.

The main motivation is that Centroid averages colour, normal and covariance across each voxel's contents. That's fine for smoothly-varying attributes but wrong for anything discrete — semantic class IDs, return numbers, colour that encodes a segmentation label. In those cases the two nearest modes preserve a real observation with its original attributes intact.

A few implementation notes:

  • NearestToCenter is single-pass — the voxel centre is trivially known from the voxel index, so tracking the winner folds into the existing binning loop.
  • NearestToCentroid is two-pass because centroids only settle after all points have been binned. To keep pass 2 cheap I cache each point's voxel index during pass 1 so we don't recompute floor((p - min) / voxel_size).
  • reduction defaults to Centroid, so existing call sites are untouched.

Tests added under VoxelDownSampleNearestToCentroid and VoxelDownSampleNearestToCenter covering the asymmetric-cluster case where all three modes emit visibly different points. The existing VoxelDownSample test still passes with the default parameter.

…Sample

Introduce a VoxelReduction enum with three modes:
  - Centroid (default, preserves existing averaging behaviour)
  - NearestToCentroid (returns the input point closest to the per-voxel
    centroid, attributes copied through)
  - NearestToCenter (returns the input point closest to the voxel's
    geometric center, attributes copied through)

Both new modes are non-deforming: every output point is an actual input
point with its original normal, color, and covariance preserved. This
matches PDAL's VoxelCentroidNearestNeighbor and VoxelCenterNearestNeighbor
filters and CloudCompare's Spatial Subsampling.

NearestToCenter tracks the winner in a single pass since the voxel center
is known from the voxel index. NearestToCentroid uses a two-pass approach
(pass 1 computes centroids, pass 2 finds the closest input point) with the
voxel index cached per point to avoid recomputing floor((p - min)/voxel_size).

Fixes isl-org#6807
Expose VoxelReduction as a nested Python enum on PointCloud (Centroid,
NearestToCentroid, NearestToCenter) using pybind11 native_enum, matching
the pattern used by VoxelGrid.VoxelPoolingMode.

Update voxel_down_sample binding with an optional 'reduction' argument
defaulting to VoxelReduction.Centroid. Fix the docstring injector entry
that previously carried a stray 'invert' key not applicable to voxel
downsampling.

Fixes isl-org#6807
Five new tests, co-located with the existing VoxelDownSample test:

- NearestToCentroid: discriminating three-point single-voxel input,
  verifies point B is picked and its color copied through.
- NearestToCenter: same input, verifies point A (equal to voxel center)
  is picked and its color copied through.
- NearestToCenter_MultiVoxel: two voxels with distinct winners; confirms
  per-voxel accounting is not shared across voxels.
- SingletonVoxel_AllModes: one-point-per-voxel degenerate case; all three
  modes must return the input point unchanged with attributes preserved.
- InvalidVoxelSize_AllModes: voxel_size <= 0 must still throw for all
  three reduction modes.

Input positions are chosen so that centroid, voxel center, and averaged
centroid land at distinct points, letting one small cloud exercise all
three modes.

Fixes isl-org#6807
Added under Main / unreleased. References PDAL precedent and cites the
new VoxelReduction enum. Note: PR number to be appended once the PR is
opened.

Fixes isl-org#6807
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add nearest point to voxel centroid/center as reduction option for PointCloud::VoxelDownSample

1 participant