Created
May 27, 2024 14:15
-
-
Save spelufo/99c9b31c35a54cea7a966ba6a9832bf4 to your computer and use it in GitHub Desktop.
open3d_poisson_recon_helpers.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def mesh_cleanup(mesh_o3d): | |
mesh_o3d.remove_non_manifold_edges() | |
mesh_o3d.merge_close_vertices(0.001) | |
mesh_o3d.remove_duplicated_vertices() | |
mesh_o3d.remove_duplicated_triangles() | |
mesh_o3d.remove_unreferenced_vertices() | |
mesh_o3d.remove_degenerate_triangles() | |
# This seems to keep the majority normal direction, but without knowing | |
# how it works there's the risk that it flips all the faces. | |
mesh_o3d.orient_triangles() | |
cis, cns, cas = mesh_o3d.cluster_connected_triangles() | |
# print("component areas pre-cleanup:", cas) | |
max_area = max(cas) | |
max_allowed_area = max_area/3 | |
remove_components = [] | |
for i, area in enumerate(cas): | |
if area < max_allowed_area: | |
remove_components.append(i) | |
mesh_o3d.remove_triangles_by_mask([ci in remove_components for ci in cis]) | |
mesh_o3d.remove_unreferenced_vertices() | |
# Fill holes: this may help but may also cost us a fair bit of time too. | |
# We need to convert to the new o3d format, then it converts to vtk internally | |
# (TODO: call vtk directly), which copies the data again... | |
# mesh_o3d = o3d.t.geometry.TriangleMesh.from_legacy(m).fill_holes(hole_size=50.0).to_legacy() | |
return mesh_o3d | |
def mesh_report(mesh_o3d, name): | |
_, _, cas = mesh_o3d.cluster_connected_triangles() | |
n_components = len(cas) | |
X = mesh_o3d.euler_poincare_characteristic() | |
nonmanifold_edges = mesh_o3d.get_non_manifold_edges(allow_boundary_edges=True) | |
boundary_edges = mesh_o3d.get_non_manifold_edges(allow_boundary_edges=False) | |
n_boundary_edges = len(boundary_edges) - len(nonmanifold_edges) | |
g = networkx.Graph() | |
g.add_edges_from(boundary_edges) | |
n_boundary_loops = networkx.number_connected_components(g) | |
genus = 1 - (X + n_boundary_loops*n_components)/2 | |
print(name, | |
"\tn_components:", n_components, | |
"\tareas:", list(map(round, cas)), | |
"\tgenus:", genus, | |
"\tn_boundary_edges:", n_boundary_edges, | |
"\tn_boundary_loops:", n_boundary_loops, | |
"\tX:", X) | |
def poisson_depth_from_width_and_scale(pcd, width, scale_factor): | |
bbox = pcd.get_axis_aligned_bounding_box() | |
p_min = bbox.get_min_bound() | |
p_max = bbox.get_max_bound() | |
resolution = max((p_max - p_min) / width) | |
resolution *= scale_factor | |
depth = 0 | |
while ((1 << depth) < resolution): | |
depth += 1 | |
return depth | |
def create_from_point_cloud_poisson(pcd, depth=8, width=0, scale=1.1, **kwargs): | |
# Work around open3d's poisson width bug: | |
# https://github.com/isl-org/Open3D/issues/5842#issuecomment-2133275951 | |
if width > 0: | |
depth = poisson_depth_from_width_and_scale(pcd, width, scale) | |
return o3d.geometry.TriangleMesh.create_from_point_cloud_poisson( | |
pcd, width=width, depth=depth, scale=scale, **kwargs | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment