Ransac Module

RANSAC core functions for finding geometric primitives (planes and lines) in point clouds.

In this module all the functions related to the RANSAC algorithm for planes and lines are defined.

The pointcloud is expected to be a numpy array of shape (N, 3) where N is the number of points and 3 is the number of coordinates (x, y, z). No information about RGB values or normals are taken into account. Therefore, an Open3D point cloud must be converted to a numpy array before using the functions in this module.

The following code is an example of how to extract the points from an Open3D point cloud and convert them to a numpy array:

import numpy as np
import open3d as o3d

filename = "pointcloud.ply"
pcd = o3d.io.read_point_cloud(filename)
np_points = np.asarray(pcd.points)

The pointcloud could be in ply or pcd format, because Open3D can read both formats.

You can always access to the pointclouds provided by Open3D. For example, the following code shows how to access to the LivingRoomPointClouds, which are 57 point clouds of from the Redwood RGB-D Dataset.

import open3d as o3d
dataset = o3d.data.LivingRoomPointClouds()
pcds_living_rooms = []
for pcd_path in dataset.paths:
    pcds_living_rooms.append(o3d.io.read_point_cloud(pcd_path))

Other 53 pointclouds from the same dataset are also available in OfficePointClouds:

import open3d as o3d
dataset = o3d.data.OfficePointClouds()
pcds_offices = []
for pcd_path in dataset.paths:
    pcds_offices.append(o3d.io.read_point_cloud(pcd_path))

After executing the previous code, we could define two examples of a living room pointcloud and an office pointcloud, respectively:

living_room_pcd = pcds_living_rooms[0]
office_pcd = pcds_offices[0]

And visualize them:

o3d.visualization.draw_geometries([living_room_pcd])

coreransac_living_room_pcd

o3d.visualization.draw_geometries([office_pcd])

coreransac_office_pcd

A brief explanation of the relationship between the functions defined here is given below:

If we want to extract the best fitting plane from a pointcloud, we have to call the function get_ransac_plane_results(), which, given a pointcloud, the maximum distance from a point to the plane for it to be considered an inlier, and the number of iterations to run the RANSAC algorithm, returns the best plane parameters, the number of inliers, and their indices. It calls the function get_ransac_plane_iteration_results() to get the results of each iteration of the RANSAC algorithm.

The function get_ransac_plane_iteration_results() returns the results of one iteration of the RANSAC algorithm. It calls the function get_how_many_below_threshold_between_plane_and_points_and_their_indices() to get the number of inliers (points which are below a threshold distance from the plane) and their indices.

The function get_ransac_line_iteration_results() is analogous to get_ransac_plane_iteration_results() but for lines. It calls the function get_how_many_below_threshold_between_line_and_points_and_their_indices() to get the number of inliers (points which are below a threshold distance from the line) and their indices.

The function get_fitting_data_from_list_planes() returns a list of dictionaries containing the plane parameters, number of inliers, and their indices for each plane in a given list, while the function get_best_fitting_data_from_list_planes() returns a dictionary containing the plane parameters, number of inliers, and their indices for the best plane in a given list.

get_best_fitting_data_from_list_planes(...)

Returns a dictionary containing the plane parameters, number of inliers, and their indices for the best plane in a given list.

get_fitting_data_from_list_planes(points, ...)

Returns a list of dictionaries containing the plane parameters, number of inliers, and their indices for each plane in a given list.

get_how_many_below_threshold_between_line_and_points_and_their_indices(...)

Computes how many points are below a threshold distance from a line and returns their count and their indices.

get_how_many_below_threshold_between_plane_and_points_and_their_indices(...)

Computes how many points are below a threshold distance from a plane and returns their count and their indices.

get_ransac_line_iteration_results(points, ...)

Returns the results of one iteration of the RANSAC algorithm for line fitting.

get_ransac_plane_iteration_results(points, ...)

Returns the results of one iteration of the RANSAC algorithm for plane fitting.

