Surface reconstruction 表面重建
在許多情況下,我們希望生成密集的3D幾何體,即三角形網(wǎng)格(triangle mesh)。然而,從多視點立體方法或深度傳感器中,我們只能獲得非結(jié)構(gòu)化的點云。要從此非結(jié)構(gòu)化輸入中獲取三角形網(wǎng)格,我們需要執(zhí)行表面重建。在文獻中存在幾種方法,Open3D目前實現(xiàn)了以下方法:
Alpha shapes(阿爾法形狀)
Ball pivoting(球旋轉(zhuǎn))
Poisson surface reconstruction(泊松表面重建)
Alpha shapes
阿爾法形狀[Edelsbrunner1983]是凸殼的推廣。正如這里[https://graphics.stanford.edu/courses/cs268-11-spring/handouts/AlphaShapes/as_fisher.pdf]所描述的,人們可以直觀地將阿爾法形狀想象成:想象一大堆冰淇淋,其中包含這些點作為硬巧克力塊。使用其中一個球形冰淇淋勺子,我們雕刻出冰淇淋塊的所有部分,我們可以在不碰到巧克力塊的情況下到達,從而甚至在內(nèi)部雕刻出孔洞(例如,只需從外面移動勺子就無法到達的部分)。我們最終將得到一個由大寫字母、弧線和點邊界的(不一定是凸的)物體。如果我們現(xiàn)在將所有圓面拉直為三角形和線段,則可以直觀地描述所謂的 alpha 形狀S。
Open3D 實現(xiàn)了涉及權(quán)衡參數(shù)alpha的方法create_from_point_cloud_alpha_shape。
bunny = o3d.data.BunnyMesh()
mesh = o3d.io.read_triangle_mesh(bunny.path)
mesh.compute_vertex_normals()
pcd = mesh.sample_points_poisson_disk(750)
o3d.visualization.draw_geometries([pcd])
alpha = 0.03
print(f"alpha={alpha:.3f}")
mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd, alpha)
mesh.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh], mesh_show_back_face=True)
該實現(xiàn)基于點云的凸殼。如果我們想從給定的點云中計算多個 alpha 形狀,那么我們可以通過只計算凸殼一次并將其傳遞給 create_from_point_cloud_alpha_shape來節(jié)省一些計算。
tetra_mesh, pt_map = o3d.geometry.TetraMesh.create_from_point_cloud(pcd)
for alpha in np.logspace(np.log10(0.5), np.log10(0.01), num=4):
print(f"alpha={alpha:.3f}")
mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(
pcd, alpha, tetra_mesh, pt_map)
mesh.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh], mesh_show_back_face=True)
Ball pivoting
球樞軸算法(ball pivoting algorithm,BPA)[Bernardini1999]是一種與阿爾法形狀相關(guān)的表面重建方法。直觀地說,想想一個具有給定半徑的3D球,我們將其落在點云上。如果它擊中任何3個點(并且它沒有落在這3個點上),它就會創(chuàng)建一個三角形。然后,算法開始從現(xiàn)有三角形的邊緣旋轉(zhuǎn),每次它擊中球沒有落下的3個點時,我們都會創(chuàng)建另一個三角形。
Open3D 在create_from_point_cloud_ball_pivoting中實現(xiàn)了此方法。該方法接受與在點云上旋轉(zhuǎn)的各個球的半徑相對應(yīng)的參數(shù)列表radii。
Note:此方法假設(shè)點云具有法線。
bunny = o3d.data.BunnyMesh()
gt_mesh = o3d.io.read_triangle_mesh(bunny.path)
gt_mesh.compute_vertex_normals()
pcd = gt_mesh.sample_points_poisson_disk(3000)
o3d.visualization.draw_geometries([pcd])
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])
Poisson surface reconstruction
泊松曲面重構(gòu)方法 [Kazhdan2006] 求解了一個正則化優(yōu)化問題,得到了一個光滑的曲面。因此,泊松曲面重建可能比上述方法更可取,因為它們會產(chǎn)生非平滑的結(jié)果、因為PointCloud點也是所得三角形網(wǎng)格的點vertices,無需任何修改。
Open3D實現(xiàn)了該方法create_from_point_cloud_poisson,該方法基本上是Kazhdan代碼的包裝器。該函數(shù)的一個重要參數(shù)depth是定義用于表面重建的八叉樹的深度,因此意味著所得三角形網(wǎng)格的分辨率。depth值越高,表示網(wǎng)格具有更多細節(jié)。
Note:此方法假設(shè)點云具有法線。
import open3d as o3d
eagle_path = r'../data/EaglePointCloud.ply'
pcd = o3d.io.read_point_cloud(eagle_path)
print(pcd)
o3d.visualization.draw_geometries([pcd],
zoom=0.664,
front=[-0.4761, -0.4698, -0.7434],
lookat=[1.8900, 3.2596, 0.9284],
up=[0.2304, -0.8825, 0.4101])
print('run Poisson surface reconstruction')
with o3d.utility.VerbosityContextManager(
o3d.utility.VerbosityLevel.Debug) as cm:
mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
pcd, depth=9)
print(mesh)
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])
泊松表面重建也會在低點密度區(qū)域創(chuàng)建三角形,甚至推斷到某些區(qū)域(見上面鷹輸出的底部)。函數(shù)create_from_point_cloud_poisson具有第二個返回值densities,該值指示每個頂點的密度。低密度值意味著頂點僅由輸入點云中的少量點支持。
在下面的代碼中,我們使用偽彩色在3D中可視化密度。紫色表示低密度,黃色表示高密度。
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])
我們可以進一步使用密度值來刪除具有低支撐的頂點和三角形。在下面的代碼中,我們刪除了密度值低于0.01所有密度值的分位數(shù)的所有頂點(和連接的三角形)。文章來源:http://www.zghlxwxcb.cn/news/detail-426504.html
print('remove low density vertices')
vertices_to_remove = densities < np.quantile(densities, 0.01)
mesh.remove_vertices_by_mask(vertices_to_remove)
print(mesh)
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])
Normal estimation 法線估計
在上面的例子中,我們假設(shè)點云具有指向外部的法線。但是,并非所有點云都已附帶相關(guān)的法線。Open3D 可用estimate_normals估計點云法線,其局部擬合每個 3D 點的平面以推導(dǎo)出法線。但是,估計的法線可能不是一致的。 orient_normals_consistent_tangent_plane使用最小生成樹傳播法線。文章來源地址http://www.zghlxwxcb.cn/news/detail-426504.html
bunny = o3d.data.BunnyMesh()
gt_mesh = o3d.io.read_triangle_mesh(bunny.path)
pcd = gt_mesh.sample_points_poisson_disk(5000)
pcd.normals = o3d.utility.Vector3dVector(np.zeros(
(1, 3))) # invalidate existing normals
pcd.estimate_normals()
o3d.visualization.draw_geometries([pcd], point_show_normal=True)
pcd.orient_normals_consistent_tangent_plane(100)
o3d.visualization.draw_geometries([pcd], point_show_normal=True)
到了這里,關(guān)于Open3D Surface reconstruction 表面重建的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!