# Open3d学习计划（4)网格

Open3D是一个开源库，支持快速开发和处理3D数据。Open3D在c++和Python中公开了一组精心选择的数据结构和算法。后端是高度优化的，并且是为并行化而设置的。

open3d有一种被称为TriangleMesh的3d三角网格的数据结构。下面的代码展示了如何从一个ply文件读取三角网格数据并且打印它的顶点和三角形。

print("Testing mesh in open3d ...")
mesh = o3dtut.get_knot_mesh()
print(mesh)
print('Vertices:')
print(np.asarray(mesh.vertices))
print('Triangles:')
print(np.asarray(mesh.triangles))

>>>>Testing mesh in open3d ...
>>>>geometry::TriangleMesh with 1440 points and 2880 triangles.
>>>>Vertices:
>>>>[[  4.51268387  28.68865967 -76.55680847]
[  7.63622284  35.52046967 -69.78063965]
[  6.21986008  44.22465134 -64.82303619]
...
[-22.12651634  31.28466606 -87.37570953]
[-13.91188431  25.4865818  -86.25827026]
[ -5.27768707  23.36245346 -81.43279266]]
>>>>Triangles:
[[   0   12   13]
[   0   13    1]
[   1   13   14]
...
[1438   11 1439]
[1439   11    0]
[1439    0 1428]]

TriangleMesh类是有像vertices和triangles这些数据字段的。open3d通过numpy直接对这些字段进行访问。

print("Try to render a mesh with normals (exist: " +
str(mesh.has_vertex_normals()) + ") and colors (exist: " +
str(mesh.has_vertex_colors()) + ")")
o3d.visualization.draw_geometries([mesh])
print("A mesh with no normals and no colors does not look good.")

>>>>Try to render a mesh with normals (exist: True) and colors (exist: False)

print("Computing normal and rendering it.")
mesh.compute_vertex_normals()
print(np.asarray(mesh.triangle_normals))
o3d.visualization.draw_geometries([mesh])

>>>>Computing normal and rendering it.
[[ 0.79164373 -0.53951444  0.28674793]
[ 0.8319824  -0.53303008  0.15389681]
[ 0.83488162 -0.09250101  0.54260136]
...
[ 0.16269924 -0.76215917 -0.6266118 ]
[ 0.52755226 -0.83707495 -0.14489352]
[ 0.56778973 -0.76467734 -0.30476777]]

print("We make a partial mesh of only the first half triangles.")
mesh1 = copy.deepcopy(mesh)
mesh1.triangles = o3d.utility.Vector3iVector(
np.asarray(mesh1.triangles)[:len(mesh1.triangles) // 2, :])
mesh1.triangle_normals = o3d.utility.Vector3dVector(
np.asarray(mesh1.triangle_normals)[:len(mesh1.triangle_normals) // 2, :])
print(mesh1.triangles)
o3d.visualization.draw_geometries([mesh1])

>>>>We make a partial mesh of only the first half triangles.
>>>>std::vector<Eigen::Vector3i> with 1440 elements.
>>>>Use numpy.asarray() to access data.

print("Painting the mesh")
mesh1.paint_uniform_color([1, 0.706, 0])
o3d.visualization.draw_geometries([mesh1])

>>>>Painting the mesh

def check_properties(name, mesh):
mesh.compute_vertex_normals()

edge_manifold = mesh.is_edge_manifold(allow_boundary_edges=True)
edge_manifold_boundary = mesh.is_edge_manifold(allow_boundary_edges=False)
vertex_manifold = mesh.is_vertex_manifold()
self_intersecting = mesh.is_self_intersecting()
watertight = mesh.is_watertight()
orientable = mesh.is_orientable()

print(name)
print(f"  edge_manifold:          {edge_manifold}")
print(f"  edge_manifold_boundary: {edge_manifold_boundary}")
print(f"  vertex_manifold:        {vertex_manifold}")
print(f"  self_intersecting:      {self_intersecting}")
print(f"  watertight:             {watertight}")
print(f"  orientable:             {orientable}")

geoms = [mesh]
if not edge_manifold:
edges = mesh.get_non_manifold_edges(allow_boundary_edges=True)
geoms.append(o3dtut.edges_to_lineset(mesh, edges, (1, 0, 0)))
if not edge_manifold_boundary:
edges = mesh.get_non_manifold_edges(allow_boundary_edges=False)
geoms.append(o3dtut.edges_to_lineset(mesh, edges, (0, 1, 0)))
if not vertex_manifold:
verts = np.asarray(mesh.get_non_manifold_vertices())
pcl = o3d.geometry.PointCloud(
points=o3d.utility.Vector3dVector(np.asarray(mesh.vertices)[verts]))
pcl.paint_uniform_color((0, 0, 1))
geoms.append(pcl)
if self_intersecting:
intersecting_triangles = np.asarray(
mesh.get_self_intersecting_triangles())
intersecting_triangles = intersecting_triangles[0:1]
intersecting_triangles = np.unique(intersecting_triangles)
print("  # visualize self-intersecting triangles")
triangles = np.asarray(mesh.triangles)[intersecting_triangles]
edges = [
np.vstack((triangles[:, i], triangles[:, j]))
for i, j in [(0, 1), (1, 2), (2, 0)]
]
edges = np.hstack(edges).T
edges = o3d.utility.Vector2iVector(edges)
geoms.append(o3dtut.edges_to_lineset(mesh, edges, (1, 0, 1)))
o3d.visualization.draw_geometries(geoms, mesh_show_back_face=True)~
>>>>Moebius
edge_manifold:          True
edge_manifold_boundary: False
vertex_manifold:        True
self_intersecting:      False
watertight:             False
orientable:             False
>>>>non-manifold edge
edge_manifold:          False
edge_manifold_boundary: False
vertex_manifold:        True
self_intersecting:      False
watertight:             False
orientable:             Tru
>>>>open box
edge_manifold:          True
edge_manifold_boundary: False
vertex_manifold:        True
self_intersecting:      False
watertight:             False
orientable:             True
>>>>intersecting_boxes
edge_manifold:          True
edge_manifold_boundary: True
vertex_manifold:        True
self_intersecting:      True
watertight:             False
orientable:             True
# visualize self-intersecting triangles

Open3d包含许多网格滤波的算法。接下来我们将会展示相关的一些滤波接口。

print('create noisy mesh')
mesh_in = o3dtut.get_knot_mesh()
vertices = np.asarray(mesh_in.vertices)
noise = 5
vertices += np.random.uniform(0, noise, size=vertices.shape)
mesh_in.vertices = o3d.utility.Vector3dVector(vertices)
mesh_in.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh_in])

print('filter with average with 1 iteration')
mesh_out = mesh_in.filter_smooth_simple(number_of_iterations=1)
mesh_out.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh_out])

