Search code examples
pythonword-wraptriangulationpoint-clouds

Point Cloud to Volume


I have a point cloud in cartesian coordinates. Using python I would like to wrap those points in a mesh and then take a volume of the cloud. The points are distributed throughout the cloud and not just representing the outermost surface. I would like to wrap the outermost surface. Can anyone point me to a library that can help me with this? What functions do you recommend I use to wrap and then calculate the volume?

Thanks for the help in advance!


Solution

  • What you need to do is to compute the Convex Hull of your point cloud.

    You can do this using https://github.com/daavoo/pyntcloud (contributions are welcome).

    Here are the steps:

    Load point cloud from file:

    from pyntcloud import PyntCloud
    diamond = PyntCloud.from_file("test/data/diamond.ply")
    

    Here is how it looks this example point cloud: point cloud

    Compute Convex Hull

    This uses scipy's wrap of Qhull library:

    convex_hull_id = diamond.add_structure("convex_hull")
    

    You can access the convex hull like this:

    convex_hull = diamond.structures[convex_hull_id]
    

    Visualize the Convex Hull

    You can generate a mesh from the convex hull as follows:

    diamond.mesh = convex_hull.get_mesh()
    

    And save the point cloud + mesh to a file (for example ply format) and visualize it in any 3D mesh software (for example Meshlab):

    diamond.to_file("diamond_hull.ply", also_save=["mesh"])
    

    Here is the output visualized in meshlab:

    mesh

    Get volume from Convex Hull

    Finally, you can acces the volume of the convex hull as easy as this:

    volume = convex_hull.volume
    

    Test with sphere

    To test the precision of this approach you can run the following code.

    This will generate a point cloud of a sphere (radius 25) and use the convex hull to compute the volume:

    from pyntcloud import PyntCloud
    from pyntcloud.geometry.models.sphere import create_sphere
    cloud = PyntCloud(create_sphere(center=[0, 0, 0], radius=25, n_points=100000))
    convex_hull_id = cloud.add_structure("convex_hull")
    convex_hull = cloud.structures[convex_hull_id]
    print(convex_hull.volume)
    

    Outputs:

    65439.21101051165
    

    And because it is a sphere we can actually compute the real volume:

    import numpy as np
    # google: volume of sphere
    print((4/3) * np.pi * (25 ** 3))
    

    Outputs:

    65449.84694978735
    

    Whit is pretty close, given that we are working with meters, and we only use 100000 points to approximate the sphere