ouster.sdk.algorithm

Module contents

Copyright (c) 2026, Ouster, Inc. All rights reserved.

Shared mapping and perception algorithms for Ouster lidar data.

Classes

Functions

GroundSegConfig

class GroundSegConfig(self)

Configuration for the ground segmentation engine.

__annotations__ = {'grid_size': 'None'}
__init__(self) None
__module__ = 'ouster.sdk.algorithm'
__new__(**kwargs)
property grid_size: None

Grid cell size in meters for the 2.5-D height map. Default: 0.5

GroundSegEngine

class GroundSegEngine

Ground segmentation engine for classifying ground points.

Coordinate frame selection:

If any valid column pose in a frame is non-identity, the engine treats those poses as SLAM poses and segments in that global frame. Otherwise, it uses sensor extrinsics and frame-local column poses.

The engine does not compute IMU gravity alignment internally. If gravity alignment is desired, plumb the frame set source first and write the resulting transform into sensor extrinsics before calling update().

__init__(*args, **kwargs)
__module__ = 'ouster.sdk.algorithm'
__new__(**kwargs)
create = <nanobind.nb_func object>

align_clouds

align_clouds(*args, **kwargs)
align_clouds(source_frame: ouster.sdk.core.LidarFrame, target_frame: ouster.sdk.core.LidarFrame, initial_guess: object | None = None, compute_confidence: bool = False) object
align_clouds(source_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], target_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], initial_guess: object | None = None, compute_confidence: bool = False) object
align_clouds(source_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], source_normals: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], target_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], target_normals: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], initial_guess: object | None = None, compute_confidence: bool = False) object

Overloaded function.

  1. align_clouds(frames: ouster.sdk.core.FrameSet) -> object

    Align every valid frame in a FrameSet to the first frame.

    The frame set must contain a valid frame at index 0, which is used as the anchor. Each frame’s sensor_info.sensor_to_body should already hold the gravity-aligned plumb extrinsic; the full matrix is used as the initial extrinsic prior. The function returns a (N, 4, 4) numpy array with one updated extrinsic matrix per input frame: the first matrix is frame 0’s input extrinsic. Each later matrix is the final extrinsic equal to that frame’s input extrinsic left-multiplied by the estimated correction, following the source_to_target_transform convention. Two valid frames use the pairwise alignment path directly; three or more valid frames use the multi-pass spanning-tree matcher.

  2. align_clouds(source_frame: ouster.sdk.core.LidarFrame, target_frame: ouster.sdk.core.LidarFrame, initial_guess: object | None = None, compute_confidence: bool = False) -> object

    Estimate source_to_target_transform from two LidarFrame inputs.

    This overload performs frame preprocessing internally: it uses RANGE, dewarps with per-column poses, and uses frame normals when available (otherwise it estimates normals). Each frame’s sensor_info.sensor_to_body is applied while preparing features: its rotation should be gravity-aligned, and the full matrix, including translation, is used as the initial extrinsic prior. The caller is responsible for setting a gravity-aligned extrinsic (e.g. computed from IMU data) on each frame before calling.

    Ground segmentation is applied to filter ground points from the XY features used for initial yaw/translation matching. If the frame already carries a "GROUND" field (uint8, written by GroundSegEngine), it is reused directly; otherwise ground segmentation is computed on the fly.

    Args:

    source_frame: Source frame transformed by the returned pose. target_frame: Reference target frame. initial_guess: Optional initial source_to_target_transform (defaults to identity). compute_confidence: If True, also returns confidence.

    Returns:
    • compute_confidence=False: np.ndarray of shape (4, 4) containing source_to_target_transform.

    • compute_confidence=True: (pose_delta, confidence) where pose_delta is (4, 4) and confidence is clamped to [0.0, 1.0].

    Confidence:

    Symmetric overlap fraction: points from each cloud are checked for a nearby point in the other cloud after applying the estimated pose (<= 0.5 m in XY). If normals are available on both sides, a normal-angle gate (<= 5 deg) is also required.

  3. align_clouds(source_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], target_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], initial_guess: object | None = None, compute_confidence: bool = False) -> object

    Estimate source_to_target_transform from two point clouds.

    Inputs are expected to be (N, 3) and (M, 3) already in a gravity-aligned common frame. The caller is responsible for applying any IMU-based gravity rotation and dewarping before calling.

    Args:

    source_points: (N, 3) points transformed by the result. target_points: (M, 3) reference target points. initial_guess: Optional initial source_to_target_transform (defaults to identity). compute_confidence: If True, also returns confidence.

    Returns:
    • compute_confidence=False: np.ndarray of shape (4, 4) containing source_to_target_transform.

    • compute_confidence=True: (pose_delta, confidence) where pose_delta is (4, 4) and confidence is clamped to [0.0, 1.0].

    Confidence:

    Symmetric overlap fraction: points from each cloud are checked for a nearby point in the other cloud after applying the estimated pose (<= 0.5 m in XY).

  4. align_clouds(source_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], source_normals: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], target_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], target_normals: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], initial_guess: object | None = None, compute_confidence: bool = False) -> object

    Estimate source_to_target_transform from point clouds with normals.

    This overload expects:

    • source_points.shape == source_normals.shape == (N, 3)

    • target_points.shape == target_normals.shape == (M, 3)

    Inputs must already be in a gravity-aligned common frame. The caller is responsible for applying any IMU-based gravity rotation and dewarping (including rotating the normals) before calling. Non-finite points/normals are ignored and normals are normalized internally.

    Args:

    source_points: (N, 3) points transformed by the result. source_normals: (N, 3) normals aligned to source_points. target_points: (M, 3) reference target points. target_normals: (M, 3) normals aligned to target_points. initial_guess: Optional initial source_to_target_transform (defaults to identity). compute_confidence: If True, also returns confidence.

    Returns:
    • compute_confidence=False: np.ndarray of shape (4, 4) containing source_to_target_transform.

    • compute_confidence=True: (pose_delta, confidence) where pose_delta is (4, 4) and confidence is clamped to [0.0, 1.0].

    Confidence:

    Symmetric overlap fraction: points from each cloud are checked for a nearby point in the other cloud after applying the estimated pose (<= 0.5 m in XY), plus a normal-angle gate (<= 5 deg).

