'How do I convert a 3D point cloud (.ply) into a mesh (with faces and vertices)?

I have a 3-D point cloud file with 1 million points that I need to convert into a mesh file in trimesh. The ultimate goal here is to take a point cloud and determine if that point cloud is convex or concave (trimesh allows me to do that once i convert the cloud into a mesh). I'm open to other libraries to solve this.

I've tried Delaunay triangulation using scipy, I just can't seem to convert my pointcloud into the right format so that it can be read by trimesh.

import open3d as o3d
import numpy as np
import trimesh
from scipy.spatial import Delaunay


pointcloud = o3d.io.read_triangle_mesh("pointcloud.ply")
points = np.array(pointcloud.points)
triangle_mesh = Delaunay(points)
#  How do i include triangle_mesh from Delaunay triangulation into processing the mesh file?
mesh = trimesh.load("pointcloud.ply")
print(trimesh.convex.is_convex(mesh))

Error

geometry::TriangleMesh appears to be a geometry::PointCloud (only contains vertices, but no triangles).
geometry::TriangleMesh with 1390073 points and 0 triangles.
expected = (faces.shape[0], faces.shape[1] * 2)
AttributeError: 'NoneType' object has no attribute 'shape'


Solution 1:[1]

Open3d 0.8.0.0 has now implemented the rolling ball pivoting algorithm to reconstruct a mesh from a point cloud.

I solved the problem of generating a trimesh from a point cloud using the following:

import open3d as o3d
import trimesh
import numpy as np

pcd = o3d.io.read_point_cloud("pointcloud.ply")
pcd.estimate_normals()

# estimate radius for rolling ball
distances = pcd.compute_nearest_neighbor_distance()
avg_dist = np.mean(distances)
radius = 1.5 * avg_dist   

mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(
           pcd,
           o3d.utility.DoubleVector([radius, radius * 2]))

# create the triangular mesh with the vertices and faces from open3d
tri_mesh = trimesh.Trimesh(np.asarray(mesh.vertices), np.asarray(mesh.triangles),
                          vertex_normals=np.asarray(mesh.vertex_normals))

trimesh.convex.is_convex(tri_mesh)

Solution 2:[2]

Just inquiring what this line of code actually does? It calls the function with point cloud, as pcd, but what does the double vector section mean? - o3d.utility.DoubleVector([radius, radius * 2]))

mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(
           pcd, o3d.utility.DoubleVector([radius, radius * 2]))

Solution 3:[3]

To save the mesh after following answer of https://stackoverflow.com/a/57971745/6394769 use trimesh export options:

trimesh.exchange.export.export_mesh(tri_mesh, 'output file path.ply .obj etc..')

https://trimsh.org/trimesh.exchange.ply.html

If you want to keep colours in trimesh, make this change:

tri_mesh = trimesh.Trimesh(....., vertex_colors = np.asarray(mesh.vertex_colors))

https://trimsh.org/trimesh.base.html

Alternatively you can directly save mesh using open3d itself:

o3d.io.write_triangle_mesh('file path .ply or .obj etc..', mesh, write_ascii=True (if needed as text and not binary file), compressed=False, print_progress=False)

Mesh colour also saved here if present inside mesh variable.

http://www.open3d.org/docs/release/python_api/open3d.io.write_point_cloud.html#open3d.io.write_point_cloud

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 wwwslinger
Solution 2 Joshua Snider
Solution 3 SFA