Skip to content

Register Point Clouds Using Cuboid Translation Sampler ICP

SUMMARY

Register Point Clouds Using Cuboid Translation Sampler ICP finds the best alignment between two point clouds by trying many candidate translations on a 3D grid, refining each one with point-to-point ICP.

It samples translations on a regular grid within [x_min, x_max] x [y_min, y_max] x [z_min, z_max] (relative to initial_transformation_matrix), runs ICP starting from each sampled translation, and keeps whichever run converged to the best fitness score. This is useful when source_point_cloud and target_point_cloud are already roughly rotationally aligned but the translation between them isn't known precisely enough for plain ICP to converge on its own. Compare with register_point_clouds_using_rotation_sampler_icp, which instead searches over rotations. The function returns the 4x4 transform that produced the best result, not an already-moved point cloud — apply it with apply_transform_to_point_cloud.

Use this Skill when you want to register two point clouds whose relative translation is uncertain but whose relative rotation is already roughly known.

The Skill

python
from telekinesis import vitreous
import numpy as np

transformation_matrix = vitreous.register_point_clouds_using_cuboid_translation_sampler_icp(
    source_point_cloud=source_point_cloud,
    target_point_cloud=target_point_cloud,
    initial_transformation_matrix=np.eye(4),
    step_size=2,
    x_min=-20,
    x_max=20,
    y_min=-20,
    y_max=20,
    z_min=-20,
    z_max=20,
    early_stop_fitness_score=0.3,
    min_fitness_score=0.48,
    max_iterations=50,
    max_correspondence_distance=2,
    estimate_scaling=False,
)

aligned_point_cloud = vitreous.apply_transform_to_point_cloud(
    point_cloud=source_point_cloud,
    transformation_matrix=transformation_matrix,
    modify_inplace=False,
)
API Reference
Full parameter and return type documentation for register_point_clouds_using_cuboid_translation_sampler_icp.
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

Source and Target Point Clouds

Raw sensor input i.e. target point cloud in green and object model in red

Registered Point Clouds

Registered source point cloud (red) aligned to target point cloud (green) using cuboid translation sampler ICP with 3D grid translation search

The Code

python
"""
Demonstrates finding the best alignment by sampling translations in a 3D grid (cuboid) with ICP.
"""

import numpy as np
from loguru import logger
import rerun as rr

from telekinesis import vitreous, datatypes


def register_point_clouds_using_cuboid_translation_sampler_icp_example():
    """
    Finds best alignment by sampling translations in a 3D grid (cuboid) with ICP.

    Tries translations on a regular 3D grid within specified x/y/z ranges, runs ICP
    for each, and keeps best result.
    """
    # ===================== Load Data ==========================================
    source_point_cloud_url = "https://assets.telekinesis.ai/examples/v1/point_clouds/weld_clamp_model_shifted.ply"
    target_point_cloud_url = "https://assets.telekinesis.ai/examples/v1/point_clouds/weld_clamp_cluster_0_centroid_registered.ply"
    source_point_cloud = datatypes.PointCloud.from_url(
        url=source_point_cloud_url, use_cache=True
    )
    target_point_cloud = datatypes.PointCloud.from_url(
        url=target_point_cloud_url, use_cache=True
    )

    # ===================== Run Skill ==========================================
    transformation_matrix = (
        vitreous.register_point_clouds_using_cuboid_translation_sampler_icp(
            step_size=2,
            x_min=-20,
            x_max=20,
            y_min=-20,
            y_max=20,
            z_min=-20,
            z_max=20,
            early_stop_fitness_score=0.3,
            min_fitness_score=0.48,
            max_iterations=50,
            max_correspondence_distance=2,
            estimate_scaling=False,
            source_point_cloud=source_point_cloud,
            target_point_cloud=target_point_cloud,
            initial_transformation_matrix=np.eye(4),
        )
    )

    # ===================== Log ================================================
    logger.success(
        f"Registered {source_point_cloud} to {target_point_cloud} using cuboid translation sampler ICP"
    )
    logger.success(f"Results: {transformation_matrix}")
    logger.info(f"Transformation matrix data: {transformation_matrix.data}")
    logger.info(f"Transformation matrix shape: {transformation_matrix.shape}")
    logger.info(f"Transformation matrix ndim: {transformation_matrix.ndim}")
    logger.info(f"Transformation matrix dtype: {transformation_matrix.dtype}")

    # ===================== Visualization  (Optional) ===========================
    aligned_source_point_cloud = vitreous.apply_transform_to_point_cloud(
        point_cloud=source_point_cloud,
        transformation_matrix=transformation_matrix,
        modify_inplace=False,
    )

    rr.init(
        "register_point_clouds_using_cuboid_translation_sampler_icp_example", spawn=True
    )
    datatypes.visualize(source_point_cloud, entity_path="/1-before_registration_source")
    datatypes.visualize(target_point_cloud, entity_path="/2-before_registration_target")
    datatypes.visualize(
        aligned_source_point_cloud, entity_path="/3-after_registration_source_aligned"
    )


