Triangle Mesh¶
triangle_mesh_connected_components.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | import open3d as o3d import numpy as np import copy if __name__ == "__main__": bunny = o3d.data.BunnyMesh() mesh = o3d.io.read_triangle_mesh(bunny.path) mesh.compute_vertex_normals() mesh = mesh.subdivide_midpoint(number_of_iterations=2) vert = np.asarray(mesh.vertices) min_vert, max_vert = vert.min(axis=0), vert.max(axis=0) for _ in range(30): cube = o3d.geometry.TriangleMesh.create_box() cube.scale(0.005, center=cube.get_center()) cube.translate( ( np.random.uniform(min_vert[0], max_vert[0]), np.random.uniform(min_vert[1], max_vert[1]), np.random.uniform(min_vert[2], max_vert[2]), ), relative=False, ) mesh += cube mesh.compute_vertex_normals() print("Displaying input mesh ...") o3d.visualization.draw([mesh]) print("Clustering connected triangles ...") with o3d.utility.VerbosityContextManager( o3d.utility.VerbosityLevel.Debug) as cm: triangle_clusters, cluster_n_triangles, cluster_area = ( mesh.cluster_connected_triangles()) triangle_clusters = np.asarray(triangle_clusters) cluster_n_triangles = np.asarray(cluster_n_triangles) cluster_area = np.asarray(cluster_area) print("Displaying mesh with small clusters removed ...") mesh_0 = copy.deepcopy(mesh) triangles_to_remove = cluster_n_triangles[triangle_clusters] < 100 mesh_0.remove_triangles_by_mask(triangles_to_remove) o3d.visualization.draw([mesh_0]) |
triangle_mesh_cropping.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | import open3d as o3d import numpy as np import copy if __name__ == "__main__": knot_mesh = o3d.data.KnotMesh() mesh = o3d.io.read_triangle_mesh(knot_mesh.path) mesh.compute_vertex_normals() print("Displaying original mesh ...") o3d.visualization.draw([mesh]) print("Displaying mesh of only the first half triangles ...") mesh_cropped = copy.deepcopy(mesh) mesh_cropped.triangles = o3d.utility.Vector3iVector( np.asarray(mesh_cropped.triangles)[:len(mesh_cropped.triangles) // 2, :]) mesh_cropped.triangle_normals = o3d.utility.Vector3dVector( np.asarray(mesh_cropped.triangle_normals) [:len(mesh_cropped.triangle_normals) // 2, :]) print(mesh_cropped.triangles) o3d.visualization.draw([mesh_cropped]) |
triangle_mesh_deformation.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | import numpy as np import open3d as o3d import time import os import sys pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(pyexample_path) import open3d_example as o3dex def problem0(): mesh = o3dex.get_plane_mesh(height=1, width=1) mesh = mesh.subdivide_midpoint(3) vertices = np.asarray(mesh.vertices) static_ids = [ 1, 46, 47, 48, 16, 51, 49, 50, 6, 31, 33, 32, 11, 26, 27, 25, 0, 64, 65, 20, 66, 68, 67, 7, 69, 71, 70, 22, 72, 74, 73, 3, 15, 44, 43, 45, 5, 41, 40, 42, 13, 39, 37, 38, 2, 56, 55, 19, 61, 60, 59, 8, 76, 75, 77, 23 ] static_positions = [] for id in static_ids: static_positions.append(vertices[id]) handle_ids = [4] handle_positions = [vertices[4] + np.array((0, 0, 0.4))] return mesh, static_ids + handle_ids, static_positions + handle_positions def problem1(): mesh = o3dex.get_plane_mesh(height=1, width=1) mesh = mesh.subdivide_midpoint(3) vertices = np.asarray(mesh.vertices) static_ids = [ 1, 46, 15, 43, 5, 40, 13, 38, 2, 56, 37, 39, 42, 41, 45, 44, 48, 47 ] static_positions = [] for id in static_ids: static_positions.append(vertices[id]) handle_ids = [21] handle_positions = [vertices[21] + np.array((0, 0, 0.4))] return mesh, static_ids + handle_ids, static_positions + handle_positions def problem2(): armadillo_data = o3d.data.ArmadilloMesh() mesh = o3d.io.read_triangle_mesh(armadillo_data.path) vertices = np.asarray(mesh.vertices) static_ids = [idx for idx in np.where(vertices[:, 1] < -30)[0]] static_positions = [] for id in static_ids: static_positions.append(vertices[id]) handle_ids = [2490] handle_positions = [vertices[2490] + np.array((-40, -40, -40))] return mesh, static_ids + handle_ids, static_positions + handle_positions if __name__ == "__main__": o3d.utility.set_verbosity_level(o3d.utility.Debug) for mesh, constraint_ids, constraint_pos in [ problem0(), problem1(), problem2() ]: constraint_ids = np.array(constraint_ids, dtype=np.int32) constraint_pos = o3d.utility.Vector3dVector(constraint_pos) tic = time.time() mesh_prime = mesh.deform_as_rigid_as_possible( o3d.utility.IntVector(constraint_ids), constraint_pos, max_iter=50) print("deform took {}[s]".format(time.time() - tic)) mesh_prime.compute_vertex_normals() mesh.paint_uniform_color((1, 0, 0)) handles = o3d.geometry.PointCloud() handles.points = constraint_pos handles.paint_uniform_color((0, 1, 0)) o3d.visualization.draw_geometries([mesh, mesh_prime, handles]) o3d.utility.set_verbosity_level(o3d.utility.Info) |
triangle_mesh_filtering_average.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | from numpy.random.mtrand import laplace import open3d as o3d import numpy as np def average_filtering(): # Create noisy mesh. knot_mesh = o3d.data.KnotMesh() mesh_in = o3d.io.read_triangle_mesh(knot_mesh.path) vertices = np.asarray(mesh_in.vertices) noise = 5 vertices += np.random.uniform(0, noise, size=vertices.shape) mesh_in.vertices = o3d.utility.Vector3dVector(vertices) mesh_in.compute_vertex_normals() print("Displaying input mesh ...") o3d.visualization.draw_geometries([mesh_in]) print("Displaying output of average mesh filter after 1 iteration ...") mesh_out = mesh_in.filter_smooth_simple(number_of_iterations=1) mesh_out.compute_vertex_normals() o3d.visualization.draw_geometries([mesh_out]) print("Displaying output of average mesh filter after 5 iteration ...") mesh_out = mesh_in.filter_smooth_simple(number_of_iterations=5) mesh_out.compute_vertex_normals() o3d.visualization.draw_geometries([mesh_out]) def laplace_filtering(): # Create noisy mesh. knot_mesh = o3d.data.KnotMesh() mesh_in = o3d.io.read_triangle_mesh(knot_mesh.path) vertices = np.asarray(mesh_in.vertices) noise = 5 vertices += np.random.uniform(0, noise, size=vertices.shape) mesh_in.vertices = o3d.utility.Vector3dVector(vertices) mesh_in.compute_vertex_normals() print("Displaying input mesh ...") o3d.visualization.draw_geometries([mesh_in]) print("Displaying output of Laplace mesh filter after 10 iteration ...") mesh_out = mesh_in.filter_smooth_laplacian(number_of_iterations=10) mesh_out.compute_vertex_normals() o3d.visualization.draw_geometries([mesh_out]) print("Displaying output of Laplace mesh filter after 50 iteration ...") mesh_out = mesh_in.filter_smooth_laplacian(number_of_iterations=50) mesh_out.compute_vertex_normals() o3d.visualization.draw_geometries([mesh_out]) def taubin_filtering(): # Create noisy mesh. knot_mesh = o3d.data.KnotMesh() mesh_in = o3d.io.read_triangle_mesh(knot_mesh.path) vertices = np.asarray(mesh_in.vertices) noise = 5 vertices += np.random.uniform(0, noise, size=vertices.shape) mesh_in.vertices = o3d.utility.Vector3dVector(vertices) mesh_in.compute_vertex_normals() print("Displaying input mesh ...") o3d.visualization.draw_geometries([mesh_in]) print("Displaying output of Taubin mesh filter after 10 iteration ...") mesh_out = mesh_in.filter_smooth_taubin(number_of_iterations=10) mesh_out.compute_vertex_normals() o3d.visualization.draw_geometries([mesh_out]) print("Displaying output of Taubin mesh filter after 100 iteration ...") mesh_out = mesh_in.filter_smooth_taubin(number_of_iterations=100) mesh_out.compute_vertex_normals() o3d.visualization.draw_geometries([mesh_out]) if __name__ == "__main__": average_filtering() laplace_filtering() taubin_filtering() |
triangle_mesh_from_point_cloud_alpha_shapes.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | import open3d as o3d if __name__ == "__main__": bunny = o3d.data.BunnyMesh() mesh = o3d.io.read_triangle_mesh(bunny.path) mesh.compute_vertex_normals() pcd = mesh.sample_points_poisson_disk(750) print("Displaying input pointcloud ...") o3d.visualization.draw_geometries([pcd]) alpha = 0.03 print(f"alpha={alpha:.3f}") print('Running alpha shapes surface reconstruction ...') mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape( pcd, alpha) mesh.compute_triangle_normals(normalized=True) print("Displaying reconstructed mesh ...") o3d.visualization.draw_geometries([mesh], mesh_show_back_face=True) |
triangle_mesh_from_point_cloud_ball_pivoting.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import open3d as o3d if __name__ == "__main__": bunny = o3d.data.BunnyMesh() gt_mesh = o3d.io.read_triangle_mesh(bunny.path) gt_mesh.compute_vertex_normals() pcd = gt_mesh.sample_points_poisson_disk(3000) print("Displaying input pointcloud ...") o3d.visualization.draw([pcd], point_size=5) radii = [0.005, 0.01, 0.02, 0.04] print('Running ball pivoting surface reconstruction ...') rec_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting( pcd, o3d.utility.DoubleVector(radii)) print("Displaying reconstructed mesh ...") o3d.visualization.draw([rec_mesh]) |
triangle_mesh_from_point_cloud_poisson.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import open3d as o3d import numpy as np if __name__ == "__main__": eagle = o3d.data.EaglePointCloud() pcd = o3d.io.read_point_cloud(eagle.path) R = pcd.get_rotation_matrix_from_xyz((np.pi, -np.pi / 4, 0)) pcd.rotate(R, center=(0, 0, 0)) print('Displaying input pointcloud ...') o3d.visualization.draw([pcd]) print('Running Poisson surface reconstruction ...') mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson( pcd, depth=9) print('Displaying reconstructed mesh ...') o3d.visualization.draw([mesh]) |
triangle_mesh_normal_estimation.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import open3d as o3d import numpy as np if __name__ == "__main__": knot_mesh = o3d.data.KnotMesh() mesh = o3d.io.read_triangle_mesh(knot_mesh.path) print("Displaying mesh without normals ...") # Invalidate existing normals. mesh.triangle_normals = o3d.utility.Vector3dVector(np.zeros((1, 3))) print("normals: \n", np.asarray(mesh.triangle_normals)) o3d.visualization.draw([mesh]) print("Computing normals and rendering it ...") mesh.compute_vertex_normals() print("normals: \n", np.asarray(mesh.triangle_normals)) o3d.visualization.draw([mesh]) |
triangle_mesh_properties.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | import open3d as o3d import numpy as np import os import sys pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(pyexample_path) import open3d_example as o3dex def check_properties(name, mesh): mesh.compute_vertex_normals() edge_manifold = mesh.is_edge_manifold(allow_boundary_edges=True) edge_manifold_boundary = mesh.is_edge_manifold(allow_boundary_edges=False) vertex_manifold = mesh.is_vertex_manifold() self_intersecting = mesh.is_self_intersecting() watertight = mesh.is_watertight() orientable = mesh.is_orientable() print(name) print(f" edge_manifold: {edge_manifold}") print(f" edge_manifold_boundary: {edge_manifold_boundary}") print(f" vertex_manifold: {vertex_manifold}") print(f" self_intersecting: {self_intersecting}") print(f" watertight: {watertight}") print(f" orientable: {orientable}") geoms = [mesh] if not edge_manifold: edges = mesh.get_non_manifold_edges(allow_boundary_edges=True) geoms.append(o3dex.edges_to_lineset(mesh, edges, (1, 0, 0))) if not edge_manifold_boundary: edges = mesh.get_non_manifold_edges(allow_boundary_edges=False) geoms.append(o3dex.edges_to_lineset(mesh, edges, (0, 1, 0))) if not vertex_manifold: verts = np.asarray(mesh.get_non_manifold_vertices()) pcl = o3d.geometry.PointCloud( points=o3d.utility.Vector3dVector(np.asarray(mesh.vertices)[verts])) pcl.paint_uniform_color((0, 0, 1)) geoms.append(pcl) if self_intersecting: intersecting_triangles = np.asarray( mesh.get_self_intersecting_triangles()) intersecting_triangles = intersecting_triangles[0:1] intersecting_triangles = np.unique(intersecting_triangles) print(" # visualize self-intersecting triangles") triangles = np.asarray(mesh.triangles)[intersecting_triangles] edges = [ np.vstack((triangles[:, i], triangles[:, j])) for i, j in [(0, 1), (1, 2), (2, 0)] ] edges = np.hstack(edges).T edges = o3d.utility.Vector2iVector(edges) geoms.append(o3dex.edges_to_lineset(mesh, edges, (1, 0, 1))) o3d.visualization.draw_geometries(geoms, mesh_show_back_face=True) if __name__ == "__main__": knot_mesh = o3d.data.KnotMesh() mesh = o3d.io.read_triangle_mesh(knot_mesh.path) check_properties('KnotMesh', mesh) check_properties('Mobius', o3d.geometry.TriangleMesh.create_mobius(twists=1)) check_properties("non-manifold edge", o3dex.get_non_manifold_edge_mesh()) check_properties("non-manifold vertex", o3dex.get_non_manifold_vertex_mesh()) check_properties("open box", o3dex.get_open_box_mesh()) check_properties("intersecting_boxes", o3dex.get_intersecting_boxes_mesh()) |
triangle_mesh_sampling.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import open3d as o3d if __name__ == "__main__": bunny = o3d.data.BunnyMesh() mesh = o3d.io.read_triangle_mesh(bunny.path) mesh.compute_vertex_normals() print("Displaying input mesh ...") o3d.visualization.draw([mesh]) print("Displaying pointcloud using uniform sampling ...") pcd = mesh.sample_points_uniformly(number_of_points=1000) o3d.visualization.draw([pcd], point_size=5) print("Displaying pointcloud using Poisson disk sampling ...") pcd = mesh.sample_points_poisson_disk(number_of_points=1000, init_factor=5) o3d.visualization.draw([pcd], point_size=5) |
triangle_mesh_simplification_decimation.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | import open3d as o3d if __name__ == "__main__": bunny = o3d.data.BunnyMesh() mesh_in = o3d.io.read_triangle_mesh(bunny.path) mesh_in.compute_vertex_normals() print("Before Simplification: ", mesh_in) o3d.visualization.draw_geometries([mesh_in]) mesh_smp = mesh_in.simplify_quadric_decimation( target_number_of_triangles=6500) print("After Simplification target number of triangles = 6500:\n", mesh_smp) o3d.visualization.draw_geometries([mesh_smp]) mesh_smp = mesh_in.simplify_quadric_decimation( target_number_of_triangles=1700) print("After Simplification target number of triangles = 1700:\n", mesh_smp) o3d.visualization.draw_geometries([mesh_smp]) |
triangle_mesh_simplification_vertex_clustering.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import open3d as o3d if __name__ == "__main__": bunny = o3d.data.BunnyMesh() mesh_in = o3d.io.read_triangle_mesh(bunny.path) mesh_in.compute_vertex_normals() print("Before Simplification: ", mesh_in) o3d.visualization.draw_geometries([mesh_in]) voxel_size = max(mesh_in.get_max_bound() - mesh_in.get_min_bound()) / 32 mesh_smp = mesh_in.simplify_vertex_clustering( voxel_size=voxel_size, contraction=o3d.geometry.SimplificationContraction.Average) print("After Simplification with voxel size =", voxel_size, ":\n", mesh_smp) o3d.visualization.draw_geometries([mesh_smp]) voxel_size = max(mesh_in.get_max_bound() - mesh_in.get_min_bound()) / 16 mesh_smp = mesh_in.simplify_vertex_clustering( voxel_size=voxel_size, contraction=o3d.geometry.SimplificationContraction.Average) print("After Simplification with voxel size =", voxel_size, ":\n", mesh_smp) o3d.visualization.draw_geometries([mesh_smp]) |
triangle_mesh_subdivision.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 | import open3d as o3d if __name__ == "__main__": knot_mesh = o3d.data.KnotMesh() mesh = o3d.io.read_triangle_mesh(knot_mesh.path) mesh.compute_vertex_normals() print("Before Subdivision: ", mesh) print("Displaying input mesh ...") o3d.visualization.draw_geometries([mesh], mesh_show_wireframe=True) mesh = mesh.subdivide_loop(number_of_iterations=1) print("After Subdivision: ", mesh) print("Displaying subdivided mesh ...") o3d.visualization.draw_geometries([mesh], mesh_show_wireframe=True) |
triangle_mesh_transformation.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | import open3d as o3d import numpy as np import copy def translate(): mesh = o3d.geometry.TriangleMesh.create_coordinate_frame() mesh_tx = copy.deepcopy(mesh).translate((1.3, 0, 0)) mesh_ty = copy.deepcopy(mesh).translate((0, 1.3, 0)) print('Displaying original and translated geometries ...') o3d.visualization.draw([{ "name": "Original Geometry", "geometry": mesh }, { "name": "Translated (in X) Geometry", "geometry": mesh_tx }, { "name": "Translated (in Y) Geometry", "geometry": mesh_ty }], show_ui=True) def rotate(): mesh = o3d.geometry.TriangleMesh.create_coordinate_frame() mesh_r = copy.deepcopy(mesh) R = mesh.get_rotation_matrix_from_xyz((np.pi / 2, 0, np.pi / 4)) mesh_r.rotate(R, center=(0, 0, 0)) print('Displaying original and rotated geometries ...') o3d.visualization.draw([{ "name": "Original Geometry", "geometry": mesh }, { "name": "Rotated Geometry", "geometry": mesh_r }], show_ui=True) def scale(): mesh = o3d.geometry.TriangleMesh.create_coordinate_frame() mesh_s = copy.deepcopy(mesh).translate((2, 0, 0)) mesh_s.scale(0.5, center=mesh_s.get_center()) print('Displaying original and scaled geometries ...') o3d.visualization.draw([{ "name": "Original Geometry", "geometry": mesh }, { "name": "Scaled Geometry", "geometry": mesh_s }], show_ui=True) def transform(): mesh = o3d.geometry.TriangleMesh.create_coordinate_frame() T = np.eye(4) T[:3, :3] = mesh.get_rotation_matrix_from_xyz((0, np.pi / 3, np.pi / 2)) T[0, 3] = 1 T[1, 3] = 1.3 print(T) mesh_t = copy.deepcopy(mesh).transform(T) print('Displaying original and transformed geometries ...') o3d.visualization.draw([{ "name": "Original Geometry", "geometry": mesh }, { "name": "Transformed Geometry", "geometry": mesh_t }], show_ui=True) if __name__ == "__main__": translate() rotate() scale() transform() |
triangle_mesh_with_numpy.py¶
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | import open3d as o3d import numpy as np if __name__ == "__main__": # Read a mesh and get its data as numpy arrays. knot_mesh = o3d.data.KnotMesh() mesh = o3d.io.read_triangle_mesh(knot_mesh.path) mesh.paint_uniform_color([0.5, 0.1, 0.3]) print('Vertices:') print(np.asarray(mesh.vertices)) print('Vertex Colors:') print(np.asarray(mesh.vertex_colors)) print('Vertex Normals:') print(np.asarray(mesh.vertex_normals)) print('Triangles:') print(np.asarray(mesh.triangles)) print('Triangle Normals:') print(np.asarray(mesh.triangle_normals)) print("Displaying mesh ...") print(mesh) o3d.visualization.draw([mesh]) # Create a mesh using numpy arrays with random colors. N = 5 vertices = o3d.utility.Vector3dVector( np.array([[0, 0, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0.5, 0.5, 0.5]])) triangles = o3d.utility.Vector3iVector( np.array([[0, 1, 2], [0, 2, 3], [0, 4, 1], [1, 4, 2], [2, 4, 3], [3, 4, 0]])) mesh_np = o3d.geometry.TriangleMesh(vertices, triangles) mesh_np.vertex_colors = o3d.utility.Vector3dVector( np.random.uniform(0, 1, size=(N, 3))) mesh_np.compute_vertex_normals() print(np.asarray(mesh_np.triangle_normals)) print("Displaying mesh made using numpy ...") o3d.visualization.draw_geometries([mesh_np]) |