Skip to content

Register Point Clouds Using Fast Global Registration

SUMMARY

Register Point Clouds Using Fast Global Registration aligns two point clouds using Fast Global Registration (FGR), a feature-based global registration method.

It estimates surface normals, computes FPFH (Fast Point Feature Histogram) descriptors around each point, matches points by feature similarity rather than raw proximity, and optimizes the alignment via graduated non-convexity. Unlike the ICP-based registration Skills in Vitreous, FGR doesn't need the clouds to already be roughly aligned — it can handle larger initial misalignments — which makes it the right choice when you don't have a good initial_transformation_matrix to start from. The function returns the 4x4 transform it found, not an already-moved point cloud — apply it with apply_transform_to_point_cloud.

Use this Skill when you want to compute an initial alignment between two point clouds without needing them to already be roughly positioned relative to each other.

The Skill

python
from telekinesis import vitreous
import numpy as np

transformation_matrix = vitreous.register_point_clouds_using_fast_global_registration(
    source_point_cloud=source_point_cloud,
    target_point_cloud=target_point_cloud,
    initial_transformation_matrix=np.eye(4),
    normal_radius=3.7,
    normal_max_neighbors=30,
    feature_radius=11.1,
    feature_max_neighbors=100,
    max_correspondence_distance=7.4,
)

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_fast_global_registration.
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 Fast Global Registration (FGR) with FPFH features

The Code

python
"""
Demonstrates aligning point clouds using Fast Global Registration (FGR).
"""

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

from telekinesis import vitreous, datatypes


def register_point_clouds_using_fast_global_registration_example():
    """
    Aligns point clouds using Fast Global Registration (FGR).

    Feature-based registration that's faster than RANSAC. Uses graduated
    non-convexity optimization.
    """
    # ===================== Load Data ==========================================
    source_point_cloud_url = "https://assets.telekinesis.ai/examples/v1/point_clouds/gusset_model_voxelized.ply"
    target_point_cloud_url = "https://assets.telekinesis.ai/examples/v1/point_clouds/gusset_0_preprocessed_voxelized.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_fast_global_registration(
            normal_radius=3.7,
            normal_max_neighbors=30,
            feature_radius=11.1,
            feature_max_neighbors=100,
            max_correspondence_distance=7.4,
            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 fast global registration"
    )
    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_fast_global_registration_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_fast_global_registration_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_fast_global_registration.py

Parameter Configuration

KeyTypeDefaultDescription
source_point_clouddatatypes.PointCloudrequiredThe point cloud to align. Normals are estimated automatically if not already present
target_point_clouddatatypes.PointCloudrequiredThe point cloud to align to. Normals are estimated automatically if not already present
initial_transformation_matrixdatatypes.Mat4x4 | np.ndarray | list[list[float]]np.eye(4)A 4x4 transform applied to source_point_cloud before registration. FGR tolerates larger initial misalignments than ICP, but a rough initial alignment still helps
normal_radiusdatatypes.Float | float | int0.02Search radius, in meters, used to estimate each point's surface normal
normal_max_neighborsdatatypes.Int | int20Maximum number of neighbors used for normal estimation
feature_radiusdatatypes.Float | float | int0.05Search radius, in meters, used to compute each point's FPFH feature descriptor
feature_max_neighborsdatatypes.Int | int30Maximum number of neighbors used when computing each FPFH feature
max_correspondence_distancedatatypes.Float | float | int0.015Maximum feature-space distance, in meters, for two points to be considered a matching correspondence

Returns

TypeDescription
datatypes.Mat4x4The 4x4 transform found by FGR — 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_fast_global_registration Skill exposes six tunable parameters that control normal estimation, FPFH feature computation, and feature matching.

initial_transformation_matrix

  • Controls: An optional seed transform applied to source_point_cloud before registration.
  • Default: np.eye(4) (identity)
  • FGR tolerates a larger initial misalignment than the ICP-based Skills, so this can usually be left at the identity; a rough alignment still helps if you happen to have one.

normal_radius

  • Controls: The search radius, in meters, used to estimate each point's surface normal.
  • Units: Meters
  • Default: 0.02
  • Increase → considers more neighbors — smoother, more stable normals, but slower
  • Decrease → fewer neighbors — faster, but noisier
  • Set to roughly 2-5x the point spacing
  • Typical range: 0.01-0.1 meters — use 0.01-0.02 for dense clouds, 0.02-0.05 for medium, 0.05-0.1 for sparse