if __name__ == "__main__":
    register_point_clouds_using_cuboid_translation_sampler_icp_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/register_point_clouds_using_cuboid_translation_sampler_icp.py

Parameter Configuration

KeyTypeDefaultDescription
source_point_clouddatatypes.PointCloudrequiredThe point cloud to align
target_point_clouddatatypes.PointCloudrequiredThe point cloud to align to
initial_transformation_matrixdatatypes.Mat4x4 | np.ndarray | list[list[float]]np.eye(4)A 4x4 transform applied to source_point_cloud before the search — the translation search happens relative to this initial alignment
step_sizedatatypes.Float | float | int0.001Spacing, in meters, between sampled translations on the search grid
x_mindatatypes.Float | float | int-0.01Lower bound, in meters, of the translation search along x (relative to initial_transformation_matrix)
x_maxdatatypes.Float | float | int0.01Upper bound, in meters, of the translation search along x
y_mindatatypes.Float | float | int-0.01Lower bound, in meters, of the translation search along y
y_maxdatatypes.Float | float | int0.01Upper bound, in meters, of the translation search along y
z_mindatatypes.Float | float | int-0.01Lower bound, in meters, of the translation search along z
z_maxdatatypes.Float | float | int0.01Upper bound, in meters, of the translation search along z
early_stop_fitness_scoredatatypes.Float | float | int0.5A fitness score in [0, 1] at which the grid search stops early instead of trying every remaining sample
min_fitness_scoredatatypes.Float | float | int0.9Minimum fitness score in [0, 1] the best result must reach to be accepted at all
max_iterationsdatatypes.Int | int50Maximum number of ICP iterations run for each sampled translation
max_correspondence_distancedatatypes.Float | float | int0.02Maximum distance, in meters, at which two points from the source/target clouds are considered a match during ICP
estimate_scalingdatatypes.Bool | boolFalseWhether to also estimate and apply a uniform scale factor between the two point clouds, instead of assuming they're at the same scale

Returns

TypeDescription
datatypes.Mat4x4The best-scoring 4x4 transform found by the grid search — this is the transform itself, not an already-transformed point cloud. Pass it to apply_transform_to_point_cloud (as transformation_matrix) to actually move source_point_cloud's points. Use .data for the raw (4, 4) array.

Raises

