Skip to content

Filter Point Cloud Using Voxel Downsampling

SUMMARY

Filter Point Cloud Using Voxel Downsampling shrinks a point cloud by averaging every point that falls inside the same cubic voxel down to a single centroid.

It divides 3D space into a grid of cubic voxels of edge length voxel_size and replaces every point that falls inside the same voxel with one point at their centroid. Unlike filter_point_cloud_using_uniform_downsampling (which just skips points by index), this accounts for actual spatial density — dense regions get thinned out proportionally more than sparse ones — producing a roughly evenly-spaced result.

Use this Skill when you want to reduce point count while keeping a spatially uniform, evenly-spaced cloud, regardless of how the input's density varied.

The Skill

python
from telekinesis import vitreous

filtered_point_cloud = vitreous.filter_point_cloud_using_voxel_downsampling(
    point_cloud=point_cloud,
    voxel_size=0.005,
)
API Reference
Full parameter and return type documentation for filter_point_cloud_using_voxel_downsampling.
View Reference →

Data Transfer Notice

There is no longer a fixed limit of 1 million points per request. However, very large datasets may result in slower data transfer and processing times. We are continuously optimizing performance as part of our beta program, with ongoing improvements to enhance speed and reliability.

Example

Raw Sensor Input

Unprocessed point cloud captured directly from the sensor. Shows full resolution, natural noise, and uneven sampling density.

Mild Downsampling

Light voxel-based reduction that removes redundant samples while preserving nearly all fine geometric detail.
Parameters: voxel_size = 0.005 (scene units).

Moderate Downsampling

Balanced simplification that reduces noise and point density while maintaining overall shape and structure.
Parameters: voxel_size = 0.01 (scene units).

Aggressive Downsampling

Heavy simplification that merges fine structures and retains only coarse geometry, ideal for performance-oriented processing.
Parameters: voxel_size = 0.025 (scene units).

The Code

python
"""
Demonstrates downsampling a point cloud using voxel grid averaging.
"""

from loguru import logger
import rerun as rr

from telekinesis import vitreous, datatypes


def filter_point_cloud_using_voxel_downsampling_example():
    """
    Downsamples a point cloud using voxel grid averaging.

    Divides 3D space into voxels and replaces all points within each voxel
    with their centroid.
    """
    # ===================== Load Data ==========================================
    point_cloud_url = "https://assets.telekinesis.ai/examples/v1/point_clouds/can_vertical_1_subtracted.ply"
    point_cloud = datatypes.PointCloud.from_url(url=point_cloud_url, use_cache=True)

    # ===================== Run Skill ==========================================
    filtered_point_cloud = vitreous.filter_point_cloud_using_voxel_downsampling(
        voxel_size=0.005, point_cloud=point_cloud
    )

    # ===================== Log ================================================
    logger.success(f"Filtered {point_cloud} using voxel downsampling")
    logger.success(f"Results: {filtered_point_cloud}")
    logger.info(
        f"Filtered point cloud positions shape: {filtered_point_cloud.positions.shape}"
    )
    logger.info(
        f"Filtered point cloud has normals shape: "
        f"{filtered_point_cloud.normals.shape if filtered_point_cloud.has_normals else None}"
    )
    logger.info(
        f"Filtered point cloud has colors shape: "
        f"{filtered_point_cloud.colors.shape if filtered_point_cloud.has_colors else None}"
    )

    # ===================== Visualization  (Optional) ===========================
    rr.init("filter_point_cloud_using_voxel_downsampling_example", spawn=True)
    datatypes.visualize(point_cloud, entity_path="/1-input_point_cloud")
    datatypes.visualize(filtered_point_cloud, entity_path="/2-filtered_point_cloud")


if __name__ == "__main__":
    filter_point_cloud_using_voxel_downsampling_example()

Runnable examples are available in the Telekinesis examples repository.

Follow the README in that repository to set up the environment, run this specific example with:

bash
cd telekinesis-examples
python examples/point_cloud/filter_point_cloud_using_voxel_downsampling.py

Parameter Configuration

KeyTypeDefaultDescription
point_clouddatatypes.PointCloudrequiredThe point cloud to downsample
voxel_sizedatatypes.Float | float | intrequiredThe edge length of each cubic voxel, in meters

Returns

TypeDescription
datatypes.PointCloudA point cloud with one point per occupied voxel, each the centroid of the original points inside it. Use .positions for the downsampled (N, 3) position array and len(...) for the point count.

Raises

ExceptionCondition
TypeErrorA parameter's value does not match its expected type (see the Parameter Configuration table above)
ConfigurationErrorThe TELEKINESIS_API_KEY environment variable is not set
SerializationErrorThe request input failed to serialize, or the response failed to deserialize
RequestTimeoutErrorThe request to the Vitreous service timed out
TransportErrorA network failure occurred before a response was received
ClientErrorThe Vitreous service rejected the request due to invalid input, invalid data, or another unexpected 4xx response
AuthenticationErrorThe API key was rejected as invalid or expired
AuthenticationServiceErrorThe authentication service was unavailable
ServerErrorThe Vitreous service returned a 5xx or otherwise unexpected error response

How to Tune the Parameters

The filter_point_cloud_using_voxel_downsampling Skill exposes one parameter that controls the size of the voxel grid points are bucketed into.

voxel_size

  • Controls: The edge length of each cubic voxel; all points inside a voxel are replaced by their centroid.
  • Units: Meters
  • Default: required — no default
  • Increase → larger voxels, more aggressive downsampling, fewer output points
  • Decrease → smaller voxels, more detail preserved, more points
  • Set it to roughly 2–5x the typical point spacing for a balanced result
  • Typical range: 0.001–0.1 meters for small objects, 0.01–0.5 for medium scenes, 0.1–1.0 for large scenes — use the smaller end (0.001–0.01) to preserve fine detail, the larger end (0.05–0.1) for aggressive reduction

TIP

Choose a voxel_size slightly larger than the sensor's noise level, but smaller than the smallest feature you need to preserve — visualizing the result helps you quickly spot the right balance.

Where to Use the Skill

Common pipelines include:

  • Registration preprocessing – downsampling both clouds before register_point_clouds_using_point_to_point_icp for faster, more stable convergence
  • Clustering preprocessing – producing a spatially uniform density before cluster_point_cloud_using_dbscan
  • Segmentation preprocessing – reducing point count before segment_point_cloud_using_plane without biasing dense regions
  • General size reduction – shrinking a large raw scan into a manageable size for any downstream skill

Alternative Skills

Skillvs. Filter Point Cloud Using Voxel Downsampling
filter_point_cloud_using_uniform_downsamplingKeeps every Nth point by index instead of averaging by spatial position — faster, since it never looks at coordinates, but doesn't account for point density and can leave dense and sparse regions just as uneven as the input.

When Not to Use the Skill

Do not use Filter Point Cloud Using Voxel Downsampling when:

  • Small details matter – edges, thin parts, and holes smaller than voxel_size are merged away and cannot be recovered
  • You are doing precision measurement – averaging points into centroids discards the original point positions
  • The cloud is already sparse – further voxelization may remove more structure than intended
  • You only need a cheap, order-preserving thinning – if spatial uniformity doesn't matter, filter_point_cloud_using_uniform_downsampling is faster since it skips the spatial bucketing entirely

WARNING

Voxel downsampling permanently removes detail below the voxel size — the original point positions inside each voxel are not recoverable from the centroid. This is irreversible.