get_ransac_plane_results(points, threshold, ...)

Computes the best plane that fits a collection of points and the indices of the inliers.

ransac.compute_number_iterations(inliers_ratio, alpha)[source]

Computes the minimum number of iterations needed to achieve a given probability of success in RANSAC.

For success this is understood as the probability of finding at least one sample set free of outliers.

Parameters:
  • inliers_ratio (float) – Ratio of inliers in the data.

  • alpha (float) – Desired probability of success.

Returns:

Minimum number of iterations needed.

Return type:

float

ransac.get_best_fitting_data_from_list_planes(points: ndarray, list_planes: List[ndarray], threshold: float) Dict[source]

Returns a dictionary containing the plane parameters, number of inliers, and their indices for the best plane in a given list.

It takes an array of points, a list of plane equations, and a threshold for defining inliers. The function evaluates each plane for its fitting quality and returns a dictionary with the parameters of the plane that has the highest inlier count, along with the count and indices of these inliers. This function expects a collection of points, a list of plane equations, and a threshold for inlier determination. It returns a dictionary with the plane’s parameters, the count of inliers, and the indices of these inliers. The keys of the dictionary are “plane”, “number_inliers”, and “indices_inliers”, respectively. The type of the values of the dictionary are np.ndarray, int, and np.ndarray, respectively.

Parameters:
  • points (np.ndarray) – The collection of points to fit the plane to.

  • list_planes (List[np.ndarray]) – The list of planes to fit to the points.

  • threshold (float) – The maximum distance from a point to the plane for it to be considered an inlier.

Returns:

A dictionary containing the plane parameters, number of inliers, and their indices.

Return type:

Dict

Example:

>>> from rsaitehu import ransac
>>> import open3d as o3d
>>> import numpy as np
>>> import random
>>> import open3d as o3d
>>> dataset = o3d.data.OfficePointClouds()
>>> pcds_offices = []
>>> for pcd_path in dataset.paths:
>>>     pcds_offices.append(o3d.io.read_point_cloud(pcd_path))
>>> office_pcd = pcds_offices[0]
>>> pcd_points = np.asarray(office_pcd.points)
>>> threshold = 0.1
>>> num_iterations = 20
>>> dict_results = ransac.get_ransac_plane_results(pcd_points, threshold, num_iterations, seed = 42)
>>> dict_results
{'best_plane': array([-0.17535096,  0.45186984, -2.44615646,  5.69205427]),
'number_inliers': 153798,
'indices_inliers': array([     0,      1,      2, ..., 248476, 248477, 248478])}
>>> fitting_data = coreransac.get_fitting_data_from_list_planes(pcd_points, [dict_results["best_plane"]], threshold)
>>> fitting_data
[{'plane': array([-0.17535096,  0.45186984, -2.44615646,  5.69205427]),
'number_inliers': 153798,
'indices_inliers': array([     0,      1,      2, ..., 248476, 248477, 248478])}]
>>> best_fitting_data = coreransac.get_best_fitting_data_from_list_planes(pcd_points, [dict_results["best_plane"]], threshold)
>>> best_fitting_data
{'plane': array([-0.17535096,  0.45186984, -2.44615646,  5.69205427]),
'number_inliers': 153798,
'indices_inliers': array([     0,      1,      2, ..., 248476, 248477, 248478])}
ransac.get_fitting_data_from_list_planes(points: ndarray, list_planes: List[ndarray], threshold: float) List[Dict][source]

Returns a list of dictionaries containing the plane parameters, number of inliers, and their indices for each plane in a given list.

It takes a collection of points, a list of plane equations, and a threshold for inlier determination. This function expects a collection of points, a list of plane equations, and a threshold for inlier determination. It returns a list where each entry corresponds to a plane and contains a dictionary with the plane’s parameters, the count of inliers, and the indices of these inliers. The keys of the dictionary are “plane”, “number_inliers”, and “indices_inliers”, respectively. The type of the values of the dictionary are np.ndarray, int, and np.ndarray, respectively.

Parameters:
  • points (np.ndarray) – The collection of points to fit the plane to.

  • list_planes (List[np.ndarray]) – The list of planes to fit to the points.

  • threshold (float) – The maximum distance from a point to the plane for it to be considered an inlier.

Returns:

A list of dictionaries containing the plane parameters, number of inliers, and their indices.

Return type:

List[Dict]

Example:

>>> from rsaitehu import ransac
>>> import open3d as o3d
>>> import numpy as np
>>> import random
>>> import open3d as o3d
>>> dataset = o3d.data.OfficePointClouds()
>>> pcds_offices = []
>>> for pcd_path in dataset.paths:
>>>     pcds_offices.append(o3d.io.read_point_cloud(pcd_path))
>>> office_pcd = pcds_offices[0]
>>> pcd_points = np.asarray(office_pcd.points)
>>> threshold = 0.1
>>> num_iterations = 20
>>> dict_results = ransac.get_ransac_plane_results(pcd_points, threshold, num_iterations, seed = 42)
>>> dict_results
{'best_plane': array([-0.17535096,  0.45186984, -2.44615646,  5.69205427]),
'number_inliers': 153798,
'indices_inliers': array([     0,      1,      2, ..., 248476, 248477, 248478])}
>>> fitting_data = coreransac.get_fitting_data_from_list_planes(pcd_points, [dict_results["best_plane"]], threshold)
>>> fitting_data
[{'plane': array([-0.17535096,  0.45186984, -2.44615646,  5.69205427]),
'number_inliers': 153798,
'indices_inliers': array([     0,      1,      2, ..., 248476, 248477, 248478])}]
ransac.get_how_many_below_threshold_between_line_and_points_and_their_indices(points: ndarray, line_two_points: ndarray, threshold: float32) Tuple[int, ndarray][source]

Computes how many points are below a threshold distance from a line and returns their count and their indices.

This functions expects a collection of points, two points defining the line, and a threshold for inlier determination. It returns a tuple containing the number of inliers and their indices. The type of the values of the tuple are int and np.ndarray, respectively.

Parameters:
  • points (np.ndarray) – The collection of points to measure the distance to the line.

  • line_two_points (np.ndarray) – Two points defining the line.

  • threshold (np.float32) – Maximum distance to the line.

Returns:

Number of points below the threshold distance as their indices.

Return type:

Tuple[int, np.ndarray]

Example:

>>> from rsaitehu import ransac
>>> from rsaitehu import geometry as geom
>>> from rsaitehu import drawing
>>> import rsaitehu.matplot3d as plot3d
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> line = np.array([[0, 0, 0], [1, 1, 1]])
>>> points = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1], [2, 2, 2], [2, 2, 3], [2, 2, 4]])
>>> threshold = 1
>>> count, indices_below = ransac.get_how_many_below_threshold_between_line_and_points_and_their_indices(points, line, threshold)
>>> count
5
>>> indices_below
array([0, 1, 2, 3, 4])
>>> points[indices_below]
array([[-1, -1, -1],
[ 0,  0,  0],
[ 1,  1,  1],
[ 2,  2,  2],
[ 2,  2,  3]])

>>> # Calculate the minimum and maximum points of the cube.
>>> cube_min = np.min(points, axis=0)
>>> cube_max = np.max(points, axis=0)

>>> # Get the intersection of the line with the cube
>>> intersection_points = geom.get_intersection_points_of_line_with_cube(line, cube_min, cube_max)

>>> # Draw the cube
>>> fig = plt.figure()
>>> ax = fig.add_subplot(111, projection='3d')
>>> drawing.draw_cube(cube_min, cube_max, alpha = 0.1, ax = ax)
>>> # Draw the segment between the intersection points
>>> plot3d.draw_segment(intersection_points, color="green", ax = ax)
>>> # Draw the intersection points
>>> plot3d.draw_points(intersection_points, color="black", style="X", ax = ax)


