Skip to content

Cluster Point Cloud Based on Density Jump

SUMMARY

Cluster Point Cloud Based on Density Jump segments a point cloud by detecting sharp changes in point density and splitting the cloud at the strongest density discontinuity.

This Skill is particularly useful when objects are closely packed or partially touching, making distance-based clustering unreliable. By analyzing how point density changes along a given axis (or a projected axis), the algorithm can separate objects that are difficult to distinguish using standard clustering methods like DBSCAN.

Use this Skill when you expect clear density transitions in your scene, such as stacked items, layered structures, or objects aligned along a dominant direction, and when traditional clustering struggles to produce clean separations.

The Skill

python
from telekinesis import vitreous

clusters = vitreous.cluster_point_cloud_based_on_density_jump(
    point_cloud=point_cloud,
    projection_axis=[0.0, 0.0, 1.0],
    num_nearest_neighbors=12,
    neighborhood_radius=0.001,
    is_point_cloud_linear=False,
)

API Reference

Performance Note

Current Data Limits: The system currently supports up to 1 million points per request (approximately 16MB of data). We're actively optimizing data transfer performance as part of our beta program, with improvements rolling out regularly to enhance processing speed.

Example

Raw Point Cloud Input

Calculated Clusters

Clusters found based on density change.
Parameters: projection_axis = np.array([0, 0, 1.0]), num_nearest_neighbors=5, neighborhood_radius=0.05.

The Code

python
from telekinesis import vitreous
from datatypes import datatypes, io
import pathlib

# Optional for logging
from loguru import logger

DATA_DIR = pathlib.Path("path/to/telekinesis-data")

# Load point cloud
filepath = str(DATA_DIR / "point_clouds" / "mug_preprocessed.ply")
point_cloud = io.load_point_cloud(filepath=filepath)
logger.success(f"Loaded point cloud with {len(point_cloud.positions)} points")

# Execute operation
clusters = vitreous.cluster_point_cloud_based_on_density_jump(
  point_cloud=point_cloud,
  projection_axis=[0.0, 0.0, 1.0],
  num_nearest_neighbors=12,
  neighborhood_radius=0.001,
  is_point_cloud_linear=False,
)
logger.success(
  "Split point cloud based on density jump"
)

The Explanation of the Code

In this example, we use the cluster_point_cloud_based_on_density_jump Skill to segment a point cloud into clusters based on sharp changes in point density. After importing the necessary modules and optionally setting up logging, the point cloud is loaded from a .ply file.

python
from telekinesis import vitreous
from datatypes import datatypes, io
import pathlib

# Optional for logging
from loguru import logger

DATA_DIR = pathlib.Path("path/to/telekinesis-data")

# Load point cloud
filepath = str(DATA_DIR / "point_clouds" / "mug_preprocessed.ply")
point_cloud = io.load_point_cloud(filepath=filepath)
logger.success(f"Loaded point cloud with {len(point_cloud.positions)} points")

The Skill analyzes local neighborhoods of points and identifies the steepest drop in density along a specified axis (in this case, the Z-axis). Points are then split into clusters wherever a density jump occurs. This is particularly useful in robotic manipulation and inspection pipelines, for example, separating stacked objects, identifying distinct parts of an assembly, or isolating individual items on a conveyor belt.

python

# Execute operation
clusters = vitreous.cluster_point_cloud_based_on_density_jump(
  point_cloud=point_cloud,
  projection_axis=[0.0, 0.0, 1.0],
  num_nearest_neighbors=12,
  neighborhood_radius=0.001,
  is_point_cloud_linear=False,
)
logger.success(
  "Split point cloud based on density jump"
)

Running the Example

Runnable examples are available in the Telekinesis examples repository. Follow the README in that repository to set up the environment. Once set up, you can run this specific example with:

bash
cd telekinesis-examples
python examples/vitreous_examples.py --example cluster_point_cloud_based_on_density_jump

How to Tune the Parameters

The cluster_point_cloud_based_on_density_jump Skill has four parameters that control how density is calculated and where the split occurs:

projection_axis (required):

  • Defines the direction along which density changes are analyzed
  • Set to the principal axis of the point cloud for best results
  • Typical values: [0, 0, 1] for vertical (Z-axis), [1, 0, 0] for horizontal along X-axis
  • Should align with the direction where you expect density discontinuities

