Search code examples
pythonmeshmeshlabopen3d

How to convert 3D cloud datapoints to mesh using python?


I have a set of 3D data points that looks similar to sphere. I need these data points to be connected as a watertight mesh so that it can be used for simulation.

I have worked with Meshlab and obtained a reasonable mesh but not watertight.

After this, I have tried with Open3D python library by using ball pivot algorithm. From this, I am unable to obtain water tight mesh as expected. I tried to work with hole_fixer external library (Hole_fixer), but finding and error in installing using cmake.

I have inserted the code and also "xyz" datapoints used for open3D.

import numpy as np
import open3d as o3d

dataname = 'meshdata2.xyz'

point_cloud = np.loadtxt(dataname, skiprows=1)


pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(point_cloud[:,:3])
pcd.estimate_normals()



distances = pcd.compute_nearest_neighbor_distance()
avg_dist = np.mean(distances)
radius = 5*avg_dist

bpa_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(pcd, o3d.utility.DoubleVector([radius, radius*2, radius*0.5]))
print(str(bpa_mesh.is_watertight()))
o3d.visualization.draw_geometries([bpa_mesh])

Link for "xyz file": xyz_file_link

Mesh obtained from Open3D: Mesh_from_open3D

I would like to know how to obtain water tight mesh for these datapoints.

Any leads will be appreciated.

Regards,

Sunag R A.


Solution

  • To achieve a water tight mesh, you can use o3d.geometry.TriangleMesh.create_from_point_cloud_poisson.

    However, Poisson reconstruction requires consistent normal orientation. In your case, you can just orient all normals toward the center of your point cloud. To do that:

    import numpy as np
    import open3d as o3d
    
    pcd = o3d.io.read_point_cloud('./meshdata2.xyz')
    pcd.estimate_normals()
    
    # to obtain a consistent normal orientation
    pcd.orient_normals_towards_camera_location(pcd.get_center())
    
    # or you might want to flip the normals to make them point outward, not mandatory
    pcd.normals = o3d.utility.Vector3dVector( - np.asarray(pcd.normals))
    
    # surface reconstruction using Poisson reconstruction
    mesh, _ = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=9)
    
    # paint uniform color to better visualize, not mandatory
    mesh.paint_uniform_color(np.array([0.7, 0.7, 0.7]))
    
    o3d.io.write_triangle_mesh('a.ply', mesh)
    

    Mesh obtained using the above code snippet: enter image description here


    For point clouds with complex topology, it might not be easy to obtain a consistent normal orientation, read my other answer for more info.