Skip to content

Filter Point Cloud Using Oriented Bounding Box

SUMMARY

Filter Point Cloud Using Oriented Bounding Box extracts points within a 3D region defined by an oriented bounding box (OBB), which can be rotated relative to the world axes.

This Skill is particularly useful in industrial, mobile, and humanoid robotics pipelines for isolating objects or regions that are not axis-aligned. For example, it can crop a rotated part on an assembly line, focus on a tilted object for mobile robot inspection, or extract a hand-held tool for humanoid manipulation. Using an OBB allows robots to accurately capture points of interest even when objects are oriented arbitrarily in space.

Use this Skill when you want to crop a point cloud to a rotated or angled region of interest for downstream perception, pose estimation, or manipulation tasks.

The Skill

python
from telekinesis import vitreous
from datatypes import datatypes
import numpy as np

# Create oriented bounding box
center = np.array([[0.0, 0.0, 0.0]], dtype=np.float32)
half_size = np.array([[0.1, 0.1, 0.1]], dtype=np.float32)
rotation_in_euler_angles = np.array([[0.0, 0.0, 45.0]], dtype=np.float32)  # Rotate 45 degrees around Z
oriented_bbox = datatypes.Boxes3D(
    half_size=half_size,
    center=center,
    rotation_in_euler_angles=rotation_in_euler_angles,
)

# Filter point cloud
filtered_point_cloud = vitreous.filter_point_cloud_using_oriented_bounding_box(
    point_cloud=point_cloud,
    oriented_bbox=oriented_bbox,
)

API 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.

Oriented Bounding Box

Oriented bounding box in red overlayed with the unprocessed point cloud.

Filtered Points

Only the points that fall within the specified 3D box defined are kept.

The Code

python
from telekinesis import vitreous
from datatypes import datatypes, io
import pathlib
import numpy as np

# Optional for logging
from loguru import logger

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

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

# Execute operation
x_min = -205.65248652
y_min = -112.59310319
z_min = 554.42936219
x_max = 121.88022318
y_max = -17.60647882
z_max = 698.54912862
rot_x = -38.1245801
rot_y = -7.89877607
rot_z = -7.74440359    

half_size = np.array(
  [[(x_max - x_min) / 2, (y_max - y_min) / 2, (z_max - z_min) / 2]],
  dtype=np.float32,
)
center = np.array(
  [[(x_min + x_max) / 2, (y_min + y_max) / 2, (z_min + z_max) / 2]],
  dtype=np.float32,
)
rotation_in_euler_angles = np.array([[rot_x, rot_y, rot_z]], dtype=np.float32)
oriented_bbox = datatypes.Boxes3D(
  half_size=half_size,
  center=center,
  rotation_in_euler_angles=rotation_in_euler_angles,
)

# Filter point cloud using oriented bounding box
filtered_point_cloud = vitreous.filter_point_cloud_using_oriented_bounding_box(
  point_cloud=point_cloud, oriented_bbox=oriented_bbox
)
logger.success("Filtered points using oriented bounding box")

The Explanation of the Code

The example begins by importing the required modules for point cloud manipulation, data handling, numerical operations, and logging. These include vitreous, datatypes, io, numpy, pathlib, and loguru.

python
from telekinesis import vitreous
from datatypes import datatypes, io
import pathlib
import numpy as np

# Optional for logging
from loguru import logger

Next, a point cloud is loaded from a .ply file. This point cloud represents the 3D geometry of an object or scene and is the input for the filtering operation. Logging is used to confirm the number of points successfully loaded.

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

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

Finally, the filter_point_cloud_using_oriented_bounding_box Skill is applied. An oriented bounding box is defined by its center, half-size, and rotation in Euler angles. This bounding box can be rotated in 3D space, allowing precise cropping of the point cloud along any orientation. The Skill filters out points outside the oriented box, which is particularly useful in robotics and industrial pipelines for isolating objects in arbitrary poses, performing localized analysis, or preparing data for tasks like registration, pose estimation, and manipulation.

python

# Execute operation
x_min = -205.65248652
y_min = -112.59310319
z_min = 554.42936219
x_max = 121.88022318
y_max = -17.60647882
z_max = 698.54912862
rot_x = -38.1245801
rot_y = -7.89877607
rot_z = -7.74440359    

half_size = np.array(
  [[(x_max - x_min) / 2, (y_max - y_min) / 2, (z_max - z_min) / 2]],
  dtype=np.float32,
)
center = np.array(
  [[(x_min + x_max) / 2, (y_min + y_max) / 2, (z_min + z_max) / 2]],
  dtype=np.float32,
)
rotation_in_euler_angles = np.array([[rot_x, rot_y, rot_z]], dtype=np.float32)
oriented_bbox = datatypes.Boxes3D(
  half_size=half_size,
  center=center,
  rotation_in_euler_angles=rotation_in_euler_angles,
)

