Point Cloud to Volume

geop picture geop · Jul 9, 2017 · Viewed 8.9k times · Source

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!

Answer

David de la Iglesia picture David de la Iglesia · Jul 19, 2017

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