print('filter with average with 5 iterations')
mesh_out = mesh_in.filter_smooth_simple(number_of_iterations=5)
mesh_out.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh_out])

>>>>create noisy mesh

print('filter with Laplacian with 10 iterations')
mesh_out = mesh_in.filter_smooth_laplacian(number_of_iterations=10)
mesh_out.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh_out])

print('filter with Laplacian with 50 iterations')
mesh_out = mesh_in.filter_smooth_laplacian(number_of_iterations=50)
mesh_out.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh_out])

>>>>filter with Laplacian with 10 iterations

Taubin滤波

print('filter with Taubin with 10 iterations')
mesh_out = mesh_in.filter_smooth_taubin(number_of_iterations=10)
mesh_out.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh_out])
print('filter with Taubin with 100 iterations')
mesh_out = mesh_in.filter_smooth_taubin(number_of_iterations=100)
mesh_out.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh_out])

Open3d包含了从网格中采样点云的功能。最简单的方法是使用sample_points_uniformly函数从三角网格的三维表面均匀采样。参数number_of_points表示从网格中采样的点云的点数。

mesh = o3d.geometry.TriangleMesh.create_sphere()
mesh.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh])
pcd = mesh.sample_points_uniformly(number_of_points=500)
o3d.visualization.draw_geometries([pcd])~
mesh = o3dtut.get_bunny_mesh()
mesh.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh])
pcd = mesh.sample_points_uniformly(number_of_points=500)
o3d.visualization.draw_geometries([pcd])

• 默认通过参数init_factor：首先通过init_factor x number_of_points来从网格中均匀采样点云，之后进行消除。
• 可以直接提供一个点云数据给sample_points_poisson_disk函数，之后会进行点云的消除。
mesh = o3d.geometry.TriangleMesh.create_sphere()
pcd = mesh.sample_points_poisson_disk(number_of_points=500, init_factor=5)
o3d.visualization.draw_geometries([pcd])

pcd = mesh.sample_points_uniformly(number_of_points=2500)
pcd = mesh.sample_points_poisson_disk(number_of_points=500, pcl=pcd)
o3d.visualization.draw_geometries([pcd])~

mesh = o3d.geometry.TriangleMesh.create_box()
mesh.compute_vertex_normals()
print(f'The mesh has {len(mesh.vertices)} vertices and {len(mesh.triangles)} triangles')
o3d.visualization.draw_geometries([mesh], zoom=0.8, mesh_show_wireframe=True)
mesh = mesh.subdivide_midpoint(number_of_iterations=1)
print(f'After subdivision it has {len(mesh.vertices)} vertices and {len(mesh.triangles)} triangles')
o3d.visualization.draw_geometries([mesh], zoom=0.8, mesh_show_wireframe=True)

Open3d实现了基于[Loop1987]的附加细分方法。该方法基于四次箱样条，该四边形样条线会在除 C2连续的非凡顶点之外的所有地方生成 C1连续的极限曲面。（The method is based on a quartic box spline, which generate C2continuous limit surfaces everywhere except at extraordinary vertices where they are C1 continuous.）这样可以得到更加平滑的拐角。