# Filter point cloud using oriented bounding box
filtered_point_cloud = vitreous.filter_point_cloud_using_oriented_bounding_box(
  point_cloud=point_cloud, oriented_bbox=oriented_bbox
)
logger.success("Filtered points using oriented bounding box")

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 filter_point_cloud_using_oriented_bounding_box

How to Tune the Parameters

The filter_point_cloud_using_oriented_bounding_box Skill has one parameter that controls the filtering:

oriented_bbox (required):

  • The oriented bounding box to use for filtering, specified as a Boxes3D object
  • The bounding box is defined by:
    • center: The center point of the box (3D coordinates)
    • half_size: Half the size of the box along each axis (width/2, height/2, depth/2)
    • rotation_in_euler_angles: Rotation angles in degrees around X, Y, Z axes (Euler angles)
  • Units: The center, half_size, and rotation angles use the same units as your point cloud (e.g., if point cloud is in meters, bbox is in meters; if in millimeters, bbox is in millimeters)
  • Increase half_size to include more points (larger region)
  • Decrease half_size to include fewer points (smaller region)
  • Adjust center to position the bounding box around the region of interest
  • Adjust rotation_in_euler_angles to orient the box to match the object's orientation

TIP

Best practice: Use calculate_oriented_bounding_box to automatically compute oriented bounding boxes from point clouds. Manually create oriented bounding boxes when you know the exact region and orientation you want to extract.

Where to Use the Skill in a Pipeline

Oriented bounding box filtering is commonly used in the following pipelines:

  • Rotated object isolation
  • Arbitrary orientation region extraction
  • Tilted object focusing
  • Oriented workspace cropping

A typical pipeline for rotated object isolation looks as follows:

python
# Example pipeline using oriented bounding box filtering (parameters omitted).

from telekinesis import vitreous
from datatypes import datatypes
import numpy as np

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

# 2. Preprocess: remove outliers
filtered_cloud = vitreous.filter_point_cloud_using_statistical_outlier_removal(...)

# 3. Optional: Compute oriented bounding box from object
object_obb = vitreous.calculate_oriented_bounding_box(point_cloud=filtered_cloud)

# 4. Filter point cloud using oriented bounding box
# Option A: Use computed oriented bounding box
cropped_cloud = vitreous.filter_point_cloud_using_oriented_bounding_box(
    point_cloud=filtered_cloud,
    oriented_bbox=object_obb,
)

# Option B: Create custom oriented bounding box
center = np.array([[0.0, 0.0, 0.5]], dtype=np.float32)
half_size = np.array([[0.2, 0.2, 0.1]], dtype=np.float32)
rotation_in_euler_angles = np.array([[30.0, 45.0, 0.0]], dtype=np.float32)  # Rotated box
custom_obb = datatypes.Boxes3D(
    half_size=half_size,
    center=center,
    rotation_in_euler_angles=rotation_in_euler_angles,
)
cropped_cloud = vitreous.filter_point_cloud_using_oriented_bounding_box(
    point_cloud=filtered_cloud,
    oriented_bbox=custom_obb,
)

# 5. Process the cropped point cloud
clusters = vitreous.cluster_point_cloud_using_dbscan(...)

Related skills to build such a pipeline:

  • calculate_oriented_bounding_box: compute oriented bounding box from point cloud
  • calculate_axis_aligned_bounding_box: compute axis-aligned bounding box
  • filter_point_cloud_using_statistical_outlier_removal: clean input before filtering
  • filter_point_cloud_using_bounding_box: alternative for axis-aligned filtering
  • filter_point_cloud_using_passthrough: alternative for simple axis-aligned filtering

Alternative Skills

Skillvs. Filter Point Cloud Using Oriented Bounding Box
filter_point_cloud_using_bounding_boxUse axis-aligned bounding box for simpler, faster filtering when objects are aligned with coordinate axes. Use oriented bounding box when objects are rotated or tilted.
filter_point_cloud_using_passthroughUse passthrough filter for simple axis-aligned min/max filtering. Use oriented bounding box when you need rotated filtering.
filter_point_cloud_using_plane_proximityUse plane proximity when you want to filter based on distance from a plane. Use oriented bounding box when you want to filter based on a 3D box region.

When Not to Use the Skill

Do not use filter point cloud using oriented bounding box when:

  • Objects are axis-aligned (use filter_point_cloud_using_bounding_box or filter_point_cloud_using_passthrough instead for simpler, faster filtering)
  • You need simple min/max coordinate filtering (use filter_point_cloud_using_passthrough instead)
  • You need to filter based on distance from a plane (use filter_point_cloud_using_plane_proximity instead)
  • The oriented bounding box is invalid (ensure the box is properly defined with valid center, half_size, and rotation)
  • You need to filter based on other criteria (use other filtering methods like radius outlier removal, statistical outlier removal, etc.)