Triangle Mesh

triangle_mesh_connected_components.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28import numpy as np
29import copy
30
31if __name__ == "__main__":
32    bunny = o3d.data.BunnyMesh()
33    mesh = o3d.io.read_triangle_mesh(bunny.path)
34    mesh.compute_vertex_normals()
35
36    mesh = mesh.subdivide_midpoint(number_of_iterations=2)
37    vert = np.asarray(mesh.vertices)
38    min_vert, max_vert = vert.min(axis=0), vert.max(axis=0)
39    for _ in range(30):
40        cube = o3d.geometry.TriangleMesh.create_box()
41        cube.scale(0.005, center=cube.get_center())
42        cube.translate(
43            (
44                np.random.uniform(min_vert[0], max_vert[0]),
45                np.random.uniform(min_vert[1], max_vert[1]),
46                np.random.uniform(min_vert[2], max_vert[2]),
47            ),
48            relative=False,
49        )
50        mesh += cube
51    mesh.compute_vertex_normals()
52    print("Displaying input mesh ...")
53    o3d.visualization.draw([mesh])
54
55    print("Clustering connected triangles ...")
56    with o3d.utility.VerbosityContextManager(
57            o3d.utility.VerbosityLevel.Debug) as cm:
58        triangle_clusters, cluster_n_triangles, cluster_area = (
59            mesh.cluster_connected_triangles())
60    triangle_clusters = np.asarray(triangle_clusters)
61    cluster_n_triangles = np.asarray(cluster_n_triangles)
62    cluster_area = np.asarray(cluster_area)
63
64    print("Displaying mesh with small clusters removed ...")
65    mesh_0 = copy.deepcopy(mesh)
66    triangles_to_remove = cluster_n_triangles[triangle_clusters] < 100
67    mesh_0.remove_triangles_by_mask(triangles_to_remove)
68    o3d.visualization.draw([mesh_0])

