Giter VIP home page Giter VIP logo

pyransac-3d's Introduction



DOI PyPI Latest Release License

What is pyRANSAC-3D?

pyRANSAC-3D is an open source implementation of Random sample consensus (RANSAC) method. It fits primitive shapes such as planes, cuboids and cylinder in a point cloud to many aplications: 3D slam, 3D reconstruction, object tracking and many others.


Features:

Installation

Requirements: Numpy

Install with Pypi:

pip3 install pyransac3d

Take a look:

Example 1 - Planar RANSAC

import pyransac3d as pyrsc

points = load_points(.) # Load your point cloud as a numpy array (N, 3)

plane1 = pyrsc.Plane()
best_eq, best_inliers = plane1.fit(points, 0.01)

Results in the plane equation Ax+By+Cz+D: [0.720, -0.253, 0.646, 1.100]

Example 2 - Spherical RANSAC

Loading a noisy sphere's point cloud with r = 5 centered in 0 we can use the following code:

import pyransac3d as pyrsc

points = load_points(.) # Load your point cloud as a numpy array (N, 3)

sph = pyrsc.Sphere()
center, radius, inliers = sph.fit(points, thresh=0.4)

Results:

center: [0.010462385575072288, -0.2855090643954039, 0.02867848979091283]
radius: 5.085218633039647

3D Sphere

Documentation & other links

License

Apache 2.0

Citation

Did this repository was useful for your work? =)

