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,
)
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,
    )

    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

ParameterTypeDefaultDescription
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 the point clouds' coordinate units, used to estimate each point's surface normal. Must be > 0
normal_max_neighborsdatatypes.Int | int20Maximum number of neighbors used for normal estimation. Must be > 0
feature_radiusdatatypes.Float | float | int0.05Search radius, in the point clouds' coordinate units, used to compute each point's FPFH feature descriptor. Must be > 0
feature_max_neighborsdatatypes.Int | int30Maximum number of neighbors used when computing each FPFH feature. Must be > 0
min_fitness_scoredatatypes.Float | float | int0.3The minimum fitness score the result must reach to be accepted (see the Returns section below for what happens if it never is)
max_correspondence_distancedatatypes.Float | float | int0.015Maximum feature-space distance, in the point clouds' coordinate units, for two points to be considered a matching correspondence. Must be > 0

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. If the alignment's fitness falls below min_fitness_score — including when either point cloud has fewer than 3 points, or FPFH feature computation yields no usable features — this silently returns the identity transform instead of raising.

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, the response was not returned as an Arrow stream, 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 or malformed input (HTTP 400/422), an unrecognized endpoint (HTTP 404), or another unexpected 4xx response
AuthenticationErrorThe API key was rejected as invalid or expired (HTTP 401)
AuthenticationServiceErrorThe authentication service returned an invalid response, was temporarily unavailable, or timed out (HTTP 502/503/504)
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 seven 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 the point clouds' coordinate units, used to estimate each point's surface normal.
  • Units: The point clouds' coordinate units (e.g. meters or millimeters, whatever unit the input data uses)
  • Default: 0.02
  • Must be > 0
  • 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 (in coordinate units matching a meter-scale point cloud) — 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
  • Must be > 0
  • 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 the point clouds' coordinate units, used to compute each point's FPFH feature descriptor.
  • Units: The point clouds' coordinate units
  • Default: 0.05
  • Must be > 0
  • 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 (in coordinate units matching a meter-scale point cloud) — 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
  • Must be > 0
  • 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

min_fitness_score

  • Controls: The minimum fitness score the result must reach to be accepted.
  • Default: 0.3
  • If the alignment's fitness falls below this threshold — including when either point cloud has fewer than 3 points, or FPFH feature computation yields no usable features — the function silently returns the identity transform instead of raising (see the Returns section above)
  • Increase → requires higher-quality alignment before accepting the result
  • Decrease → accepts a lower-quality alignment

max_correspondence_distance

  • Controls: The maximum feature-space distance, in the point clouds' coordinate units, for two points to be considered a matching correspondence.
  • Units: The point clouds' coordinate units
  • Default: 0.015
  • Must be > 0
  • 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 (in coordinate units matching a meter-scale point cloud)

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.

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.