triangle_mesh_cropping.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28import numpy as np
29import copy
30
31if __name__ == "__main__":
32    knot_mesh = o3d.data.KnotMesh()
33    mesh = o3d.io.read_triangle_mesh(knot_mesh.path)
34    mesh.compute_vertex_normals()
35    print("Displaying original mesh ...")
36    o3d.visualization.draw([mesh])
37
38    print("Displaying mesh of only the first half triangles ...")
39    mesh_cropped = copy.deepcopy(mesh)
40    mesh_cropped.triangles = o3d.utility.Vector3iVector(
41        np.asarray(mesh_cropped.triangles)[:len(mesh_cropped.triangles) //
42                                           2, :])
43    mesh_cropped.triangle_normals = o3d.utility.Vector3dVector(
44        np.asarray(mesh_cropped.triangle_normals)
45        [:len(mesh_cropped.triangle_normals) // 2, :])
46    print(mesh_cropped.triangles)
47    o3d.visualization.draw([mesh_cropped])

triangle_mesh_deformation.py

  1# ----------------------------------------------------------------------------
  2# -                        Open3D: www.open3d.org                            -
  3# ----------------------------------------------------------------------------
  4# The MIT License (MIT)
  5#
  6# Copyright (c) 2018-2021 www.open3d.org
  7#
  8# Permission is hereby granted, free of charge, to any person obtaining a copy
  9# of this software and associated documentation files (the "Software"), to deal
 10# in the Software without restriction, including without limitation the rights
 11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12# copies of the Software, and to permit persons to whom the Software is
 13# furnished to do so, subject to the following conditions:
 14#
 15# The above copyright notice and this permission notice shall be included in
 16# all copies or substantial portions of the Software.
 17#
 18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 24# IN THE SOFTWARE.
 25# ----------------------------------------------------------------------------
 26
 27import numpy as np
 28import open3d as o3d
 29import time
 30import os
 31import sys
 32
 33pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 34sys.path.append(pyexample_path)
 35
 36import open3d_example as o3dex
 37
 38
 39def problem0():
 40    mesh = o3dex.get_plane_mesh(height=1, width=1)
 41    mesh = mesh.subdivide_midpoint(3)
 42    vertices = np.asarray(mesh.vertices)
 43    static_ids = [
 44        1, 46, 47, 48, 16, 51, 49, 50, 6, 31, 33, 32, 11, 26, 27, 25, 0, 64, 65,
 45        20, 66, 68, 67, 7, 69, 71, 70, 22, 72, 74, 73, 3, 15, 44, 43, 45, 5, 41,
 46        40, 42, 13, 39, 37, 38, 2, 56, 55, 19, 61, 60, 59, 8, 76, 75, 77, 23
 47    ]
 48    static_positions = []
 49    for id in static_ids:
 50        static_positions.append(vertices[id])
 51    handle_ids = [4]
 52    handle_positions = [vertices[4] + np.array((0, 0, 0.4))]
 53
 54    return mesh, static_ids + handle_ids, static_positions + handle_positions
 55
 56
 57def problem1():
 58    mesh = o3dex.get_plane_mesh(height=1, width=1)
 59    mesh = mesh.subdivide_midpoint(3)
 60    vertices = np.asarray(mesh.vertices)
 61    static_ids = [
 62        1, 46, 15, 43, 5, 40, 13, 38, 2, 56, 37, 39, 42, 41, 45, 44, 48, 47
 63    ]
 64    static_positions = []
 65    for id in static_ids:
 66        static_positions.append(vertices[id])
 67    handle_ids = [21]
 68    handle_positions = [vertices[21] + np.array((0, 0, 0.4))]
 69
 70    return mesh, static_ids + handle_ids, static_positions + handle_positions
 71
 72
 73def problem2():
 74    armadillo_data = o3d.data.ArmadilloMesh()
 75    mesh = o3d.io.read_triangle_mesh(armadillo_data.path)
 76    vertices = np.asarray(mesh.vertices)
 77    static_ids = [idx for idx in np.where(vertices[:, 1] < -30)[0]]
 78    static_positions = []
 79    for id in static_ids:
 80        static_positions.append(vertices[id])
 81    handle_ids = [2490]
 82    handle_positions = [vertices[2490] + np.array((-40, -40, -40))]
 83
 84    return mesh, static_ids + handle_ids, static_positions + handle_positions
 85
 86
 87if __name__ == "__main__":
 88    o3d.utility.set_verbosity_level(o3d.utility.Debug)
 89
 90    for mesh, constraint_ids, constraint_pos in [
 91            problem0(), problem1(), problem2()
 92    ]:
 93        constraint_ids = np.array(constraint_ids, dtype=np.int32)
 94        constraint_pos = o3d.utility.Vector3dVector(constraint_pos)
 95        tic = time.time()
 96        mesh_prime = mesh.deform_as_rigid_as_possible(
 97            o3d.utility.IntVector(constraint_ids), constraint_pos, max_iter=50)
 98        print("deform took {}[s]".format(time.time() - tic))
 99        mesh_prime.compute_vertex_normals()
100
101        mesh.paint_uniform_color((1, 0, 0))
102        handles = o3d.geometry.PointCloud()
103        handles.points = constraint_pos
104        handles.paint_uniform_color((0, 1, 0))
105        o3d.visualization.draw_geometries([mesh, mesh_prime, handles])
106
107    o3d.utility.set_verbosity_level(o3d.utility.Info)

triangle_mesh_filtering_average.py

  1# ----------------------------------------------------------------------------
  2# -                        Open3D: www.open3d.org                            -
  3# ----------------------------------------------------------------------------
  4# The MIT License (MIT)
  5#
  6# Copyright (c) 2018-2021 www.open3d.org
  7#
  8# Permission is hereby granted, free of charge, to any person obtaining a copy
  9# of this software and associated documentation files (the "Software"), to deal
 10# in the Software without restriction, including without limitation the rights
 11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12# copies of the Software, and to permit persons to whom the Software is
 13# furnished to do so, subject to the following conditions:
 14#
 15# The above copyright notice and this permission notice shall be included in
 16# all copies or substantial portions of the Software.
 17#
 18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 24# IN THE SOFTWARE.
 25# ----------------------------------------------------------------------------
 26
 27from numpy.random.mtrand import laplace
 28import open3d as o3d
 29import numpy as np
 30
 31
 32def average_filtering():
 33    # Create noisy mesh.
 34    knot_mesh = o3d.data.KnotMesh()
 35    mesh_in = o3d.io.read_triangle_mesh(knot_mesh.path)
 36    vertices = np.asarray(mesh_in.vertices)
 37    noise = 5
 38    vertices += np.random.uniform(0, noise, size=vertices.shape)
 39    mesh_in.vertices = o3d.utility.Vector3dVector(vertices)
 40    mesh_in.compute_vertex_normals()
 41    print("Displaying input mesh ...")
 42    o3d.visualization.draw_geometries([mesh_in])
 43
 44    print("Displaying output of average mesh filter after 1 iteration ...")
 45    mesh_out = mesh_in.filter_smooth_simple(number_of_iterations=1)
 46    mesh_out.compute_vertex_normals()
 47    o3d.visualization.draw_geometries([mesh_out])
 48
 49    print("Displaying output of average mesh filter after 5 iteration ...")
 50    mesh_out = mesh_in.filter_smooth_simple(number_of_iterations=5)
 51    mesh_out.compute_vertex_normals()
 52    o3d.visualization.draw_geometries([mesh_out])
 53
 54
 55def laplace_filtering():
 56    # Create noisy mesh.
 57    knot_mesh = o3d.data.KnotMesh()
 58    mesh_in = o3d.io.read_triangle_mesh(knot_mesh.path)
 59    vertices = np.asarray(mesh_in.vertices)
 60    noise = 5
 61    vertices += np.random.uniform(0, noise, size=vertices.shape)
 62    mesh_in.vertices = o3d.utility.Vector3dVector(vertices)
 63    mesh_in.compute_vertex_normals()
 64    print("Displaying input mesh ...")
 65    o3d.visualization.draw_geometries([mesh_in])
 66
 67    print("Displaying output of Laplace mesh filter after 10 iteration ...")
 68    mesh_out = mesh_in.filter_smooth_laplacian(number_of_iterations=10)
 69    mesh_out.compute_vertex_normals()
 70    o3d.visualization.draw_geometries([mesh_out])
 71
 72    print("Displaying output of Laplace mesh filter after 50 iteration ...")
 73    mesh_out = mesh_in.filter_smooth_laplacian(number_of_iterations=50)
 74    mesh_out.compute_vertex_normals()
 75    o3d.visualization.draw_geometries([mesh_out])
 76
 77
 78def taubin_filtering():
 79    # Create noisy mesh.
 80    knot_mesh = o3d.data.KnotMesh()
 81    mesh_in = o3d.io.read_triangle_mesh(knot_mesh.path)
 82    vertices = np.asarray(mesh_in.vertices)
 83    noise = 5
 84    vertices += np.random.uniform(0, noise, size=vertices.shape)
 85    mesh_in.vertices = o3d.utility.Vector3dVector(vertices)
 86    mesh_in.compute_vertex_normals()
 87    print("Displaying input mesh ...")
 88    o3d.visualization.draw_geometries([mesh_in])
 89
 90    print("Displaying output of Taubin mesh filter after 10 iteration ...")
 91    mesh_out = mesh_in.filter_smooth_taubin(number_of_iterations=10)
 92    mesh_out.compute_vertex_normals()
 93    o3d.visualization.draw_geometries([mesh_out])
 94
 95    print("Displaying output of Taubin mesh filter after 100 iteration ...")
 96    mesh_out = mesh_in.filter_smooth_taubin(number_of_iterations=100)
 97    mesh_out.compute_vertex_normals()
 98    o3d.visualization.draw_geometries([mesh_out])
 99
100
101if __name__ == "__main__":
102    average_filtering()
103    laplace_filtering()
104    taubin_filtering()

triangle_mesh_from_point_cloud_alpha_shapes.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28
29if __name__ == "__main__":
30    bunny = o3d.data.BunnyMesh()
31    mesh = o3d.io.read_triangle_mesh(bunny.path)
32    mesh.compute_vertex_normals()
33
34    pcd = mesh.sample_points_poisson_disk(750)
35    print("Displaying input pointcloud ...")
36    o3d.visualization.draw_geometries([pcd])
37    alpha = 0.03
38    print(f"alpha={alpha:.3f}")
39    print('Running alpha shapes surface reconstruction ...')
40    mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(
41        pcd, alpha)
42    mesh.compute_triangle_normals(normalized=True)
43    print("Displaying reconstructed mesh ...")
44    o3d.visualization.draw_geometries([mesh], mesh_show_back_face=True)

triangle_mesh_from_point_cloud_ball_pivoting.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28
29if __name__ == "__main__":
30    bunny = o3d.data.BunnyMesh()
31    gt_mesh = o3d.io.read_triangle_mesh(bunny.path)
32    gt_mesh.compute_vertex_normals()
33
34    pcd = gt_mesh.sample_points_poisson_disk(3000)
35    print("Displaying input pointcloud ...")
36    o3d.visualization.draw([pcd], point_size=5)
37
38    radii = [0.005, 0.01, 0.02, 0.04]
39    print('Running ball pivoting surface reconstruction ...')
40    rec_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(
41        pcd, o3d.utility.DoubleVector(radii))
42    print("Displaying reconstructed mesh ...")
43    o3d.visualization.draw([rec_mesh])

triangle_mesh_from_point_cloud_poisson.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28import numpy as np
29
30if __name__ == "__main__":
31    eagle = o3d.data.EaglePointCloud()
32    pcd = o3d.io.read_point_cloud(eagle.path)
33    R = pcd.get_rotation_matrix_from_xyz((np.pi, -np.pi / 4, 0))
34    pcd.rotate(R, center=(0, 0, 0))
35    print('Displaying input pointcloud ...')
36    o3d.visualization.draw([pcd])
37
38    print('Running Poisson surface reconstruction ...')
39    mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
40        pcd, depth=9)
41    print('Displaying reconstructed mesh ...')
42    o3d.visualization.draw([mesh])

triangle_mesh_normal_estimation.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28import numpy as np
29
30if __name__ == "__main__":
31    knot_mesh = o3d.data.KnotMesh()
32    mesh = o3d.io.read_triangle_mesh(knot_mesh.path)
33    print("Displaying mesh without normals ...")
34    # Invalidate existing normals.
35    mesh.triangle_normals = o3d.utility.Vector3dVector(np.zeros((1, 3)))
36    print("normals: \n", np.asarray(mesh.triangle_normals))
37    o3d.visualization.draw([mesh])
38
39    print("Computing normals and rendering it ...")
40    mesh.compute_vertex_normals()
41    print("normals: \n", np.asarray(mesh.triangle_normals))
42    o3d.visualization.draw([mesh])

triangle_mesh_properties.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28import numpy as np
29import os
30import sys
31
32pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
33sys.path.append(pyexample_path)
34
35import open3d_example as o3dex
36
37
38def check_properties(name, mesh):
39    mesh.compute_vertex_normals()
40
41    edge_manifold = mesh.is_edge_manifold(allow_boundary_edges=True)
42    edge_manifold_boundary = mesh.is_edge_manifold(allow_boundary_edges=False)
43    vertex_manifold = mesh.is_vertex_manifold()
44    self_intersecting = mesh.is_self_intersecting()
45    watertight = mesh.is_watertight()
46    orientable = mesh.is_orientable()
47
48    print(name)
49    print(f"  edge_manifold:          {edge_manifold}")
50    print(f"  edge_manifold_boundary: {edge_manifold_boundary}")
51    print(f"  vertex_manifold:        {vertex_manifold}")
52    print(f"  self_intersecting:      {self_intersecting}")
53    print(f"  watertight:             {watertight}")
54    print(f"  orientable:             {orientable}")
55
56    geoms = [mesh]
57    if not edge_manifold:
58        edges = mesh.get_non_manifold_edges(allow_boundary_edges=True)
59        geoms.append(o3dex.edges_to_lineset(mesh, edges, (1, 0, 0)))
60    if not edge_manifold_boundary:
61        edges = mesh.get_non_manifold_edges(allow_boundary_edges=False)
62        geoms.append(o3dex.edges_to_lineset(mesh, edges, (0, 1, 0)))
63    if not vertex_manifold:
64        verts = np.asarray(mesh.get_non_manifold_vertices())
65        pcl = o3d.geometry.PointCloud(
66            points=o3d.utility.Vector3dVector(np.asarray(mesh.vertices)[verts]))
67        pcl.paint_uniform_color((0, 0, 1))
68        geoms.append(pcl)
69    if self_intersecting:
70        intersecting_triangles = np.asarray(
71            mesh.get_self_intersecting_triangles())
72        intersecting_triangles = intersecting_triangles[0:1]
73        intersecting_triangles = np.unique(intersecting_triangles)
74        print("  # visualize self-intersecting triangles")
75        triangles = np.asarray(mesh.triangles)[intersecting_triangles]
76        edges = [
77            np.vstack((triangles[:, i], triangles[:, j]))
78            for i, j in [(0, 1), (1, 2), (2, 0)]
79        ]
80        edges = np.hstack(edges).T
81        edges = o3d.utility.Vector2iVector(edges)
82        geoms.append(o3dex.edges_to_lineset(mesh, edges, (1, 0, 1)))
83    o3d.visualization.draw_geometries(geoms, mesh_show_back_face=True)
84
85
86if __name__ == "__main__":
87    knot_mesh = o3d.data.KnotMesh()
88    mesh = o3d.io.read_triangle_mesh(knot_mesh.path)
89    check_properties('KnotMesh', mesh)
90    check_properties('Mobius',
91                     o3d.geometry.TriangleMesh.create_mobius(twists=1))
92    check_properties("non-manifold edge", o3dex.get_non_manifold_edge_mesh())
93    check_properties("non-manifold vertex",
94                     o3dex.get_non_manifold_vertex_mesh())
95    check_properties("open box", o3dex.get_open_box_mesh())
96    check_properties("intersecting_boxes", o3dex.get_intersecting_boxes_mesh())

triangle_mesh_sampling.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28
29if __name__ == "__main__":
30    bunny = o3d.data.BunnyMesh()
31    mesh = o3d.io.read_triangle_mesh(bunny.path)
32    mesh.compute_vertex_normals()
33
34    print("Displaying input mesh ...")
35    o3d.visualization.draw([mesh])
36
37    print("Displaying pointcloud using uniform sampling ...")
38    pcd = mesh.sample_points_uniformly(number_of_points=1000)
39    o3d.visualization.draw([pcd], point_size=5)
40
41    print("Displaying pointcloud using Poisson disk sampling ...")
42    pcd = mesh.sample_points_poisson_disk(number_of_points=1000, init_factor=5)
43    o3d.visualization.draw([pcd], point_size=5)

triangle_mesh_simplification_decimation.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28
29if __name__ == "__main__":
30    bunny = o3d.data.BunnyMesh()
31    mesh_in = o3d.io.read_triangle_mesh(bunny.path)
32    mesh_in.compute_vertex_normals()
33
34    print("Before Simplification: ", mesh_in)
35    o3d.visualization.draw_geometries([mesh_in])
36
37    mesh_smp = mesh_in.simplify_quadric_decimation(
38        target_number_of_triangles=6500)
39    print("After Simplification target number of triangles = 6500:\n", mesh_smp)
40    o3d.visualization.draw_geometries([mesh_smp])
41
42    mesh_smp = mesh_in.simplify_quadric_decimation(
43        target_number_of_triangles=1700)
44    print("After Simplification target number of triangles = 1700:\n", mesh_smp)
45    o3d.visualization.draw_geometries([mesh_smp])

triangle_mesh_simplification_vertex_clustering.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28
29if __name__ == "__main__":
30    bunny = o3d.data.BunnyMesh()
31    mesh_in = o3d.io.read_triangle_mesh(bunny.path)
32    mesh_in.compute_vertex_normals()
33
34    print("Before Simplification: ", mesh_in)
35    o3d.visualization.draw_geometries([mesh_in])
36
37    voxel_size = max(mesh_in.get_max_bound() - mesh_in.get_min_bound()) / 32
38    mesh_smp = mesh_in.simplify_vertex_clustering(
39        voxel_size=voxel_size,
40        contraction=o3d.geometry.SimplificationContraction.Average)
41    print("After Simplification with voxel size =", voxel_size, ":\n", mesh_smp)
42    o3d.visualization.draw_geometries([mesh_smp])
43
44    voxel_size = max(mesh_in.get_max_bound() - mesh_in.get_min_bound()) / 16
45    mesh_smp = mesh_in.simplify_vertex_clustering(
46        voxel_size=voxel_size,
47        contraction=o3d.geometry.SimplificationContraction.Average)
48    print("After Simplification with voxel size =", voxel_size, ":\n", mesh_smp)
49    o3d.visualization.draw_geometries([mesh_smp])

triangle_mesh_subdivision.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28
29if __name__ == "__main__":
30    knot_mesh = o3d.data.KnotMesh()
31    mesh = o3d.io.read_triangle_mesh(knot_mesh.path)
32    mesh.compute_vertex_normals()
33    print("Before Subdivision: ", mesh)
34    print("Displaying input mesh ...")
35    o3d.visualization.draw_geometries([mesh], mesh_show_wireframe=True)
36    mesh = mesh.subdivide_loop(number_of_iterations=1)
37    print("After Subdivision: ", mesh)
38    print("Displaying subdivided mesh ...")
39    o3d.visualization.draw_geometries([mesh], mesh_show_wireframe=True)

triangle_mesh_transformation.py

  1# ----------------------------------------------------------------------------
  2# -                        Open3D: www.open3d.org                            -
  3# ----------------------------------------------------------------------------
  4# The MIT License (MIT)
  5#
  6# Copyright (c) 2018-2021 www.open3d.org
  7#
  8# Permission is hereby granted, free of charge, to any person obtaining a copy
  9# of this software and associated documentation files (the "Software"), to deal
 10# in the Software without restriction, including without limitation the rights
 11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12# copies of the Software, and to permit persons to whom the Software is
 13# furnished to do so, subject to the following conditions:
 14#
 15# The above copyright notice and this permission notice shall be included in
 16# all copies or substantial portions of the Software.
 17#
 18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 24# IN THE SOFTWARE.
 25# ----------------------------------------------------------------------------
 26
 27import open3d as o3d
 28import numpy as np
 29import copy
 30
 31
 32def translate():
 33    mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()
 34    mesh_tx = copy.deepcopy(mesh).translate((1.3, 0, 0))
 35    mesh_ty = copy.deepcopy(mesh).translate((0, 1.3, 0))
 36    print('Displaying original and translated geometries ...')
 37    o3d.visualization.draw([{
 38        "name": "Original Geometry",
 39        "geometry": mesh
 40    }, {
 41        "name": "Translated (in X) Geometry",
 42        "geometry": mesh_tx
 43    }, {
 44        "name": "Translated (in Y) Geometry",
 45        "geometry": mesh_ty
 46    }],
 47                           show_ui=True)
 48
 49
 50def rotate():
 51    mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()
 52    mesh_r = copy.deepcopy(mesh)
 53    R = mesh.get_rotation_matrix_from_xyz((np.pi / 2, 0, np.pi / 4))
 54    mesh_r.rotate(R, center=(0, 0, 0))
 55    print('Displaying original and rotated geometries ...')
 56    o3d.visualization.draw([{
 57        "name": "Original Geometry",
 58        "geometry": mesh
 59    }, {
 60        "name": "Rotated Geometry",
 61        "geometry": mesh_r
 62    }],
 63                           show_ui=True)
 64
 65
 66def scale():
 67    mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()
 68    mesh_s = copy.deepcopy(mesh).translate((2, 0, 0))
 69    mesh_s.scale(0.5, center=mesh_s.get_center())
 70    print('Displaying original and scaled geometries ...')
 71    o3d.visualization.draw([{
 72        "name": "Original Geometry",
 73        "geometry": mesh
 74    }, {
 75        "name": "Scaled Geometry",
 76        "geometry": mesh_s
 77    }],
 78                           show_ui=True)
 79
 80
 81def transform():
 82    mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()
 83    T = np.eye(4)
 84    T[:3, :3] = mesh.get_rotation_matrix_from_xyz((0, np.pi / 3, np.pi / 2))
 85    T[0, 3] = 1
 86    T[1, 3] = 1.3
 87    print(T)
 88    mesh_t = copy.deepcopy(mesh).transform(T)
 89    print('Displaying original and transformed geometries ...')
 90    o3d.visualization.draw([{
 91        "name": "Original Geometry",
 92        "geometry": mesh
 93    }, {
 94        "name": "Transformed Geometry",
 95        "geometry": mesh_t
 96    }],
 97                           show_ui=True)
 98
 99
100if __name__ == "__main__":
101
102    translate()
103    rotate()
104    scale()
105    transform()

triangle_mesh_with_numpy.py

 1# ----------------------------------------------------------------------------
 2# -                        Open3D: www.open3d.org                            -
 3# ----------------------------------------------------------------------------
 4# The MIT License (MIT)
 5#
 6# Copyright (c) 2018-2021 www.open3d.org
 7#
 8# Permission is hereby granted, free of charge, to any person obtaining a copy
 9# of this software and associated documentation files (the "Software"), to deal
10# in the Software without restriction, including without limitation the rights
11# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12# copies of the Software, and to permit persons to whom the Software is
13# furnished to do so, subject to the following conditions:
14#
15# The above copyright notice and this permission notice shall be included in
16# all copies or substantial portions of the Software.
17#
18# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24# IN THE SOFTWARE.
25# ----------------------------------------------------------------------------
26
27import open3d as o3d
28import numpy as np
29
30if __name__ == "__main__":
31    # Read a mesh and get its data as numpy arrays.
32    knot_mesh = o3d.data.KnotMesh()
33    mesh = o3d.io.read_triangle_mesh(knot_mesh.path)
34    mesh.paint_uniform_color([0.5, 0.1, 0.3])
35    print('Vertices:')
36    print(np.asarray(mesh.vertices))
37    print('Vertex Colors:')
38    print(np.asarray(mesh.vertex_colors))
39    print('Vertex Normals:')
40    print(np.asarray(mesh.vertex_normals))
41    print('Triangles:')
42    print(np.asarray(mesh.triangles))
43    print('Triangle Normals:')
44    print(np.asarray(mesh.triangle_normals))
45    print("Displaying mesh ...")
46    print(mesh)
47    o3d.visualization.draw([mesh])
48
49    # Create a mesh using numpy arrays with random colors.
50    N = 5
51    vertices = o3d.utility.Vector3dVector(
52        np.array([[0, 0, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0.5, 0.5, 0.5]]))
53    triangles = o3d.utility.Vector3iVector(
54        np.array([[0, 1, 2], [0, 2, 3], [0, 4, 1], [1, 4, 2], [2, 4, 3],
55                  [3, 4, 0]]))
56    mesh_np = o3d.geometry.TriangleMesh(vertices, triangles)
57    mesh_np.vertex_colors = o3d.utility.Vector3dVector(
58        np.random.uniform(0, 1, size=(N, 3)))
59    mesh_np.compute_vertex_normals()
60    print(np.asarray(mesh_np.triangle_normals))
61    print("Displaying mesh made using numpy ...")
62    o3d.visualization.draw_geometries([mesh_np])