>>> # Get the indices of the points above the threshold
>>> all_indices = np.arange(len(points))
>>> indices_above = np.setdiff1d(all_indices, indices_below)
>>> # Plot the points below the threshold in red
>>> plot3d.draw_points(points[indices_below], color="red", style="o", ax = ax)
>>> # Plot the points above the threshold in blue
>>> plot3d.draw_points(points[indices_above], color="blue", style="o", ax = ax)

>>> ax.set_xlabel('X')
>>> ax.set_ylabel('Y')
>>> ax.set_zlabel('Z')
>>> ax.legend()
>>> plt.show()

coreransac_get_how_many_below_threshold_between_line_and_points_and_their_indices_example

ransac.get_how_many_below_threshold_between_plane_and_points_and_their_indices(points: ndarray, plane: ndarray, threshold: float32) Tuple[int, ndarray][source]

Computes how many points are below a threshold distance from a plane and returns their count and their indices.

This functions expects a collection of points, four parameters defining the plane, and a threshold for inlier determination. It returns a tuple containing the number of inliers and their indices. The type of the values of the tuple are int and np.ndarray, respectively.

Parameters:
  • points (np.ndarray) – The collection of points to measure the distance to the line.

  • plane (np.ndarray) – Four parameters defining the plane in the form Ax + By + Cz + D = 0.

  • threshold (np.float32) – Maximum distance to the line.

Returns:

Number of points below the threshold distance as their indices.

Return type:

Tuple[int, np.ndarray]

Example:

>>> from rsaitehu import ransac
>>> import numpy as np
>>> plane = np.array([1, 1, 1, 0])
>>> points = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1], [2, 2, 2], [2, 2, 3], [2, 2, 4]])
>>> threshold = 1
>>> count, indices = ransac.get_how_many_below_threshold_between_plane_and_points_and_their_indices(points, plane, threshold)
>>> count
1
>>> indices
array([1])
>>> points[indices]
array([[0, 0, 0]])
ransac.get_ransac_line_iteration_results(points: ndarray, threshold: float, len_points: int | None = None, seed: int | None = None) dict[source]

Returns the results of one iteration of the RANSAC algorithm for line fitting.

This functions expects a collection of points, the number of points in the collection, the maximum distance from a point to the line for it to be considered an inlier, and the seed to initialize the random number generator. It returns a dictionary containing the current line parameters, number of inliers, and their indices. The keys of the dictionary are current_random_points, “current_line”, “threshold”, “number_inliers”, and “indices_inliers”, respectively.

Parameters:
  • points (np.ndarray) – The collection of points to fit the line to.

  • threshold (float) – The maximum distance from a point to the line for it to be considered an inlier.

  • len_points (Optional[int]) – The number of points in the collection of points.

Returns:

A dictionary containing the current line parameters, number of inliers, and their indices.

Return type:

dict

ransac.get_ransac_plane_iteration_results(points: ndarray, threshold: float, len_points: int | None = None, seed: int | None = None) dict[source]

Returns the results of one iteration of the RANSAC algorithm for plane fitting.

This functions expects a collection of points, the number of points in the collection, the maximum distance from a point to the plane for it to be considered an inlier, and the seed to initialize the random number generator. It returns a dictionary containing the current plane parameters, number of inliers, and their indices. The keys of the dictionary are current_random_points, “current_plane”, “threshold”, “number_inliers”, and “indices_inliers”, respectively. The type of the values of the dictionary are np.ndarray, np.ndarray, float, int, and np.ndarray, respectively.

Parameters:
  • points (np.ndarray) – The collection of points to fit the plane to.

  • threshold (float) – The maximum distance from a point to the plane for it to be considered an inlier.

  • len_points (Optional[int]) – The number of points in the collection of points.

  • seed (Optional[int]) – The seed to initialize the random number generator.

Returns:

A dictionary containing the current plane parameters, number of inliers, and their indices, as well as the three random points sampled to create the plane.

Return type:

dict

Example:

>>> from rsaitehu import ransac
>>> import open3d as o3d
>>> import numpy as np
>>> import random
>>> import open3d as o3d
>>> dataset = o3d.data.OfficePointClouds()
>>> pcds_offices = []
>>> for pcd_path in dataset.paths:
>>>     pcds_offices.append(o3d.io.read_point_cloud(pcd_path))
>>> office_pcd = pcds_offices[0]
>>> pcd_points = np.asarray(office_pcd.points)
>>> threshold = 0.1
>>> num_iterations = 20
>>> dict_results = ransac.get_ransac_plane_iteration_results(pcd_points, threshold, seed = 42)
>>> dict_results
>>> {'current_random_points': array([[1.61072648, 1.83984375, 1.91796875],
>>> [3.00390625, 2.68674755, 2.01953125],
>>> [2.10068583, 2.34765625, 2.14453125]]),
>>> 'current_plane': array([ 0.14030194, -0.2658808 ,  0.29252566, -0.297864  ]),
>>> 'threshold': 0.1,
>>> 'number_inliers': 34283,
>>> 'indices_inliers': array([ 98356, 101924, 101956, ..., 271055, 271245, 271246])}
>>> inliers = dict_results["indices_inliers"]
>>> inlier_cloud = office_pcd.select_by_index(inliers)
>>> inlier_cloud.paint_uniform_color([1.0, 0, 0])
>>> outlier_cloud = office_pcd.select_by_index(inliers, invert=True)
>>> o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud])

coreransac_get_ransac_plane_iteration_results_example

ransac.get_ransac_plane_results(points: ndarray, threshold: float, num_iterations: int, len_points: int | None = None, seed: int | None = None) dict[source]

Computes the best plane that fits a collection of points and the indices of the inliers.

This functions expects a collection of points, the number of points in the collection, the maximum distance from a point to the plane for it to be considered an inlier, and the number of iterations to run the RANSAC algorithm. It returns a dictionary containing the best plane parameters, number of inliers, and their indices. The keys of the dictionary are “best_plane”, “number_inliers”, and “indices_inliers”, respectively. The type of the values of the dictionary are np.ndarray, int, and np.ndarray, respectively. Reproducibility is enforced by setting the seed parameter to a fixed value.

Parameters:
  • points (np.ndarray) – The collection of points to fit the plane to.

  • threshold (float) – The maximum distance from a point to the plane for it to be considered an inlier.

  • num_iterations (int) – The number of iterations to run the RANSAC algorithm.

  • len_points (Optional[int]) – The number of points in the collection of points.

  • seed (Optional[int]) – The seed to initialize the random number generator.

Returns:

A dictionary containing the best plane parameters, number of inliers, and their indices.

Return type:

dict

Example:

>>> from rsaitehu import ransac
>>> import open3d as o3d
>>> import numpy as np
>>> import random
>>> import open3d as o3d
>>> dataset = o3d.data.OfficePointClouds()
>>> pcds_offices = []
>>> for pcd_path in dataset.paths:
>>>     pcds_offices.append(o3d.io.read_point_cloud(pcd_path))
>>> office_pcd = pcds_offices[0]
>>> pcd_points = np.asarray(office_pcd.points)
>>> threshold = 0.1
>>> num_iterations = 20
>>> dict_results = ransac.get_ransac_plane_results(pcd_points, threshold, num_iterations, seed = 42)
>>> dict_results
{'best_plane': array([-0.17535096,  0.45186984, -2.44615646,  5.69205427]),
'number_inliers': 153798,
'indices_inliers': array([     0,      1,      2, ..., 248476, 248477, 248478])}
>>> inliers = dict_results["indices_inliers"]
>>> inlier_cloud = office_pcd.select_by_index(inliers)
>>> inlier_cloud.paint_uniform_color([1.0, 0, 0])
>>> outlier_cloud = office_pcd.select_by_index(inliers, invert=True)
>>> o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud])

coreransac_get_ransac_plane_results_example