normal_max_neighbors

  • Controls: The maximum number of neighbors used for normal estimation.
  • Units: Points (integer count)
  • Default: 20
  • Increase → more stable normals, slower
  • Decrease → faster, noisier
  • Typical range: 10-50 — use 10-20 for fast, 20-30 for balanced, 30-50 for quality

feature_radius

  • Controls: The search radius, in meters, used to compute each point's FPFH feature descriptor.
  • Units: Meters
  • Default: 0.05
  • Increase → captures larger-scale surface features, but slower
  • Decrease → captures finer features
  • Set to roughly 5-10x the point spacing
  • Typical range: 0.02-0.2 meters — use 0.02-0.05 for fine features, 0.05-0.1 for balanced, 0.1-0.2 for coarse

feature_max_neighbors

  • Controls: The maximum number of neighbors used when computing each FPFH feature.
  • Units: Points (integer count)
  • Default: 30
  • Increase → captures more surrounding context, slower
  • Decrease → faster
  • Typical range: 20-100 — use 20-30 for fast, 30-50 for balanced, 50-100 for detailed

max_correspondence_distance

  • Controls: The maximum feature-space distance, in meters, for two points to be considered a matching correspondence.
  • Units: Meters
  • Default: 0.015
  • Increase → allows matching more dissimilar features, risking incorrect matches
  • Decrease → requires closer matches
  • Set to roughly 2-5x feature_radius
  • Typical range: 0.01-0.1 meters

TIP

Set normal_radius and feature_radius relative to your point cloud's density (a few times the typical point spacing) before touching the other parameters — feature quality depends more on these radii matching the data than on the neighbor-count limits. Follow up with register_point_clouds_using_point_to_point_icp or register_point_clouds_using_point_to_plane_icp for a higher-accuracy refinement once FGR has produced a rough alignment.

Where to Use the Skill

Common pipelines include:

  • Initial coarse alignment with no prior pose estimate – bootstrapping registration when neither the translation nor the rotation between two clouds is known
  • Feature-based multi-view registration – merging scans from viewpoints that weren't tracked precisely enough for a direct ICP start
  • Object pose estimation from scratch – finding a first alignment of a reference model to a scene scan before refining with ICP
  • Recovering from a failed or missing coarse alignment – as a fallback when register_point_clouds_using_centroid_translation or a sampler-based ICP Skill isn't applicable because the misalignment is too large

Alternative Skills

Skillvs. Register Point Clouds Using Fast Global Registration
register_point_clouds_using_point_to_point_icpMatches by raw point-to-point distance and requires the clouds to already be roughly aligned within max_correspondence_distance. Use it to refine the alignment FGR produces, or directly if you already have a good starting alignment.
register_point_clouds_using_point_to_plane_icpMatches by distance to the target's tangent plane using normals; also requires rough pre-alignment. A more accurate refinement step to run after FGR when normals are reliable.
register_point_clouds_using_cuboid_translation_sampler_icpSearches over translations with repeated ICP runs; still requires the clouds to be roughly rotationally aligned first, unlike FGR.
register_point_clouds_using_rotation_sampler_icpSearches over rotations with repeated ICP runs; still requires the clouds to be roughly positioned first, unlike FGR.

The SDK's register_point_clouds_using_centroid_translation is a much cheaper coarse-alignment alternative when you already know the clouds share the same orientation and only need a translation estimate — FGR is the better choice when you don't even have that.

When Not to Use the Skill

Do not use Register Point Clouds Using Fast Global Registration when:

  • The point clouds are already well-aligned – use register_point_clouds_using_point_to_point_icp or register_point_clouds_using_point_to_plane_icp directly for refinement instead
  • You need very high final accuracy – FGR produces a coarse-to-medium alignment; follow it with an ICP-based Skill for a precise final result
  • The point clouds have very different geometries – FPFH feature matching relies on comparable surface structure and may fail otherwise
  • The point clouds are very sparse – normals and FPFH descriptors become unreliable with too few neighboring points
  • You already have a good rough alignment and only need refinement speed – the ICP-based Skills are cheaper once a good initial_transformation_matrix is available

TIP

Because FGR estimates normals and FPFH features from scratch, voxel-downsampling both clouds to a consistent density before calling this Skill (e.g. with filter_point_cloud_using_voxel_downsampling) makes normal_radius and feature_radius easier to tune and keeps the feature computation fast.