Parameters:
  • args (Any)

  • kwargs (Any)

Return type:

Any

normals

normals(xyz: ndarray[shape=(*, *, 3), writable=False], range: ndarray[shape=(*, *), writable=False], sensor_origins_xyz: ndarray[shape=(*, 3), writable=False], pixel_search_range: int = 1, min_angle_of_incidence_rad: float = 0.017453292519943295, target_distance_m: float = 0.025) numpy.ndarray[dtype=float64, order='C']
normals(xyz: ndarray[shape=(*, *, 3), writable=False], range: ndarray[shape=(*, *), writable=False], xyz2: ndarray[shape=(*, *, 3), writable=False], range2: ndarray[shape=(*, *), writable=False], sensor_origins_xyz: ndarray[shape=(*, 3), writable=False], pixel_search_range: int = 1, min_angle_of_incidence_rad: float = 0.017453292519943295, target_distance_m: float = 0.025) tuple[numpy.ndarray[dtype=float64, order='C'], numpy.ndarray[dtype=float64, order='C']]

Overloaded function.

  1. normals(xyz: ndarray[shape=(*, *, 3), writable=False], range: ndarray[shape=(*, *), writable=False], sensor_origins_xyz: ndarray[shape=(*, 3), writable=False], pixel_search_range: int = 1, min_angle_of_incidence_rad: float = 0.017453292519943295, target_distance_m: float = 0.025) -> numpy.ndarray[dtype=float64, order='C']

Compute normals from destaggered XYZ/range arrays.

Parameters:
  • xyz (Annotated[NDArray, dict(shape=(None, None, 3), writable=False)]) – destaggered XYZ coordinates for the first return (H, W, 3)

  • range (Annotated[NDArray, dict(shape=(None, None), writable=False)]) – destaggered range image for the first return (H, W)

  • sensor_origins_xyz (Annotated[NDArray, dict(shape=(None, 3), writable=False)]) – per-column sensor origins in the same frame as xyz/range, shape (W, 3). For world-frame xyz, use (frame.body_to_world @ frame.sensor_info.sensor_to_body)[:, :3, 3]. For sensor-frame xyz, pass zeros with shape (W, 3) (e.g. np.zeros((w, 3))).

  • pixel_search_range (int) – non-negative axial search radius (in pixels) when gathering neighbours

  • min_angle_of_incidence_rad (float) – minimum allowable incidence angle between a beam and surface (radians) (default: 1 deg, ~0.01745 rad)

  • target_distance_m (float) – target neighbour distance used when selecting candidate points

Returns:

A destaggered normal array of shape (H, W, 3) for the provided return.

  1. normals(xyz: ndarray[shape=(*, *, 3), writable=False], range: ndarray[shape=(*, *), writable=False], xyz2: ndarray[shape=(*, *, 3), writable=False], range2: ndarray[shape=(*, *), writable=False], sensor_origins_xyz: ndarray[shape=(*, 3), writable=False], pixel_search_range: int = 1, min_angle_of_incidence_rad: float = 0.017453292519943295, target_distance_m: float = 0.025) -> tuple[numpy.ndarray[dtype=float64, order='C'], numpy.ndarray[dtype=float64, order='C']]

Compute normals for both first and second returns from destaggered XYZ/range arrays.

Parameters:
  • xyz (Annotated[NDArray, dict(shape=(None, None, 3), writable=False)]) – destaggered XYZ coordinates for the first return (H, W, 3)

  • range (Annotated[NDArray, dict(shape=(None, None), writable=False)]) – destaggered range image for the first return (H, W)

  • xyz2 – destaggered XYZ coordinates for the second return (H, W, 3)

  • range2 – destaggered range image for the second return (H, W)

  • sensor_origins_xyz (Annotated[NDArray, dict(shape=(None, 3), writable=False)]) – per-column sensor origins in the same frame as xyz/range, shape (W, 3). For world-frame xyz, use (frame.body_to_world @ frame.sensor_info.sensor_to_body)[:, :3, 3]. For sensor-frame xyz, pass zeros.

  • pixel_search_range (int) – non-negative axial search radius (in pixels) when gathering neighbours

  • min_angle_of_incidence_rad (float) – minimum allowable incidence angle between a beam and surface (radians) (default: 1 deg, ~0.01745 rad)

  • target_distance_m (float) – target neighbour distance used when selecting candidate points

Returns:

A tuple of destaggered normal arrays (first_return_normals, second_return_normals).

point_to_plane_align

point_to_plane_align(source_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], target_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], source_normals: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], target_normals: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], initial_guess: object | None = None, max_corr_dist: float = 0.25, max_normal_angle_deg: float = 20.0) object

Align two point clouds using point-to-plane ICP.

This helper returns source_to_target_transform: source_points are transformed by the returned pose and target_points stay fixed as the reference cloud.

Parameters:
  • source_points (Annotated[NDArray[numpy.float64], dict(shape=(None, 3), order='C', writable=False)]) – (N, 3) source points transformed by the result.

  • target_points (Annotated[NDArray[numpy.float64], dict(shape=(None, 3), order='C', writable=False)]) – (M, 3) reference target points.

  • source_normals (Annotated[NDArray[numpy.float64], dict(shape=(None, 3), order='C', writable=False)]) – (N, 3) normals aligned with the source points.

  • target_normals (Annotated[NDArray[numpy.float64], dict(shape=(None, 3), order='C', writable=False)]) – (M, 3) normals aligned with the reference target points.

  • initial_guess (object | None) – Optional initial source_to_target_transform.

  • max_corr_dist (float) – Maximum correspondence distance in meters.

  • max_normal_angle_deg (float) – Maximum normal-angle difference in degrees.

Returns:

A (4, 4) numpy array containing source_to_target_transform. The initial guess is returned when fewer than 20 usable points or correspondences are available.

Non-finite points and normals are ignored, normals are normalized internally, and correspondences are weighted with a MAD-scaled Huber loss.

point_to_point_align

point_to_point_align(source_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], target_points: numpy.ndarray[dtype=float64, shape=(*, 3), order='C', writable=False], initial_guess: object | None = None, max_corr_dist: float = 0.25) object

Align two point clouds using point-to-point ICP.

This helper returns source_to_target_transform: source_points are transformed by the returned pose and target_points stay fixed as the reference cloud.

Parameters:
  • source_points (Annotated[NDArray[numpy.float64], dict(shape=(None, 3), order='C', writable=False)]) – (N, 3) source points transformed by the result.

  • target_points (Annotated[NDArray[numpy.float64], dict(shape=(None, 3), order='C', writable=False)]) – (M, 3) reference target points.

  • initial_guess (object | None) – Optional initial source_to_target_transform.

  • max_corr_dist (float) – Maximum correspondence distance in meters.

Returns:

A (4, 4) numpy array containing source_to_target_transform. The initial guess is returned when fewer than 20 usable points or correspondences are available.

Non-finite points are ignored. Correspondences are weighted with a MAD-scaled Huber loss.