Triangle Mesh#

triangle_mesh.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8# examples/Python/Basic/mesh.py
 9
10import copy
11import numpy as np
12import cloudViewer as cv3d
13
14if __name__ == "__main__":
15
16    print("Testing mesh in cloudViewer ...")
17    knot_data = cv3d.data.KnotMesh()
18    mesh = cv3d.io.read_triangle_mesh(knot_data.path)
19    mesh.compute_vertex_normals()
20    print(mesh)
21    print(np.asarray(mesh.get_vertices()))
22    print(np.asarray(mesh.get_triangles()))
23    print("")
24
25    # triangulation
26    # DELAUNAY_2D_AXIS_ALIGNED or DELAUNAY_2D_BEST_LS_PLANE.
27    triangulation_type = cv3d.geometry.DELAUNAY_2D_BEST_LS_PLANE
28    new_mesh = cv3d.geometry.ccMesh.triangulate(
29        cloud=mesh.get_associated_cloud(), type=triangulation_type)
30    new_mesh.compute_vertex_normals()
31    cv3d.visualization.draw_geometries([new_mesh])
32
33    # triangulation between with two polylines
34    cv3d.data.set_custom_downloads_prefix(
35        "https://github.com/Asher-1/cloudViewer_downloads/releases/download/")
36    polylines_data = cv3d.data.PolylinesModel()
37    entity = cv3d.io.read_entity(polylines_data.path)
38    polylines = entity.filter_children(recursive=False,
39                                       filter=cv3d.geometry.ccHObject.POLY_LINE)
40    print(polylines)
41    assert len(polylines) > 1
42    mesh_polys = cv3d.geometry.ccMesh.triangulate_two_polylines(
43        poly1=polylines[0], poly2=polylines[1])
44    mesh_polys.compute_vertex_normals()
45    cv3d.visualization.draw_geometries(polylines + [mesh_polys])
46
47    print("Try to render a mesh with normals (exist: " +
48          str(mesh.has_vertex_normals()) + ") and colors (exist: " +
49          str(mesh.has_vertex_colors()) + ")")
50    mesh.set_temp_color([0, 0, 1])
51    mesh.set_opacity(0.5)
52    mesh.show_colors(True)
53    cv3d.visualization.draw_geometries([mesh])
54    print("A mesh with no normals and no colors does not seem good.")
55
56    print("Computing normal and rendering it.")
57    mesh.compute_vertex_normals()
58    print(np.asarray(mesh.get_triangle_normals()))
59    cv3d.visualization.draw_geometries([mesh])
60
61    print("We make a partial mesh of only the first half triangles.")
62    mesh1 = copy.deepcopy(mesh)
63    triangles = np.asarray(mesh1.get_triangles())
64    triangle_normals = np.asarray(mesh1.get_triangle_normals())
65    mesh1.set_triangles(
66        cv3d.utility.Vector3iVector(triangles[:len(triangles) // 2, :]))
67    mesh1.set_triangle_normals(
68        cv3d.utility.Vector3dVector(triangle_normals[:len(triangle_normals) //
69                                                     2, :]))
70    print(mesh1.get_triangles())
71    cv3d.visualization.draw_geometries([mesh1])
72
73    print("Painting the mesh")
74    mesh1.paint_uniform_color([1, 0.706, 0])
75    cv3d.visualization.draw_geometries([mesh1])

triangle_mesh_collision.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import numpy as np
 9import cloudViewer as cv3d
10import time
11
12import os
13import sys
14
15if __name__ == "__main__":
16    # intersection tests
17    print("#" * 80)
18    print("Intersection tests")
19    print("#" * 80)
20    np.random.seed(30)
21    bbox = cv3d.geometry.ccMesh.create_box(20, 20, 20).translate(
22        (-10, -10, -10))
23    meshes = [cv3d.geometry.ccMesh.create_box() for _ in range(20)]
24    meshes.append(cv3d.geometry.ccMesh.create_sphere())
25    meshes.append(cv3d.geometry.ccMesh.create_cone())
26    meshes.append(cv3d.geometry.ccMesh.create_torus())
27    dirs = [np.random.uniform(-0.1, 0.1, size=(3,)) for _ in meshes]
28    for mesh in meshes:
29        mesh.compute_vertex_normals()
30        mesh.paint_uniform_color((0.5, 0.5, 0.5))
31        mesh.translate(np.random.uniform(-7.5, 7.5, size=(3,)))
32    vis = cv3d.visualization.Visualizer()
33    vis.create_window()
34    for mesh in meshes:
35        vis.add_geometry(mesh)
36    for iter in range(1000):
37        for mesh, dir in zip(meshes, dirs):
38            mesh.paint_uniform_color((0.5, 0.5, 0.5))
39            mesh.translate(dir)
40        for idx0, mesh0 in enumerate(meshes):
41            collision = False
42            collision = collision or mesh0.is_intersecting(bbox)
43            for idx1, mesh1 in enumerate(meshes):
44                if collision:
45                    break
46                if idx0 == idx1:
47                    continue
48                collision = collision or mesh0.is_intersecting(mesh1)
49            if collision:
50                mesh0.paint_uniform_color((1, 0, 0))
51                dirs[idx0] *= -1
52            vis.update_geometry(mesh0)
53        vis.poll_events()
54        vis.update_renderer()
55        time.sleep(0.05)
56    vis.destroy_window()

triangle_mesh_connected_components.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8# examples/Python/Basic/mesh_connected_components.py
 9
10import cloudViewer as cv3d
11import numpy as np
12import copy
13import time
14
15if __name__ == "__main__":
16    cv3d.utility.set_verbosity_level(cv3d.utility.Debug)
17
18    print("Generate data")
19    bunny = cv3d.data.BunnyMesh()
20    mesh = cv3d.io.read_triangle_mesh(bunny.path)
21    mesh.compute_vertex_normals()
22
23    print("Subdivide mesh to make it a bit harder")
24    mesh = mesh.subdivide_midpoint(number_of_iterations=2)
25    print(mesh)
26
27    vert = np.asarray(mesh.get_vertices())
28    min_vert, max_vert = vert.min(axis=0), vert.max(axis=0)
29    for _ in range(30):
30        cube = cv3d.geometry.ccMesh.create_box()
31        cube.scale(0.005)
32        cube.translate(
33            (
34                np.random.uniform(min_vert[0], max_vert[0]),
35                np.random.uniform(min_vert[1], max_vert[1]),
36                np.random.uniform(min_vert[2], max_vert[2]),
37            ),
38            relative=False,
39        )
40        mesh += cube
41    mesh.compute_vertex_normals()
42    print("Displaying input mesh ...")
43    cv3d.visualization.draw([mesh])
44
45    print("Cluster connected triangles")
46    with cv3d.utility.VerbosityContextManager(
47            cv3d.utility.VerbosityLevel.Debug) as cm:
48        triangle_clusters, cluster_n_triangles, cluster_area = (
49            mesh.cluster_connected_triangles())
50    triangle_clusters = np.asarray(triangle_clusters)
51    cluster_n_triangles = np.asarray(cluster_n_triangles)
52    cluster_area = np.asarray(cluster_area)
53
54    print("Displaying mesh with small clusters removed ...")
55    mesh_0 = copy.deepcopy(mesh)
56    triangles_to_remove = cluster_n_triangles[triangle_clusters] < 100
57    mesh_0.remove_triangles_by_mask(triangles_to_remove)
58    cv3d.visualization.draw([mesh_0])

triangle_mesh_cropping.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8# examples/Python/Basic/mesh_filter.py
 9
10import numpy as np
11import cloudViewer as cv3d
12import copy
13
14if __name__ == "__main__":
15    knot_mesh = cv3d.data.KnotMesh()
16    mesh = cv3d.io.read_triangle_mesh(knot_mesh.path)
17    mesh.compute_vertex_normals()
18    print("Displaying original mesh ...")
19    cv3d.visualization.draw([mesh])
20
21    print("Displaying mesh of only the first half triangles ...")
22    mesh_cropped = copy.deepcopy(mesh)
23    mesh_cropped.set_triangles(
24        cv3d.utility.Vector3iVector(
25            np.asarray(
26                mesh_cropped.triangles())[:len(mesh_cropped.triangles()) //
27                                          2, :]))
28    mesh_cropped.set_triangle_normals(
29        cv3d.utility.Vector3dVector(
30            np.asarray(mesh_cropped.triangle_normals())
31            [:len(mesh_cropped.triangle_normals()) // 2, :]))
32    print(mesh_cropped.triangles())
33    cv3d.visualization.draw([mesh_cropped])

triangle_mesh_deformation.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import numpy as np
 9import cloudViewer as cv3d
10import time
11import os
12import sys
13
14pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
15sys.path.append(pyexample_path)
16
17import cloudViewer_example as cv3dex
18
19
20def problem0():
21    mesh = cv3dex.get_plane_mesh(height=1, width=1)
22    mesh = mesh.subdivide_midpoint(3)
23    vertices = np.asarray(mesh.vertices())
24    static_ids = [
25        1, 46, 47, 48, 16, 51, 49, 50, 6, 31, 33, 32, 11, 26, 27, 25, 0, 64, 65,
26        20, 66, 68, 67, 7, 69, 71, 70, 22, 72, 74, 73, 3, 15, 44, 43, 45, 5, 41,
27        40, 42, 13, 39, 37, 38, 2, 56, 55, 19, 61, 60, 59, 8, 76, 75, 77, 23
28    ]
29    static_positions = []
30    for id in static_ids:
31        static_positions.append(vertices[id])
32    handle_ids = [4]
33    handle_positions = [vertices[4] + np.array((0, 0, 0.4))]
34
35    return mesh, static_ids + handle_ids, static_positions + handle_positions
36
37
38def problem1():
39    mesh = cv3dex.get_plane_mesh(height=1, width=1)
40    mesh = mesh.subdivide_midpoint(3)
41    vertices = np.asarray(mesh.vertices())
42    static_ids = [
43        1, 46, 15, 43, 5, 40, 13, 38, 2, 56, 37, 39, 42, 41, 45, 44, 48, 47
44    ]
45    static_positions = []
46    for id in static_ids:
47        static_positions.append(vertices[id])
48    handle_ids = [21]
49    handle_positions = [vertices[21] + np.array((0, 0, 0.4))]
50
51    return mesh, static_ids + handle_ids, static_positions + handle_positions
52
53
54def problem2():
55    armadillo_data = cv3d.data.ArmadilloMesh()
56    mesh = cv3d.io.read_triangle_mesh(armadillo_data.path)
57    vertices = np.asarray(mesh.vertices())
58    static_ids = [idx for idx in np.where(vertices[:, 1] < -30)[0]]
59    static_positions = []
60    for id in static_ids:
61        static_positions.append(vertices[id])
62    handle_ids = [2490]
63    handle_positions = [vertices[2490] + np.array((-40, -40, -40))]
64
65    return mesh, static_ids + handle_ids, static_positions + handle_positions
66
67
68if __name__ == "__main__":
69    cv3d.utility.set_verbosity_level(cv3d.utility.Debug)
70
71    for mesh, constraint_ids, constraint_pos in [
72            problem0(), problem1(), problem2()
73    ]:
74        constraint_ids = np.array(constraint_ids, dtype=np.int32)
75        constraint_pos = cv3d.utility.Vector3dVector(constraint_pos)
76        tic = time.time()
77        mesh_prime = mesh.deform_as_rigid_as_possible(
78            cv3d.utility.IntVector(constraint_ids), constraint_pos, max_iter=50)
79        print("deform took {}[s]".format(time.time() - tic))
80        mesh_prime.compute_vertex_normals()
81
82        mesh.paint_uniform_color((1, 0, 0))
83        handles = cv3d.geometry.ccPointCloud()
84        handles.set_points(constraint_pos)
85        handles.paint_uniform_color((0, 1, 0))
86        cv3d.visualization.draw_geometries([mesh, mesh_prime, handles],
87                                           mesh_show_back_face=True)
88
89    cv3d.utility.set_verbosity_level(cv3d.utility.Info)

triangle_mesh_filtering_average.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import numpy as np
 9import cloudViewer as cv3d
10
11
12def average_filtering():
13    # Create noisy mesh.
14    knot_mesh = cv3d.data.KnotMesh()
15    mesh_in = cv3d.io.read_triangle_mesh(knot_mesh.path)
16    vertices = np.asarray(mesh_in.vertices())
17    noise = 5
18    vertices += np.random.uniform(0, noise, size=vertices.shape)
19    mesh_in.set_vertices(cv3d.utility.Vector3dVector(vertices))
20    mesh_in.compute_vertex_normals()
21    print("Displaying input mesh ...")
22    cv3d.visualization.draw_geometries([mesh_in])
23
24    print("Displaying output of average mesh filter after 1 iteration ...")
25    mesh_out = mesh_in.filter_smooth_simple(number_of_iterations=1)
26    mesh_out.compute_vertex_normals()
27    cv3d.visualization.draw_geometries([mesh_out])
28
29    print("Displaying output of average mesh filter after 5 iteration ...")
30    mesh_out = mesh_in.filter_smooth_simple(number_of_iterations=5)
31    mesh_out.compute_vertex_normals()
32    cv3d.visualization.draw_geometries([mesh_out])
33
34
35def laplace_filtering():
36    # Create noisy mesh.
37    knot_mesh = cv3d.data.KnotMesh()
38    mesh_in = cv3d.io.read_triangle_mesh(knot_mesh.path)
39    vertices = np.asarray(mesh_in.vertices())
40    noise = 5
41    vertices += np.random.uniform(0, noise, size=vertices.shape)
42    mesh_in.set_vertices(cv3d.utility.Vector3dVector(vertices))
43    mesh_in.compute_vertex_normals()
44    print("Displaying input mesh ...")
45    cv3d.visualization.draw_geometries([mesh_in])
46
47    print("Displaying output of Laplace mesh filter after 10 iteration ...")
48    mesh_out = mesh_in.filter_smooth_laplacian(number_of_iterations=10)
49    mesh_out.compute_vertex_normals()
50    cv3d.visualization.draw_geometries([mesh_out])
51
52    print("Displaying output of Laplace mesh filter after 50 iteration ...")
53    mesh_out = mesh_in.filter_smooth_laplacian(number_of_iterations=50)
54    mesh_out.compute_vertex_normals()
55    cv3d.visualization.draw_geometries([mesh_out])
56
57
58def taubin_filtering():
59    # Create noisy mesh.
60    knot_mesh = cv3d.data.KnotMesh()
61    mesh_in = cv3d.io.read_triangle_mesh(knot_mesh.path)
62    vertices = np.asarray(mesh_in.vertices())
63    noise = 5
64    vertices += np.random.uniform(0, noise, size=vertices.shape)
65    mesh_in.set_vertices(cv3d.utility.Vector3dVector(vertices))
66    mesh_in.compute_vertex_normals()
67    print("Displaying input mesh ...")
68    cv3d.visualization.draw_geometries([mesh_in])
69
70    print("Displaying output of Taubin mesh filter after 10 iteration ...")
71    mesh_out = mesh_in.filter_smooth_taubin(number_of_iterations=10)
72    mesh_out.compute_vertex_normals()
73    cv3d.visualization.draw_geometries([mesh_out])
74
75    print("Displaying output of Taubin mesh filter after 100 iteration ...")
76    mesh_out = mesh_in.filter_smooth_taubin(number_of_iterations=100)
77    mesh_out.compute_vertex_normals()
78    cv3d.visualization.draw_geometries([mesh_out])
79
80
81if __name__ == "__main__":
82    average_filtering()
83    laplace_filtering()
84    taubin_filtering()

triangle_mesh_from_point_cloud_alpha_shapes.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import cloudViewer as cv3d
 9import numpy as np
10
11if __name__ == "__main__":
12    bunny = cv3d.data.BunnyMesh()
13    mesh = cv3d.io.read_triangle_mesh(bunny.path)
14    mesh.compute_vertex_normals()
15
16    pcd = mesh.sample_points_poisson_disk(750)
17    print("Displaying input pointcloud ...")
18    cv3d.visualization.draw_geometries([pcd])
19    alpha = 0.03
20    print(f"alpha={alpha:.3f}")
21    print('Running alpha shapes surface reconstruction ...')
22    mesh = cv3d.geometry.ccMesh.create_from_point_cloud_alpha_shape(pcd, alpha)
23    mesh.compute_triangle_normals(normalized=True)
24    print("Displaying reconstructed mesh ...")
25    cv3d.visualization.draw_geometries([mesh], mesh_show_back_face=True)
26
27    tetra_mesh, pt_map = cv3d.geometry.TetraMesh.create_from_point_cloud(pcd)
28    print("done with tetra mesh")
29    cv3d.visualization.draw_geometries([tetra_mesh])
30    for alpha in np.logspace(np.log10(0.5), np.log10(0.01), num=4):
31        print("alpha={}".format(alpha))
32        mesh = cv3d.geometry.ccMesh.create_from_point_cloud_alpha_shape(
33            pcd, alpha, tetra_mesh, pt_map)
34        mesh.compute_vertex_normals()
35        cv3d.visualization.draw_geometries([mesh], mesh_show_back_face=True)

triangle_mesh_from_point_cloud_ball_pivoting.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import cloudViewer as cv3d
 9
10if __name__ == "__main__":
11    bunny = cv3d.data.BunnyMesh()
12    gt_mesh = cv3d.io.read_triangle_mesh(bunny.path)
13    gt_mesh.compute_vertex_normals()
14
15    pcd = gt_mesh.sample_points_poisson_disk(3000)
16    print("Displaying input pointcloud ...")
17    cv3d.visualization.draw([pcd], point_size=5)
18
19    radii = [0.005, 0.01, 0.02, 0.04]
20    print('Running ball pivoting surface reconstruction ...')
21    rec_mesh = cv3d.geometry.ccMesh.create_from_point_cloud_ball_pivoting(
22        pcd, cv3d.utility.DoubleVector(radii))
23    print("Displaying reconstructed mesh ...")
24    cv3d.visualization.draw([rec_mesh])

triangle_mesh_from_point_cloud_poisson.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import cloudViewer as cv3d
 9import numpy as np
10import matplotlib.pyplot as plt
11
12if __name__ == "__main__":
13    eagle = cv3d.data.EaglePointCloud()
14    pcd = cv3d.io.read_point_cloud(eagle.path)
15    R = pcd.get_rotation_matrix_from_xyz((np.pi, -np.pi / 4, 0))
16    pcd.rotate(R, center=(0, 0, 0))
17    print('Displaying input pointcloud ...')
18    cv3d.visualization.draw([pcd])
19
20    print('Running Poisson surface reconstruction ...')
21    mesh, densities = cv3d.geometry.ccMesh.create_from_point_cloud_poisson(
22        pcd, depth=9)
23    print('Displaying reconstructed mesh ...')
24    cv3d.visualization.draw([mesh])
25
26    print('visualize densities')
27    densities = np.asarray(densities)
28    density_colors = plt.get_cmap('plasma')(
29        (densities - densities.min()) / (densities.max() - densities.min()))
30    density_colors = density_colors[:, :3]
31    density_mesh = cv3d.geometry.ccMesh()
32    density_mesh.create_internal_cloud()
33    density_mesh.set_vertices(mesh.get_vertices())
34    density_mesh.set_triangles(mesh.get_triangles())
35    density_mesh.set_vertex_colors(cv3d.utility.Vector3dVector(density_colors))
36    cv3d.visualization.draw_geometries([density_mesh])
37
38    print('remove low density vertices')
39    vertices_to_remove = densities < np.quantile(densities, 0.1)
40    mesh.remove_vertices_by_mask(vertices_to_remove)
41    print(mesh)
42    cv3d.visualization.draw_geometries([mesh])

triangle_mesh_half_edge.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import numpy as np
 9import cloudViewer as cv3d
10
11if __name__ == "__main__":
12    # Initialize a HalfEdgeTriangleMesh from TriangleMesh
13    mesh = cv3d.geometry.ccMesh.create_sphere()
14    bbox = cv3d.geometry.ccBBox()
15    bbox.set_min_bound([-1, -1, -1])
16    bbox.set_max_bound([1, 0.6, 1])
17    bbox.set_validity(True)
18    mesh = mesh.crop(bbox)
19    het_mesh = cv3d.geometry.HalfEdgeTriangleMesh.create_from_triangle_mesh(
20        mesh)
21    cv3d.visualization.draw_geometries([het_mesh], mesh_show_back_face=True)
22
23    # Colorize boundary vertices to red
24    vertex_colors = 0.75 * np.ones((len(het_mesh.vertices), 3))
25    for boundary in het_mesh.get_boundaries():
26        for vertex_id in boundary:
27            vertex_colors[vertex_id] = [1, 0, 0]
28    het_mesh.vertex_colors = cv3d.utility.Vector3dVector(vertex_colors)
29    cv3d.visualization.draw_geometries([het_mesh], mesh_show_back_face=True)

triangle_mesh_hidden_point_removal.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8# examples/Python/Basic/hidden_point_removal.py
 9
10import numpy as np
11import cloudViewer as cv3d
12
13
14def mesh_generator():
15    yield cv3d.geometry.ccMesh.create_sphere()
16    knot = cv3d.data.KnotMesh()
17    mesh_knot = cv3d.io.read_triangle_mesh(knot.path)
18    mesh_knot.compute_vertex_normals()
19    yield mesh_knot
20
21    bunny = cv3d.data.BunnyMesh()
22    mesh_bunny = cv3d.io.read_triangle_mesh(bunny.path)
23    mesh_bunny.compute_vertex_normals()
24    yield mesh_bunny
25
26    armadillo = cv3d.data.ArmadilloMesh()
27    mesh_armadillo = cv3d.io.read_triangle_mesh(armadillo.path)
28    mesh_armadillo.compute_vertex_normals()
29    yield mesh_armadillo
30
31
32if __name__ == "__main__":
33    for mesh in mesh_generator():
34        print("Convert mesh to a point cloud and estimate dimensions")
35        pcl = cv3d.geometry.ccPointCloud()
36        pcl.set_points(mesh.vertices())
37        pcl.set_colors(mesh.vertex_colors())
38        diameter = np.linalg.norm(
39            np.asarray(pcl.get_max_bound()) - np.asarray(pcl.get_min_bound()))
40
41        print("Define parameters used for hidden_point_removal")
42        camera = [diameter, diameter * 0.5, diameter * 0.5]
43        radius = diameter * 100
44
45        print("Create coordinate frame for visualizing the camera location")
46        camera_frame = cv3d.geometry.ccMesh.create_coordinate_frame(
47            size=diameter / 5, origin=camera)
48
49        print("Remove all hidden points viewed from the camera location")
50        hull, _ = pcl.hidden_point_removal(camera, radius)
51
52        print("Visualize result")
53        hull_ls = cv3d.geometry.LineSet.create_from_triangle_mesh(hull)
54        hull_ls.paint_uniform_color((1, 0, 0))
55        pcl.paint_uniform_color((0.5, 0.5, 1))
56        cv3d.visualization.draw_geometries([pcl, hull_ls, camera_frame])
57
58    print("Create a point cloud representing a sphere")
59    mesh = cv3d.geometry.ccMesh.create_sphere()
60    pcl = cv3d.geometry.ccPointCloud()
61    pcl.set_points(mesh.vertices())
62
63    print("Assign colors based on their index (green to red)")
64    l = len(pcl.points())
65    colors = np.array(
66        [np.arange(0, l, 1) / l,
67         np.arange(l, 0, -1) / l,
68         np.zeros(l)]).transpose()
69    pcl.set_colors(cv3d.utility.Vector3dVector(colors))
70
71    print("Remove all hidden points viewed from the camera location")
72    mesh, pt_map = pcl.hidden_point_removal([4, 0, 0], 100)
73
74    print("Add back colors using the point map")
75    mesh.set_vertex_colors(
76        cv3d.utility.Vector3dVector(colors[np.asarray(pt_map)]))
77
78    print("Visualize the result")
79    mesh.compute_vertex_normals()
80    mesh.orient_triangles()
81    cv3d.visualization.draw_geometries([mesh, pcl])

triangle_mesh_project_to_albedo.py#

  1# ----------------------------------------------------------------------------
  2# -                        CloudViewer: www.cloudViewer.org                  -
  3# ----------------------------------------------------------------------------
  4# Copyright (c) 2018-2024 www.cloudViewer.org
  5# SPDX-License-Identifier: MIT
  6# ----------------------------------------------------------------------------
  7"""This example demonstrates project_image_to_albedo. Use create_dataset mode to
  8render images of a 3D mesh or model from different viewpoints.
  9albedo_from_dataset mode then uses the calibrated images to re-create the albedo
 10texture for the mesh.
 11"""
 12import os
 13import argparse
 14from pathlib import Path
 15import subprocess as sp
 16import time
 17import numpy as np
 18import cloudViewer as cv3d
 19from cloudViewer.visualization import gui, rendering, O3DVisualizer
 20from cloudViewer.core import Tensor
 21
 22
 23def create_dataset(meshfile, n_images=10, movie=False, vary_exposure=False):
 24    """Render images of a 3D mesh from different viewpoints, covering the
 25    northern hemisphere. These form a synthetic dataset to test the
 26    project_images_to_albedo function.
 27    """
 28    # Adjust these parameters to properly frame your model.
 29    # Window system pixel scaling (e.g. 1 for normal, 2 for HiDPI / retina display)
 30    SCALING = 2
 31    width, height = 1024, 1024  # image width, height
 32    focal_length = 512
 33    d_camera_obj = 0.3  # distance from camera to object
 34    K = np.array([[focal_length, 0, width / 2], [0, focal_length, height / 2],
 35                  [0, 0, 1]])
 36    t = np.array([0, 0, d_camera_obj])  # origin / object in camera ref frame
 37
 38    model = cv3d.io.read_triangle_model(meshfile)
 39    # DefaultLit shader will produce non-uniform images with specular
 40    # highlights, etc. These should be avoided to accurately capture the diffuse
 41    # albedo
 42    unlit = rendering.MaterialRecord()
 43    unlit.shader = "unlit"
 44
 45    def triangle_wave(n, period=1):
 46        """Triangle wave function between [0,1] with given period."""
 47        return abs(n % period - period / 2) / (period / 2)
 48
 49    def rotate_camera_and_shoot(cv3dvis):
 50        Rts = []
 51        images = []
 52        cv3dvis.scene.scene.enable_sun_light(False)
 53        print("Rendering images: ", end='', flush=True)
 54        n_0 = 2 * n_images // 3
 55        n_1 = n_images - n_0 - 1
 56        for n in range(n_images):
 57            Rt = np.eye(4)
 58            Rt[:3, 3] = t
 59            if n < n_0:
 60                theta = n * (2 * np.pi) / n_0
 61                Rt[:3, :
 62                   3] = cv3d.geometry.ccHObject.get_rotation_matrix_from_zyx(
 63                       [np.pi, theta, 0])
 64            elif n < n_images - 1:
 65                theta = (n - n_0) * (2 * np.pi) / n_1
 66                Rt[:3, :
 67                   3] = cv3d.geometry.ccHObject.get_rotation_matrix_from_xyz(
 68                       [np.pi / 4, theta, np.pi])
 69            else:  # one image from the top
 70                Rt[:3, :
 71                   3] = cv3d.geometry.ccHObject.get_rotation_matrix_from_zyx(
 72                       [np.pi, 0, -np.pi / 2])
 73            Rts.append(Rt)
 74            cv3dvis.setup_camera(K, Rt, width, height)
 75            # Vary IBL intensity as a poxy for exposure value. IBL ranges from
 76            # [0,150000]. We vary it between 20000 and 100000.
 77            if vary_exposure:
 78                cv3dvis.set_ibl_intensity(20000 + 80000 *
 79                                          triangle_wave(n, n_images / 4))
 80            cv3dvis.post_redraw()
 81            cv3dvis.export_current_image(f"render-{n:02}.jpg")
 82            images.append(f"render-{n:02}.jpg")
 83            print('.', end='', flush=True)
 84        np.savez("cameras.npz",
 85                 width=width,
 86                 height=height,
 87                 K=K,
 88                 Rts=Rts,
 89                 images=images)
 90        # Now create a movie from the saved images by calling ffmpeg with
 91        # subprocess
 92        if movie:
 93            print("\nCreating movie...", end='', flush=True)
 94            sp.run([
 95                "ffmpeg", "-framerate", f"{n_images / 6}", "-pattern_type",
 96                "glob", "-i", "render-*.jpg", "-y", meshfile.stem + ".mp4"
 97            ],
 98                   check=True)
 99        cv3dvis.close()
100        print("\nDone.")
101
102    print("If the object is properly framed in the GUI window, click on the "
103          "'Save Images' action in the menu.")
104    cv3d.visualization.draw([{
105        'geometry': model,
106        'name': meshfile.name,
107        'material': unlit
108    }],
109                            show_ui=False,
110                            width=int(width / SCALING),
111                            height=int(height / SCALING),
112                            actions=[("Save Images", rotate_camera_and_shoot)])
113
114
115def albedo_from_images(meshfile, calib_data_file, albedo_contrast=1.25):
116    model = cv3d.io.read_triangle_model(meshfile)
117    tmeshes = cv3d.t.geometry.TriangleMesh.from_triangle_mesh_model(model)
118    tmeshes = list(tmeshes.values())
119    calib = np.load(calib_data_file)
120    Ks = list(Tensor(calib["K"]) for _ in range(len(calib["Rts"])))
121    Rts = list(Tensor(Rt) for Rt in calib["Rts"])
122    images = list(cv3d.t.io.read_image(imfile) for imfile in calib["images"])
123    calib.close()
124    start = time.time()
125    with cv3d.utility.VerbosityContextManager(
126            cv3d.utility.VerbosityLevel.Debug):
127        albedo = tmeshes[0].project_images_to_albedo(images, Ks, Rts, 1024,
128                                                     True)
129    albedo = albedo.linear_transform(scale=albedo_contrast)  # brighten albedo
130    tmeshes[0].material.texture_maps["albedo"] = albedo
131    print(f"project_images_to_albedo ran in {time.time() - start:.2f}s")
132    cv3d.t.io.write_image("albedo.png", albedo)
133    cv3d.t.io.write_triangle_mesh(meshfile.stem + "_albedo.glb", tmeshes[0])
134    cam_vis = list({
135        "name":
136            f"camera-{i:02}",
137        "geometry":
138            cv3d.geometry.LineSet.create_camera_visualization(
139                images[0].columns, images[0].rows, K.numpy(), Rt.numpy(), 0.1)
140    } for i, (K, Rt) in enumerate(zip(Ks, Rts)))
141    cv3d.visualization.draw(cam_vis + [{
142        "name": meshfile.name,
143        "geometry": tmeshes[0]
144    }],
145                            show_ui=True)
146
147
148if __name__ == "__main__":
149
150    parser = argparse.ArgumentParser(description=__doc__)
151    parser.add_argument("action",
152                        choices=('create_dataset', 'albedo_from_images'))
153    parser.add_argument("--meshfile",
154                        type=Path,
155                        default=Path("."),
156                        help="Path to mesh file.")
157    parser.add_argument("--n-images",
158                        type=int,
159                        default=10,
160                        help="Number of images to render.")
161    parser.add_argument("--download_sample_model",
162                        help="Download a sample 3D model for this example.",
163                        action="store_true")
164    parser.add_argument(
165        "--movie",
166        action="store_true",
167        help=
168        "Create movie from rendered images with ffmpeg. ffmpeg must be installed and in path."
169    )
170    args = parser.parse_args()
171
172    if args.action == "create_dataset":
173        if args.download_sample_model:
174            cv3d.data.set_custom_downloads_prefix(
175                "https://github.com/Asher-1/cloudViewer_downloads/releases/download/"
176            )
177            args.meshfile = Path(cv3d.data.BalusterVase().path)
178        if args.meshfile == Path("."):
179            parser.error("Please provide a path to a mesh file, or use "
180                         "--download_sample_model.")
181        if args.n_images < 10:
182            parser.error("Atleast 10 images should be used!")
183        create_dataset(args.meshfile,
184                       n_images=args.n_images,
185                       movie=args.movie,
186                       vary_exposure=True)
187    else:
188        cv3d.data.set_custom_downloads_prefix(
189            "https://github.com/Asher-1/cloudViewer_downloads/releases/download/"
190        )
191        args.meshfile = Path(cv3d.data.BalusterVase().path)
192        albedo_from_images(args.meshfile, "cameras.npz")

triangle_mesh_properties.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import cloudViewer as cv3d
 9import numpy as np
10import os
11import sys
12
13pyexample_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
14sys.path.append(pyexample_path)
15
16import cloudViewer_example as cv3dex
17
18
19def check_properties(name, mesh):
20    mesh.compute_vertex_normals()
21
22    edge_manifold = mesh.is_edge_manifold(allow_boundary_edges=True)
23    edge_manifold_boundary = mesh.is_edge_manifold(allow_boundary_edges=False)
24    vertex_manifold = mesh.is_vertex_manifold()
25    self_intersecting = mesh.is_self_intersecting()
26    watertight = mesh.is_watertight()
27    orientable = mesh.is_orientable()
28
29    print(name)
30    print(f"  edge_manifold:          {edge_manifold}")
31    print(f"  edge_manifold_boundary: {edge_manifold_boundary}")
32    print(f"  vertex_manifold:        {vertex_manifold}")
33    print(f"  self_intersecting:      {self_intersecting}")
34    print(f"  watertight:             {watertight}")
35    print(f"  orientable:             {orientable}")
36
37    geoms = [mesh]
38    if not edge_manifold:
39        edges = mesh.get_non_manifold_edges(allow_boundary_edges=True)
40        geoms.append(cv3dex.edges_to_lineset(mesh, edges, (1, 0, 0)))
41    if not edge_manifold_boundary:
42        edges = mesh.get_non_manifold_edges(allow_boundary_edges=False)
43        geoms.append(cv3dex.edges_to_lineset(mesh, edges, (0, 1, 0)))
44    if not vertex_manifold:
45        verts = np.asarray(mesh.get_non_manifold_vertices())
46        pcl = cv3d.geometry.ccPointCloud(points=cv3d.utility.Vector3dVector(
47            np.asarray(mesh.get_vertices())[verts]))
48        pcl.paint_uniform_color((0, 0, 1))
49        geoms.append(pcl)
50    if self_intersecting:
51        intersecting_triangles = np.asarray(
52            mesh.get_self_intersecting_triangles())
53        intersecting_triangles = intersecting_triangles[0:1]
54        intersecting_triangles = np.unique(intersecting_triangles)
55        print("  # visualize self-intersecting triangles")
56        triangles = np.asarray(mesh.get_triangles())[intersecting_triangles]
57        edges = [
58            np.vstack((triangles[:, i], triangles[:, j]))
59            for i, j in [(0, 1), (1, 2), (2, 0)]
60        ]
61        edges = np.hstack(edges).T
62        edges = cv3d.utility.Vector2iVector(edges)
63        geoms.append(cv3dex.edges_to_lineset(mesh, edges, (1, 0, 1)))
64    cv3d.visualization.draw_geometries(geoms, mesh_show_back_face=True)
65
66
67if __name__ == "__main__":
68    knot_mesh = cv3d.data.KnotMesh()
69    mesh = cv3d.io.read_triangle_mesh(knot_mesh.path)
70    check_properties('KnotMesh', mesh)
71    check_properties('Mobius', cv3d.geometry.ccMesh.create_mobius(twists=1))
72    check_properties("non-manifold edge", cv3dex.get_non_manifold_edge_mesh())
73    check_properties("non-manifold vertex",
74                     cv3dex.get_non_manifold_vertex_mesh())
75    check_properties("open box", cv3dex.get_open_box_mesh())
76    check_properties("intersecting_boxes", cv3dex.get_intersecting_boxes_mesh())

triangle_mesh_sampling.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import numpy as np
 9import time
10import cloudViewer as cv3d
11
12
13def time_fcn(fcn, *fcn_args, runs=5):
14    times = []
15    for _ in range(runs):
16        tic = time.time()
17        res = fcn(*fcn_args)
18        times.append(time.time() - tic)
19    return res, times
20
21
22def mesh_generator():
23    yield cv3d.geometry.ccMesh.create_plane()
24    yield cv3d.geometry.ccMesh.create_sphere()
25
26    bunny = cv3d.data.BunnyMesh()
27    mesh = cv3d.io.read_triangle_mesh(bunny.path)
28    mesh.compute_vertex_normals()
29    yield mesh
30
31
32if __name__ == "__main__":
33    plane = cv3d.geometry.ccMesh.create_plane()
34    cv3d.visualization.draw_geometries([plane], mesh_show_back_face=True)
35
36    print('Uniform sampling can yield clusters of points on the surface')
37    pcd = plane.sample_points_uniformly(number_of_points=500)
38    cv3d.visualization.draw_geometries([pcd])
39
40    print(
41        'Poisson disk sampling can evenly distributes the points on the surface.'
42    )
43    print('The method implements sample elimination.')
44    print('Therefore, the method starts with a sampled point cloud and removes '
45          'point to satisfy the sampling criterion.')
46    print('The method supports two options to provide the initial point cloud')
47    print('1) Default via the parameter init_factor: The method first samples '
48          'uniformly a point cloud from the mesh with '
49          'init_factor x number_of_points and uses this for the elimination')
50    pcd = plane.sample_points_poisson_disk(number_of_points=500, init_factor=5)
51    cv3d.visualization.draw_geometries([pcd])
52
53    print(
54        '2) one can provide an own point cloud and pass it to the '
55        'cv3d.geometry.sample_points_poisson_disk method. Then this point cloud is used '
56        'for elimination.')
57    print('Initial point cloud')
58    pcd = plane.sample_points_uniformly(number_of_points=2500)
59    cv3d.visualization.draw_geometries([pcd])
60    pcd = plane.sample_points_poisson_disk(number_of_points=500, pcl=pcd)
61    cv3d.visualization.draw_geometries([pcd])
62
63    print('Timings')
64    for mesh in mesh_generator():
65        mesh.compute_vertex_normals()
66        cv3d.visualization.draw_geometries([mesh])
67
68        pcd, times = time_fcn(mesh.sample_points_uniformly, 500)
69        print('sample uniform took on average: %f[s]' % np.mean(times))
70        cv3d.visualization.draw_geometries([pcd])
71
72        pcd, times = time_fcn(mesh.sample_points_poisson_disk, 500, 5)
73        print('sample poisson disk took on average: %f[s]' % np.mean(times))
74        cv3d.visualization.draw_geometries([pcd])

triangle_mesh_simplification_decimation.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import cloudViewer as cv3d
 9
10if __name__ == "__main__":
11    bunny = cv3d.data.BunnyMesh()
12    mesh_in = cv3d.io.read_triangle_mesh(bunny.path)
13    mesh_in.compute_vertex_normals()
14
15    print("Before Simplification: ", mesh_in)
16    cv3d.visualization.draw_geometries([mesh_in])
17
18    mesh_smp = mesh_in.simplify_quadric_decimation(
19        target_number_of_triangles=6500)
20    print("After Simplification target number of triangles = 6500:\n", mesh_smp)
21    cv3d.visualization.draw_geometries([mesh_smp])
22
23    mesh_smp = mesh_in.simplify_quadric_decimation(
24        target_number_of_triangles=1700)
25    print("After Simplification target number of triangles = 1700:\n", mesh_smp)
26    cv3d.visualization.draw_geometries([mesh_smp])

triangle_mesh_simplification_vertex_clustering.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import cloudViewer as cv3d
 9
10if __name__ == "__main__":
11    bunny = cv3d.data.BunnyMesh()
12    mesh_in = cv3d.io.read_triangle_mesh(bunny.path)
13    mesh_in.compute_vertex_normals()
14
15    print("Before Simplification: ", mesh_in)
16    cv3d.visualization.draw_geometries([mesh_in])
17
18    voxel_size = max(mesh_in.get_max_bound() - mesh_in.get_min_bound()) / 32
19    mesh_smp = mesh_in.simplify_vertex_clustering(
20        voxel_size=voxel_size,
21        contraction=cv3d.geometry.SimplificationContraction.Average)
22    print("After Simplification with voxel size =", voxel_size, ":\n", mesh_smp)
23    cv3d.visualization.draw_geometries([mesh_smp])
24
25    voxel_size = max(mesh_in.get_max_bound() - mesh_in.get_min_bound()) / 16
26    mesh_smp = mesh_in.simplify_vertex_clustering(
27        voxel_size=voxel_size,
28        contraction=cv3d.geometry.SimplificationContraction.Average)
29    print("After Simplification with voxel size =", voxel_size, ":\n", mesh_smp)
30    cv3d.visualization.draw_geometries([mesh_smp])

triangle_mesh_subdivision.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8# examples/Python/Basic/mesh_subdivision.py
 9
10import numpy as np
11import cloudViewer as cv3d
12
13
14def mesh_generator():
15    knot_mesh = cv3d.data.KnotMesh()
16    yield cv3d.io.read_triangle_mesh(knot_mesh.path)
17    yield cv3d.geometry.ccMesh.create_plane()
18    yield cv3d.geometry.ccMesh.create_tetrahedron()
19    yield cv3d.geometry.ccMesh.create_box()
20    yield cv3d.geometry.ccMesh.create_octahedron()
21    yield cv3d.geometry.ccMesh.create_icosahedron()
22    yield cv3d.geometry.ccMesh.create_sphere()
23    yield cv3d.geometry.ccMesh.create_cone()
24    yield cv3d.geometry.ccMesh.create_cylinder()
25
26
27if __name__ == "__main__":
28    np.random.seed(42)
29
30    number_of_iterations = 3
31
32    for mesh in mesh_generator():
33        mesh.compute_vertex_normals()
34        print("original mesh has %d triangles and %d vertices" %
35              (np.asarray(mesh.get_triangles()).shape[0],
36               np.asarray(mesh.get_vertices()).shape[0]))
37        cv3d.visualization.draw_geometries([mesh], mesh_show_wireframe=True)
38
39        mesh_up = mesh.subdivide_midpoint(
40            number_of_iterations=number_of_iterations)
41        print("midpoint upsampled mesh has %d triangles and %d vertices" %
42              (np.asarray(mesh_up.get_triangles()).shape[0],
43               np.asarray(mesh_up.get_vertices()).shape[0]))
44        cv3d.visualization.draw_geometries([mesh_up], mesh_show_wireframe=True)
45
46        mesh_up = mesh.subdivide_loop(number_of_iterations=number_of_iterations)
47        print("loop upsampled mesh has %d triangles and %d vertices" %
48              (np.asarray(mesh_up.get_triangles()).shape[0],
49               np.asarray(mesh_up.get_vertices()).shape[0]))
50        cv3d.visualization.draw_geometries([mesh_up], mesh_show_wireframe=True)

triangle_mesh_transformation.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import cloudViewer as cv3d
 9import numpy as np
10import copy
11
12
13def translate():
14    mesh = cv3d.geometry.ccMesh.create_coordinate_frame()
15    mesh_tx = copy.deepcopy(mesh).translate((1.3, 0, 0))
16    mesh_ty = copy.deepcopy(mesh).translate((0, 1.3, 0))
17    print('Displaying original and translated geometries ...')
18    cv3d.visualization.draw([{
19        "name": "Original Geometry",
20        "geometry": mesh
21    }, {
22        "name": "Translated (in X) Geometry",
23        "geometry": mesh_tx
24    }, {
25        "name": "Translated (in Y) Geometry",
26        "geometry": mesh_ty
27    }],
28                            show_ui=True)
29
30
31def rotate():
32    mesh = cv3d.geometry.ccMesh.create_coordinate_frame()
33    mesh_r = copy.deepcopy(mesh)
34    R = mesh.get_rotation_matrix_from_xyz((np.pi / 2, 0, np.pi / 4))
35    mesh_r.rotate(R, center=(0, 0, 0))
36    print('Displaying original and rotated geometries ...')
37    cv3d.visualization.draw([{
38        "name": "Original Geometry",
39        "geometry": mesh
40    }, {
41        "name": "Rotated Geometry",
42        "geometry": mesh_r
43    }],
44                            show_ui=True)
45
46
47def scale():
48    mesh = cv3d.geometry.ccMesh.create_coordinate_frame()
49    mesh_s = copy.deepcopy(mesh).translate((2, 0, 0))
50    mesh_s.scale(0.5, center=mesh_s.get_center())
51    print('Displaying original and scaled geometries ...')
52    cv3d.visualization.draw([{
53        "name": "Original Geometry",
54        "geometry": mesh
55    }, {
56        "name": "Scaled Geometry",
57        "geometry": mesh_s
58    }],
59                            show_ui=True)
60
61
62def transform():
63    mesh = cv3d.geometry.ccMesh.create_coordinate_frame()
64    T = np.eye(4)
65    T[:3, :3] = mesh.get_rotation_matrix_from_xyz((0, np.pi / 3, np.pi / 2))
66    T[0, 3] = 1
67    T[1, 3] = 1.3
68    print(T)
69    mesh_t = copy.deepcopy(mesh).transform(T)
70    print('Displaying original and transformed geometries ...')
71    cv3d.visualization.draw([{
72        "name": "Original Geometry",
73        "geometry": mesh
74    }, {
75        "name": "Transformed Geometry",
76        "geometry": mesh_t
77    }],
78                            show_ui=True)
79
80
81if __name__ == "__main__":
82    translate()
83    rotate()
84    scale()
85    transform()

triangle_mesh_voxelization.py#

  1# ----------------------------------------------------------------------------
  2# -                        CloudViewer: www.cloudViewer.org                  -
  3# ----------------------------------------------------------------------------
  4# Copyright (c) 2018-2024 www.cloudViewer.org
  5# SPDX-License-Identifier: MIT
  6# ----------------------------------------------------------------------------
  7
  8import time
  9import cloudViewer as cv3d
 10import numpy as np
 11
 12
 13def preprocess(model):
 14    """Normalize model to fit in unit sphere (sphere with unit radius).
 15    
 16    Calculate center & scale of vertices, and transform vertices to have 0 mean and unit variance. 
 17
 18    Returns:
 19        cloudViewer.geometry.ccMesh: normalized mesh
 20    """
 21    min_bound = model.get_min_bound()
 22    max_bound = model.get_max_bound()
 23    center = min_bound + (max_bound - min_bound) / 2.0
 24    scale = np.linalg.norm(max_bound - min_bound) / 2.0
 25    vertices = np.asarray(model.get_vertices())
 26    vertices -= center
 27    model.set_vertices(cv3d.utility.Vector3dVector(vertices / scale))
 28
 29    ## Paint uniform color for pleasing visualization
 30    model.paint_uniform_color(np.array([1, 0.7, 0]))
 31    return model
 32
 33
 34def mesh_generator():
 35    bunny = cv3d.data.BunnyMesh()
 36    mesh_bunny = cv3d.io.read_triangle_mesh(bunny.path)
 37    mesh_bunny.compute_vertex_normals()
 38    yield mesh_bunny
 39
 40    armadillo = cv3d.data.ArmadilloMesh()
 41    mesh_armadillo = cv3d.io.read_triangle_mesh(armadillo.path)
 42    mesh_armadillo.compute_vertex_normals()
 43    yield mesh_armadillo
 44
 45
 46if __name__ == "__main__":
 47    print("Start mesh_sampling_and_voxelization example")
 48    for mesh in mesh_generator():
 49        print("Normalize mesh")
 50        mesh = preprocess(mesh)
 51        cv3d.visualization.draw_geometries([mesh])
 52        print("")
 53
 54        print("Sample uniform points")
 55        start = time.time()
 56        pcd = mesh.sample_points_uniformly(number_of_points=100000)
 57        print("took %.2f milliseconds" % ((time.time() - start) * 1000.0))
 58        print("")
 59
 60        print("visualize sampled point cloud")
 61        cv3d.visualization.draw_geometries([pcd])
 62        print("")
 63
 64        print("Voxelize point cloud")
 65        start = time.time()
 66        voxel = cv3d.geometry.VoxelGrid.create_from_point_cloud(pcd,
 67                                                                voxel_size=0.05)
 68        print("took %.2f milliseconds" % ((time.time() - start) * 1000.0))
 69        print("")
 70
 71        print("visualize voxel grid")
 72        cv3d.visualization.draw_geometries([voxel])
 73        print("")
 74
 75        print("Element-wise check if points belong to voxel grid")
 76        queries = np.asarray(pcd.get_points())
 77        start = time.time()
 78        output = voxel.check_if_included(cv3d.utility.Vector3dVector(queries))
 79        print("took %.2f milliseconds" % ((time.time() - start) * 1000.0))
 80        print(output[:10])
 81        print("")
 82
 83        print(
 84            "Element-wise check if points with additive Gaussian noise belong to voxel grid"
 85        )
 86        queries_noise = queries + np.random.normal(0, 0.1,
 87                                                   (len(pcd.get_points()), 3))
 88        start = time.time()
 89        output_noise = voxel.check_if_included(
 90            cv3d.utility.Vector3dVector(queries_noise))
 91        print(output_noise[:10])
 92        print("took %.2f milliseconds" % ((time.time() - start) * 1000.0))
 93        print("")
 94
 95        print("Transform voxelgrid to octree")
 96        start = time.time()
 97        octree = voxel.to_octree(max_depth=8)
 98        print(octree)
 99        print("took %.2f milliseconds" % ((time.time() - start) * 1000.0))
100        cv3d.visualization.draw_geometries([octree])
101        print("")

triangle_mesh_with_numpy.py#

 1# ----------------------------------------------------------------------------
 2# -                        CloudViewer: www.cloudViewer.org                  -
 3# ----------------------------------------------------------------------------
 4# Copyright (c) 2018-2024 www.cloudViewer.org
 5# SPDX-License-Identifier: MIT
 6# ----------------------------------------------------------------------------
 7
 8import cloudViewer as cv3d
 9import numpy as np
10
11if __name__ == "__main__":
12    # Read a mesh and get its data as numpy arrays.
13    knot_mesh = cv3d.data.KnotMesh()
14    mesh = cv3d.io.read_triangle_mesh(knot_mesh.path)
15    mesh.compute_vertex_normals()
16    mesh.paint_uniform_color([0.5, 0.1, 0.3])
17    print('Vertices:')
18    print(np.asarray(mesh.vertices()))
19    print('Vertex Colors:')
20    print(np.asarray(mesh.vertex_colors()))
21    print('Vertex Normals:')
22    print(np.asarray(mesh.vertex_normals()))
23    print('Triangles:')
24    print(np.asarray(mesh.triangles()))
25    print('Triangle Normals:')
26    print(np.asarray(mesh.triangle_normals()))
27    print("Displaying mesh ...")
28    print(mesh)
29    cv3d.visualization.draw([mesh])
30
31    # Create a mesh using numpy arrays with random colors.
32    N = 5
33    vertices = cv3d.utility.Vector3dVector(
34        np.array([[0, 0, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0.5, 0.5, 0.5]]))
35    triangles = cv3d.utility.Vector3iVector(
36        np.array([[0, 1, 2], [0, 2, 3], [0, 4, 1], [1, 4, 2], [2, 4, 3],
37                  [3, 4, 0]]))
38    mesh_np = cv3d.geometry.ccMesh(vertices, triangles)
39    mesh_np.set_vertex_colors(
40        cv3d.utility.Vector3dVector(np.random.uniform(0, 1, size=(N, 3))))
41    mesh_np.compute_vertex_normals()
42    print(np.asarray(mesh_np.triangle_normals))
43    print("Displaying mesh made using numpy ...")
44    cv3d.visualization.draw_geometries([mesh_np], mesh_show_wireframe=True)