Alpha shapes

利用凸包搞得重建。

import open3d as o3d

mesh_ply = o3d.io.read_triangle_mesh("mode/bunny.ply")
# 采样
pcd = mesh_ply.sample_points_poisson_disk(750)
# 看一下凸包情况
hull, _ = pcd.compute_convex_hull()
hull_ls = o3d.geometry.LineSet.create_from_triangle_mesh(hull)
hull_ls.paint_uniform_color((1, 0, 0))
o3d.visualization.draw_geometries([pcd, hull_ls], width=1280, height=720)
#开始表面重建,alpha值可调
alpha = 0.1
print(f"alpha={alpha:.3f}")
mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd, alpha)
mesh.compute_vertex_normals()
print(mesh)
o3d.visualization.draw_geometries([mesh], mesh_show_back_face=True, width=1280, height=720)

结果:

凸包情况
a34b7c962f6048c7957dc74dc5a1cc93
重建效果,Alpha=0.149eb9bd79be642c0a41bf598b23c15fc
继续,Alpha = 0.015
c33ea83edffb45c08022d42be2bd9273

滚球法

import open3d as o3d

mesh = o3d.io.read_triangle_mesh("mode/bunny.ply")
mesh.compute_vertex_normals()
#老规矩,先采样
pcd = mesh.sample_points_poisson_disk(3000)
#这里可以看到法线
o3d.visualization.draw_geometries([pcd], point_show_normal=True, width=1280, height=720)
#开始重建
radii = [0.005, 0.01, 0.02, 0.04]
rec_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(pcd, o3d.utility.DoubleVector(radii))
o3d.visualization.draw_geometries([pcd, rec_mesh], width=1280, height=720)

效果:

法线标注情况
b9e6b9eee51e4ad49b320e5634e8d7a5
重建效果
c884a814cb5e4ce5acc60c228eef681a

泊松表面重建

上面两种,滚球法看上去还不错,但实际上两个都很鸡肋,不够平滑。这方面泊松重建会好一点。
泊松表面重建可调节参数只有一个,那就是depth,这是定义八叉树深度的,数值高的话细节会更多一点。

import open3d as o3d

mesh = o3d.io.read_triangle_mesh("mode/Fantasy Dragon.ply")
mesh.compute_vertex_normals()
pcd = mesh.sample_points_poisson_disk(3000)

with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
    mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=9)
#给他涂个颜色
mesh.paint_uniform_color([1, 0, 0])
o3d.visualization.draw_geometries([mesh], zoom=0.664,
                                  front=[-0.4761, -0.4698, -0.7434],
                                  lookat=[1.8900, 3.2596, 0.9284],
                                  up=[0.2304, -0.8825, 0.4101],
                                  width=1280,
                                  height=720)

3a356062603f49ee91e2f17b763ce3d0
接下来走个流程,看看点的密度。

print('visualize densities')
densities = np.asarray(densities)
density_colors = plt.get_cmap('plasma')(
    (densities - densities.min()) / (densities.max() - densities.min()))
density_colors = density_colors[:, :3]
density_mesh = o3d.geometry.TriangleMesh()
density_mesh.vertices = mesh.vertices
density_mesh.triangles = mesh.triangles
density_mesh.triangle_normals = mesh.triangle_normals
density_mesh.vertex_colors = o3d.utility.Vector3dVector(density_colors)
o3d.visualization.draw_geometries([density_mesh], zoom=0.664,
                                  front=[-0.4761, -0.4698, -0.7434],
                                  lookat=[1.8900, 3.2596, 0.9284],
                                  up=[0.2304, -0.8825, 0.4101],
                                  width=1280,
                                  height=720)

042c8573308a482aaa1c2f158380f55b
紫色是低密度,黄色是高密度,可以筛出一些点密度低的。结果如下:
10e4a329326441889c97466d5d5633a7
看似没什么变化。采样点3000的情况下重建,依旧存在一些散点噪点。要去除噪点,有两种办法:第一种:继续减少采样点;第二种,增加采样点。减少采样点会丢失更多细节,所以不推荐。
咱们来看看增加采样点的效果。

采样点=10000
2f7ea4e19546407c90abd04c6ed1bdbf
几乎是还原了原貌,但是如果去除了低密度区域呢?
4ff4c6124e164f03949544883fd57e6f
变得不完整了。所以看情况使用删点功能。

下面看看减少采样点的情况。

采样点=1000
9d944b4fa7fe4c0c8830657fc2f5d091

跟预想中一样,虽然原来的那些散点没了,但同时也丢失了很多细节,得不偿失。
接下来换个模型看看重建效果。

采样点15000
接近极限了,即使是采样点基本包裹了整个模型,也依旧会丢失一些细节。
30be7f55600e481791d47e13d2281d73
文章目录