num_nearest_neighbors (default: 12):

  • The number of nearest neighbors used for density estimation at each point
  • Increase (15-30) for more stable density calculation, but slower and may smooth out small density changes
  • Decrease (6-10) for more sensitivity to local variations, but may be affected by noise
  • Typical range: 6-30

neighborhood_radius (default: 0.001):

  • The radius of the spherical neighborhood used for density calculation
  • Units: Uses the same units as your point cloud (e.g., if point cloud is in meters, radius is in meters; if in millimeters, radius is in millimeters)
  • Increase to consider points from a larger area, making estimates more robust but less sensitive to local changes
  • Decrease for more sensitivity to local density variations, but may be affected by noise
  • Should be set based on the scale of your point cloud:
    • Millimeter-scale point clouds (e.g., Zivid where 1 unit = 1 mm): Typical values 1-50 (representing 1-50 mm radius)
    • Centimeter-scale point clouds (e.g., 1 unit = 1 cm): Typical values 0.1-5 (representing 0.1-5 cm radius)
    • Meter-scale point clouds (e.g., 1 unit = 1 m): Typical values 0.001-0.1 (representing 0.001-0.1 m radius)

is_point_cloud_linear (default: False):

  • Set to True if the point cloud represents a linear structure (e.g., rod or wire)
  • Set to False for 2D or 3D structures
  • When True, uses a different density calculation method optimized for linear structures

TIP

Best practice: Start with default values and adjust projection_axis to align with the principal direction of your objects. Then fine-tune neighborhood_radius based on your point cloud scale (remember it uses the same units as your point cloud), and adjust num_nearest_neighbors if the split is too sensitive or not sensitive enough.

Where to Use the Skill in a Pipeline

Density jump clustering is commonly used in the following pipelines:

  • Stacked object separation
  • Layered structure analysis
  • Assembly part identification
  • Conveyor belt item isolation

A typical pipeline for stacked object separation looks as follows:

python
# Example pipeline using density jump clustering (parameters omitted).

from telekinesis import vitreous
import numpy as np

# 1. Load raw point cloud
point_cloud = vitreous.load_point_cloud(...)

# 2. Preprocess: remove outliers and downsample
filtered_cloud = vitreous.filter_point_cloud_using_statistical_outlier_removal(...)
downsampled_cloud = vitreous.filter_point_cloud_using_voxel_downsampling(...)

# 3. Cluster based on density jump (assuming vertical stacking)
clusters = vitreous.cluster_point_cloud_based_on_density_jump(
    point_cloud=downsampled_cloud,
    projection_axis=[0.0, 0.0, 1.0],  # Vertical axis
    num_nearest_neighbors=12,
    neighborhood_radius=0.001,
    is_point_cloud_linear=False,
)

# 4. Process each cluster separately
for cluster in clusters:
    # Compute bounding box, centroid, or other analysis
    centroid = vitreous.calculate_point_cloud_centroid(point_cloud=cluster)
    bbox = vitreous.calculate_oriented_bounding_box(point_cloud=cluster)

Related skills to build such a pipeline:

  • filter_point_cloud_using_statistical_outlier_removal: clean input before clustering
  • filter_point_cloud_using_voxel_downsampling: reduce point cloud density for faster processing
  • cluster_point_cloud_using_dbscan: alternative clustering method for distance-based separation
  • calculate_point_cloud_centroid: compute center of each cluster
  • calculate_oriented_bounding_box: compute bounding box for each cluster

Alternative Skills

Skillvs. Cluster Based on Density Jump
cluster_point_cloud_using_dbscanUse DBSCAN when objects are spatially separated. Use density jump clustering when objects are closely packed or touching and you need to separate them based on density changes along an axis.

When Not to Use the Skill

Do not use cluster based on density jump when:

  • Objects are clearly separated in space (use cluster_point_cloud_using_dbscan instead)
  • There is no clear density discontinuity along any axis (the algorithm may not find a meaningful split)
  • You need more than 2 clusters (this Skill always produces exactly 2 clusters)
  • The point cloud has uniform density (no density jump to detect)
  • You don't know the principal axis (you need to identify the projection axis first)

WARNING

This Skill always produces exactly 2 clusters by splitting at the strongest density discontinuity. If you need multiple clusters or objects are not aligned along a single axis, consider using cluster_point_cloud_using_dbscan instead.