OPEN3D学习笔记(二)
Mesh
Open3D具有3D三角形网格的数据结构,称为TriangleMesh。下面的代码显示了如何从层中读取三角形网格并打印其顶点和三角形。
print("Testing mesh in open3d ...")
mesh = o3dtut.get_knot_mesh()
print(mesh)
print('Vertices:')
print(np.asarray(mesh.vertices)) # 每个点的坐标xyz
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]]
'''
可视化Mesh
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)
您可以旋转和移动网格,但是网格被涂成均匀的灰色,看起来不像“ 3d”。原因是当前网格没有顶点或面的法线。因此,使用统一的颜色底纹代替更复杂的Phong底纹。
表面法线估计
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]]
'''
裁剪Mesh
通过直接在网格的三角形和triangle_normals数据字段上进行操作,可以去除表面的一半。这是通过numpy完成的。
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])
Mesh网格属性(不太懂)
1.is_edge_manifold 和 is_vertex_manifold
如果每个边都边界一个或两个三角形,则三角形网格是边缘流形edge manifold
函数is_edge_manifold具有bool参数allow_boundary_edges,该参数定义是否应允许有界边
此外,如果顶点的星形是边缘流形和边缘连接的,例如两个或多个仅通过顶点而不通过边缘连接的面,则三角形网格是顶点流形vertex manifold
2.另一个特性是自相交的测试。如果网格中存在与另一个网格相交的三角形,则函数is_self_intersecting返回True。可以将水密网格定义为边缘流形,顶点流形并且不自相交的网格。函数is_watertight在Open3D中实现此检查。
3.我们也可以测试三角形网格(如果它是可定向的),即三角形可以以所有法线指向外部的方式定向。Open3D中的相应功能称为is_orientable。
网格过滤
平均过滤器(Average filter)
拉普拉斯式(Laplacian)
陶宾过滤器(Taubin filter)
采样(Sampling)
网格细分
Mesh subdivision
在网格细分中,我们将每个三角形划分为多个较小的三角形。在最简单的情况下,我们计算每个三角形每侧的中点,并将三角形划分为四个较小的三角形。这是在subdivide_midpoint函数中实现的。3D曲面和面积保持不变,但顶点和三角形的数量增加。参数number_of_iterations定义重复此过程的频率。
网格简化
有时,我们希望用较少的三角形和顶点来表示高分辨率的网格,但是低分辨率的网格仍然应该接近高分辨率的网格。为此,Open3D实现了许多网格简化方法。
顶点聚类、网格抽取
连接的组建
先跳过
Transformation
Translate平移
vt=v+t
在某个左边实现值的位移,相对的
mesh = o3d.geometry.TriangleMesh.create_coordinate_frame() # 直接就是坐标轴,没有点的
mesh_tx = copy.deepcopy(mesh).translate((1.3,0,0))
mesh_ty = copy.deepcopy(mesh).translate((0,1.3,0))
print(f'Center of mesh: {mesh.get_center()}')
print(f'Center of mesh tx: {mesh_tx.get_center()}') # get_center()返回顶点的均值
print(f'Center of mesh ty: {mesh_ty.get_center()}')
o3d.visualization.draw_geometries([mesh, mesh_tx, mesh_ty])
'''
输出:
Center of mesh: [0.05167549 0.05167549 0.05167549]
Center of mesh tx: [1.35167549 0.05167549 0.05167549]
Center of mesh ty: [0.05167549 1.35167549 0.05167549]
'''
该方法采用relative第二个参数,默认设置为true。如果将其更改为False,则几何中心将直接平移到第一个参数中指定的位置。(绝对的)
mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()
mesh_mv = copy.deepcopy(mesh).translate((2,2,2), relative=False)
print(f'Center of mesh: {mesh.get_center()}')
print(f'Center of translated mesh: {mesh_mv.get_center()}')
o3d.visualization.draw_geometries([mesh, mesh_mv])
# 输出
# Center of mesh: [0.05167549 0.05167549 0.05167549]
# Center of translated mesh: [2. 2. 2.]
Rotation旋转
Convert from Euler angles with get_rotation_matrix_from_xyz (where xyz can also be of the form yzx zxy, xzy, zyx, and yxz)
Convert from Axis-angle representation with get_rotation_matrix_from_axis_angle
Convert from Quaternions with get_rotation_matrix_from_quaternion
函数rotate具有第二个参数中心,默认情况下设置为True。这表明对象在应用旋转之前先居中,然后又移回其先前的中心。如果将此参数设置为False,则将直接应用旋转,这将围绕坐标中心旋转整个几何。这意味着旋转后可以更改网格中心。
Scale缩放
vs=s⋅v
mesh = o3d.geometry.TriangleMesh.create_coordinate_frame() # 坐标轴
mesh_s = copy.deepcopy(mesh).translate((2,1,0))
mesh_s.scale(0.5, center=(0,0,0)) # 缩放,是原来的0.5倍
o3d.visualization.draw_geometries([mesh, mesh_s])
General transformation一般转换
用4*4的矩阵
mesh = o3d.geometry.TriangleMesh.create_coordinate_frame()
T = np.eye(4) # 生成一个矩阵,4*4的,对角线为1
T[:3,:3] = mesh.get_rotation_matrix_from_xyz((0,np.pi/3, np.pi/2)) # 定义旋转矩阵
T[0,3] = 1
T[1,3] = 1.3 # 定义平移向量
print(T)
mesh_t = copy.deepcopy(mesh).transform(T)
o3d.visualization.draw_geometries([mesh, mesh_t])
'''
[[ 3.06161700e-17 -5.00000000e-01 8.66025404e-01 1.00000000e+00]
[ 1.00000000e+00 6.12323400e-17 0.00000000e+00 1.30000000e+00]
[-5.30287619e-17 8.66025404e-01 5.00000000e-01 0.00000000e+00]
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]]
'''