Skip to content

Instantly share code, notes, and snippets.

@spelufo
Created May 27, 2024 14:15
Show Gist options
  • Save spelufo/99c9b31c35a54cea7a966ba6a9832bf4 to your computer and use it in GitHub Desktop.
Save spelufo/99c9b31c35a54cea7a966ba6a9832bf4 to your computer and use it in GitHub Desktop.
open3d_poisson_recon_helpers.py
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