ExceptionCondition
TypeErrorA parameter's value does not match its expected type (see the Parameter Configuration table above)
ValueErrorinitial_transformation_matrix is not shape (4, 4) (or, for a list input, doesn't contain only numeric elements)
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 register_point_clouds_using_cuboid_translation_sampler_icp Skill exposes thirteen tunable parameters that define the translation search grid and control the ICP refinement run at each grid point.

initial_transformation_matrix

  • Controls: The seed transform the translation grid is centered on — every sampled translation is relative to this.
  • Default: np.eye(4) (identity — no pre-alignment)
  • Provide a rough rotation-only alignment here if source_point_cloud and target_point_cloud aren't already close in orientation; this Skill only searches over translation, not rotation.

step_size

  • Controls: Spacing, in meters, between sampled translations on the search grid.
  • Units: Meters
  • Default: 0.001
  • Increase → coarser grid — fewer samples, faster, but may miss the optimal alignment
  • Decrease → finer grid — more samples, slower, more thorough
  • Set to roughly 0.5-2x the alignment accuracy you need
  • Typical range: 0.0005-0.01 meters — use 0.0005-0.001 for a precise search, 0.001-0.005 for balanced, 0.005-0.01 for coarse

x_min / x_max, y_min / y_max, z_min / z_max

  • Controls: The bounds, in meters, of the translation search cuboid along each axis, relative to initial_transformation_matrix.
  • Units: Meters
  • Default: -0.01 / 0.01 on all three axes
  • The _min bound should be negative and the _max bound positive (and greater than _min) if the true translation could lie in either direction along that axis
  • Typical range: -0.1 to 0.1 meters per bound

early_stop_fitness_score

  • Controls: A fitness score in [0, 1] at which the grid search stops early instead of trying every remaining sample.
  • Units: Dimensionless (fitness score)
  • Default: 0.5
  • Increase → accepts stopping sooner (faster), but may settle for a suboptimal alignment
  • Decrease → requires a better fit before stopping early
  • Typical range: 0.3-0.7 — use 0.3-0.5 for a fast search, 0.5-0.7 for higher quality

min_fitness_score

  • Controls: The minimum fitness score in [0, 1] the best result must reach to be accepted at all.
  • Units: Dimensionless (fitness score)
  • Default: 0.9
  • Increase → requires higher-quality alignment
  • Decrease → accepts lower quality
  • Typical range: 0.7-0.99 — use 0.7-0.85 for lenient, 0.85-0.95 for balanced, 0.95-0.99 for strict

max_iterations

  • Controls: The maximum number of ICP iterations run for each sampled translation.
  • Units: Iterations (integer)
  • Default: 50
  • Increase → more refinement per sample, but slower overall
  • Decrease → faster
  • Typical range: 10-200 — use 10-30 for fast, 30-50 for balanced, 50-200 for high precision

max_correspondence_distance

  • Controls: The maximum distance, in meters, at which two points from the source/target clouds are considered a match during ICP.
  • Units: Meters
  • Default: 0.02
  • Increase → allows matching more distant points, risking incorrect matches
  • Decrease → requires closer matches
  • Set to roughly 2-5x the point spacing
  • Typical range: 0.01-0.1 meters

estimate_scaling

  • Controls: Whether to also estimate and apply a uniform scale factor between the two point clouds, instead of assuming they're at the same scale.
  • Default: False
  • Set to True only if the clouds might genuinely be at different scales.

TIP

Pick x_min/x_max/y_min/y_max/z_min/z_max to bracket your expected translation uncertainty first, then set step_size to roughly 0.5-2x the precision you need within that range. If the clouds aren't already roughly rotationally aligned, resolve that separately (e.g. with register_point_clouds_using_rotation_sampler_icp or a known fixed rotation) — this Skill only searches over translation.

Where to Use the Skill

Common pipelines include:

  • 6D pose estimation with uncertain translation – aligning a reference/CAD model to a sensor scan when the object's position, but not its orientation, on a fixture or conveyor is unknown
  • Multi-view point cloud registration – merging scans captured from positions that are only approximately known
  • Robotic pick-and-place setup – locating a known part whose position varies from scan to scan while its orientation stays consistent
  • Refining a coarse translation guess – following up the SDK's register_point_clouds_using_centroid_translation when a single centroid match isn't precise enough

Alternative Skills

Skillvs. Register Point Clouds Using Cuboid Translation Sampler ICP
register_point_clouds_using_rotation_sampler_icpSearches over rotations instead of translations. Use it when the clouds are already close in position but the relative rotation is unknown; use this Skill when it's the other way around.
register_point_clouds_using_point_to_point_icpPlain point-to-point ICP from a single initial guess, with no sampling. Use it once you already have a translation estimate good enough for direct convergence; use this Skill first if you don't.
register_point_clouds_using_fast_global_registrationFeature-based global registration that doesn't require any rough pre-alignment at all. A good alternative starting point when neither the translation nor the rotation between the clouds is known.

The SDK's register_point_clouds_using_centroid_translation is a fast, translation-only coarse-alignment step commonly run before this Skill (it has no doc page yet, but its docstring — and this Skill's — reference each other directly).

When Not to Use the Skill

Do not use Register Point Clouds Using Cuboid Translation Sampler ICP when:

  • The clouds are already roughly aligned in translation – plain register_point_clouds_using_point_to_point_icp (or register_point_clouds_using_point_to_plane_icp) converges directly, without the extra grid search
  • The rotation between the clouds is unknown, not the translation – use register_point_clouds_using_rotation_sampler_icp instead, which searches rotations
  • You have no rough alignment at all, in rotation or translation – use register_point_clouds_using_fast_global_registration first, since it tolerates large initial misalignment
  • You need a fast result – this Skill runs a full ICP pass for every sampled translation, so it is slower than a single ICP call
  • The translation uncertainty spans a very large volume – the grid may need too many samples at a workable step_size to search effectively
  • The point clouds may be at different scales – set estimate_scaling=True, or pre-scale the clouds; otherwise the search assumes matching scale

TIP

Keep the search cuboid (x_min/x_max/y_min/y_max/z_min/z_max) as tight as your actual translation uncertainty allows — a smaller cuboid at a given step_size means fewer ICP runs and a faster search.