mesh = o3d.geometry.TriangleMesh.create_sphere()
mesh.compute_vertex_normals()
print(f'The mesh has {len(mesh.vertices)} vertices and {len(mesh.triangles)} triangles')
o3d.visualization.draw_geometries([mesh], zoom=0.8, mesh_show_wireframe=True)
mesh = mesh.subdivide_loop(number_of_iterations=2)
print(f'After subdivision it has {len(mesh.vertices)} vertices and {len(mesh.triangles)} triangles')
o3d.visualization.draw_geometries([mesh], zoom=0.8, mesh_show_wireframe=True)

mesh_in = o3dtut.get_bunny_mesh()
print(f'Input mesh has {len(mesh_in.vertices)} vertices and {len(mesh_in.triangles)} triangles')
o3d.visualization.draw_geometries([mesh_in])

voxel_size = max(mesh_in.get_max_bound() - mesh_in.get_min_bound()) / 32
print(f'voxel_size = {voxel_size:e}')
mesh_smp = mesh_in.simplify_vertex_clustering(
voxel_size=voxel_size,
contraction=o3d.geometry.SimplificationContraction.Average)
print(f'Simplified mesh has {len(mesh_smp.vertices)} vertices and {len(mesh_smp.triangles)} triangles')
o3d.visualization.draw_geometries([mesh_smp])

voxel_size = max(mesh_in.get_max_bound() - mesh_in.get_min_bound()) / 16
print(f'voxel_size = {voxel_size:e}')
mesh_smp = mesh_in.simplify_vertex_clustering(
voxel_size=voxel_size,
contraction=o3d.geometry.SimplificationContraction.Average)
print(f'Simplified mesh has {len(mesh_smp.vertices)} vertices and {len(mesh_smp.triangles)} triangles')
o3d.visualization.draw_geometries([mesh_smp])~

mesh_smp = mesh_in.simplify_quadric_decimation(
target_number_of_triangles=6500)
print(f'Simplified mesh has {len(mesh_smp.vertices)} vertices and {len(mesh_smp.triangles)} triangles')
o3d.visualization.draw_geometries([mesh_smp])

target_number_of_triangles=1700)
print(f'Simplified mesh has {len(mesh_smp.vertices)} vertices and {len(mesh_smp.triangles)} triangles')
o3d.visualization.draw_geometries([mesh_smp])

print("Generate data")

mesh = o3dtut.get_bunny_mesh().subdivide_midpoint(number_of_iterations=2)

vert = np.asarray(mesh.vertices)

min_vert, max_vert = vert.min(axis=0), vert.max(axis=0)

for _ in range(30):

cube = o3d.geometry.TriangleMesh.create_box()

cube.scale(0.005, center=cube.get_center())

cube.translate(

(

np.random.uniform(min_vert[0], max_vert[0]),

np.random.uniform(min_vert[1], max_vert[1]),

np.random.uniform(min_vert[2], max_vert[2]),

),

relative=False,

)

mesh += cube

mesh.compute_vertex_normals()

print("Show input mesh")

o3d.visualization.draw_geometries([mesh])~

0 条评论

• ### Open3d学习计划（3)变换

Open3D是一个开源库，支持快速开发和处理3D数据。Open3D在c++和Python中公开了一组精心选择的数据结构和算法。后端是高度优化的，并且是为并行化而...

• ### 分享—PCL 编译成.net可用的 DLL

这是关于PCL 编译成.net可用的DLL ，来自于ccjia的分享，希望大家都能够踊跃的敢于分享，

• ### PCL 1.8.0+VS 2015配置经历分享

作为一个新手，我这次配置该环境的主要目的是运行相关文件，因此对一些原理并没有深入了解，所以只能说一说我配置的过程。（其实很多情况弄得我摸不着头脑，仿佛又回到了做...

• ### Open3d学习计划（3)变换

Open3D是一个开源库，支持快速开发和处理3D数据。Open3D在c++和Python中公开了一组精心选择的数据结构和算法。后端是高度优化的，并且是为并行化而...

• ### C# winform用sharpGL（OpenGl）解析读取3D模型obj

自己写了个简单的类读取解析obj模型，使用导入类，然后new个对象，在读取obj模型，然后调用显示列表显示就可以了。至于其他什么旋转移动的你们自己加起来应该很容...

• ### python 操作excel

python 读写 excel 有好多选择，但是，方便操作的库不多，在我尝试了几个库之后，我觉得两个比较方便的库分别是 xlrd/xlwt、openpyxl。

• ### go语言学习-类型转换

1.字符串到整形(string to int)：ParseInt 返回的是 int64

• ### 神经网络和深度学习（三） ——浅层神经网络的表示与输出

神经网络和深度学习（三）——浅层神经网络的表示与输出 （原创内容，转载请注明来源，谢谢） 一、神经网络的表示 神经网络，实质上是一些输入，经过多层神经元的处理...

• ### “夹心饼干”微软WMR求突破，布局商业领域是个好方法？

在HTC Vive和Oculus Rifit等PC头显，与Oculus Go等VR一体机的夹击下，微软WMR布局To B领域，或许是个不错的策略。但前路依然困难...