@software{Mariga_pyRANSAC-3D_2022,
  author = {Mariga, Leonardo},
  doi = {10.5281/zenodo.7212567},
  month = {10},
  title = {{pyRANSAC-3D}},
  url = {https://github.com/leomariga/pyRANSAC-3D},
  version = {v0.6.0},
  year = {2022}
}

Contributing is awesome!

See CONTRIBUTING

Contact

Developed with ❤️ by the internet

Mainteiner: Leonardo Mariga

Did you like it? Remember to click on 🌟 button.

pyransac-3d's People

Contributors

jungerm2 avatar karellat avatar leomariga avatar leriks11 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyransac-3d's Issues

Restrict Volume of Cuboid

Thank you very much for this repo! I learned a lot form it and enjoyed working with it.

Do you know if it is possible to restrict the solution of the cuboid by imposing a known volume (or width, height, lenght) or the cuboid? I use the cuboid.fit algorithm on a pointcloud containing multiple objects. Unfortunately, the algorithm returned a cuboid that returned a solution comprising all distinct object. I tried to restrict the algorithm as followes:

lenght = pts[pt_id_inliers, 0].max() - pts[pt_id_inliers, 0].min()
height = pts[pt_id_inliers, 1].max() - pts[pt_id_inliers, 1].min()
width = pts[pt_id_inliers, 2].max() - pts[pt_id_inliers, 2].min()
volume = height * length * width
if volume > max_volume:
    continue

Where max_volume is a function argument to the fit function. Strangely, the proposed solution of the algorithm does not change from one iteration to the loop to the other and at the end the algorithm does not find any solution.

Do yo have any idea how one could impose a restricted size of the cuboid?

Getting Runtime error when fitting.

Encountered the error when plane fitting:

/usr/local/lib/python3.8/dist-packages/pyransac3d/plane.py:59: RuntimeWarning: invalid value encountered in true_divide
vecC = vecC / np.linalg.norm(vecC)

Code Attached:

def plane_fit(pointList):
[X, Y, Z, I] = pointList
p_arr = np.empty((len(X), 3), float)
P_color_arr = np.empty((0, 3), int)

print('print len of full points')
print(len(X))
for i in range(len(X)):
    p_arr = np.append(p_arr, np.array([[X[i], Y[i], Z[i]]]), axis=0)
    P_color_arr = np.append(p_arr, np.array([[I[i], 0, 0]]), axis=0)

plane1 = pyrsc.Plane()

# Load saved point cloud and visualize it
pcd_load = o3d.geometry.PointCloud()
pcd_load.points = o3d.utility.Vector3dVector(p_arr)
pcd_load.colors = o3d.utility.Vector3dVector(P_color_arr)
print("pcd created")
# o3d.visualization.draw_geometries([pcd_load])
points = np.asarray(pcd_load.points)


best_eq, best_inliers = plane1.fit(points, 1)
X_new = []
Y_new = []
Z_new = []
I_new = []
print("Printing len of inliners")
print(len(best_inliers))
print("Equation:")
print(best_eq)
for i in range(len(p_arr)):
    if i in best_inliers:
        X_new.append(p_arr[i][0])
        Y_new.append(p_arr[i][1])
        Z_new.append(p_arr[i][2])
        I_new.append(1)


print(len(X_new))
return [X_new, Y_new, Z_new, I_new]

Distance to plane

Hey there,

this is more of a request then an issue. Your work is nice and lightweighted. Simple to use and works very efficient. This is what I can say after 20 min of use.
What I miss or better what I would like to have is a method to compare my pointCloud with the calculated plane. The result of this comparison should be pointCloud where each pixel represents the distance to calculated plane equation.

What do you think about this?

Add line

Add line fit with RANSAC. Select two points and verify distance from nearby points

error running the the test_plane.py

I ran the 'tests/test_plane.py ' but got the following error:

>>> python tests/test_plane.py  
RPly: Unable to open file
[Open3D WARNING] Read PLY failed: unable to open file: dataset/caixa.ply
0
Traceback (most recent call last):
  File "tests/test_plane.py", line 15, in <module>
    best_eq, best_inliers = plano1.fit(points, 0.01)
  File "/Users/opt/anaconda3/envs/open3d/lib/python3.8/site-packages/pyransac3d/plane.py", line 46, in fit
    id_samples = random.sample(range(1, n_points-1), 3)
  File "/Users/opt/anaconda3/envs/open3d/lib/python3.8/random.py", line 363, in sample
    raise ValueError("Sample larger than population or is negative")
ValueError: Sample larger than population or is negative

filename aux.py prevents installation on windows

I've just had some nasty issues installing on windows(10) due to 'aux' being a reserved word wrt to filenames (aux.py) ,

This issue prevents installation with pip, and leaves the user unable to open, rename, or delete the file - making it effectively impossible to clean up afterwards.

Add cone

Add cone RANSAC implementation

Wrong center for detecting circles

When we detect circles from point sets, the resulting circle is at a wrong place. Here an example (green - inliers):
pyransac_before

After checking the code, I guess the bug comes from the line 93 in file "circle.py".
I changed it to "p_center = [p_center_x, p_center_y, P_rot[0, 2]]" then the result becomes:
pyransac_after

Could you check the code? I'm open for further discussion.

Cuboid with just 3 planes?

Hi there,

I just started using this library, and I am also new to computational geometry so please bear with me..

I am trying to fit a cuboid to some points, but I just realized that the Cuboid.fit() result is just returning 3 planes. I expected it to return 6 planes, as I don't see how 3 planes can fully parametrize a cuboid object.

I felt pretty dumb and was sure I was missing something, so I asked ChatGPT which seems to agree that we need 6 planes and not 3.. now I am even more confused.

What am I missing?

Interest in threading?

I was playing around with this library, and I found that because of the heavy usage of numpy (which releases the global interpeter lock), that a simple ThreadPoolExecutor running the internals of the for loops will allow for a 5x speedup on my laptop.

I was wondering if there was any interest in adding this to the library?

This is the API I was thinking would work. Each Ransac class would subclass this, to enable parallelization. Also, I added the ability to pass a seed, so that you can run deterministic ransac tests.

class BaseParallelRansac(ABC):
    def __init__(self, seed=None, n_workers=None):
        self.executor = ThreadPoolExecutor(max_workers=None)
        self.random = Random(seed)

    def fit(
        self, points: np.ndarray, thresh: float = 0.05, max_iteration: int = 5000
    ) -> Tuple[List[int], List[int]]:
        """
        :param points: A numpy array of points, of shape (# points, 3)
        :param thresh: The distance threshold to include points as inliers
        :param max_iteration: How many (parallel) Ransac iterations to run
        :returns:
            best_eq: A list of integers representing the best 'equation' for the primitive shape.
            best_inliers: A list of indices of points that fit the shape.
        """
        best_eq = []
        best_inliers = []
        jobs = ((self.random, points, float(thresh)) for _ in range(max_iteration))
        for eq, point_id_inliers in self.executor.map(self.iteration, *zip(*jobs)):
            if len(point_id_inliers) > len(best_inliers):
                best_eq = eq
                best_inliers = point_id_inliers
        return best_eq, best_inliers

    @staticmethod
    @abstractmethod
    def iteration(
        self, random: Random, points: np.ndarray, thresh: float
    ) -> Tuple[List[int], List[int]]:
        pass

class Cuboid(BaseParallelRansac):
   def iteration(random, points, thresh):
       # Implementation of a the inside of the for loop
       ...

Bad plane fitting (maybe bad parameter)

Hey,

I would like to attach a plane equation to a point cloud in order to be able to compare new point clouds with the plane later.

At first it looked fine, but over time I noticed that my plane equation is always aligned parallel to the Z-plane. As can be seen here:
Image Pasted at 2021-3-9 13-15
My plan equation parameter = [0,0,1,-832]

This is my code:
planeObj = pyrsc.Plane() best_eq, best_inliers = planeObj.fit(pointCloudPoints, thresh=0.001, minPoints=1000, maxIteration=10000)

I'm using round about 200k points for the fitting.

Now I am not sure if I have set my parameters correctly and hope that you can help me here.

For comparison, here is a picture with a different RANSAC algorithm:
Image Pasted at 2021-3-9 13-18
Here are the plane equationparameter = [-2.62341300e-05 4.57572034e-05 -1.20127911e-03 9.99999277e-01]
This code I code from here https://github.com/falcondai/py-ransac

I hope you have a tip for me.

Thank you.

finding random shapes

Hi, is there any way to load a point cloud file, and find the different shapes hiding in it without prior knowledge? If I don't know what the shape is ahead of time, is there any way to use the algorithm?
Thanks a lot for you help!

Cannot fit a space circle

The fitting error occurs when the plane of the space circle does not pass through the origin. For example, "points[:,2]=points[:,2]+5" in "test_circle.py". Shift all points up by 5, and the fit is incorrect

Cylinder Fitting

The cylinder fitting with RANSAC method is very unstable. There are some ways to improve the performance of RANSAC:

  1. add or compute the normal components to the point cloud data.
  2. take the RANSAC result as an initial guess, optimize the cylinder coefficents with the inlier points and normals using nonlinear optimization algorithms, such as LM algorithm.
  3. use MSAC or MLESAC instead of RANSAC.

Disable printing the number of points

I have thousands of shapes, and I don't want the fitting function to print the number of points for each shape. Could you disable that option?

Thanks in advance!

How to find other planes of an object?

Hi, I was able to run test_plane.py and obtain this output

image

I was wondering how to automatically obtain the other 2 planes (highlighted in pink and purple rectangles) in this particular case

image

Thanks!

RANSAC Plane from 3 and 4 points fails

Currently Ransac Plane fails when total of the provided points is 3 or 4.

Reproducible code

import pyransac3d as pyrsc
import numpy as np

plane = pyrsc.Plane()
pts = [[0,0,0],[0,1,0],[1,0,0]]
plane.fit(np.array(pts), 0.01)

And it receives error:

File "<stdin>", line 1, in <module>
  File "/home/ardiya/.local/lib/python3.8/site-packages/pyransac3d/plane.py", line 46, in fit
    id_samples = random.sample(range(1, n_points-1), 3)
  File "/usr/lib/python3.8/random.py", line 363, in sample
    raise ValueError("Sample larger than population or is negative")
ValueError: Sample larger than population or is negative

Env note:
pyransac3d 0.5.1 from pip install

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.