一、补充一些小知识

1、以mesh方式读取ply文件

import open3d as o3d

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

龙

2.旋转矩阵

三维模型使用R,T两个参数来变换,视图的空间坐标系建立:向上为z轴,向右为y轴,x轴指向屏幕前。使用transform方法变换坐标,变换矩阵为[4*4]的矩阵,transform([[R, T], [0, 1]])
正常读取一个ply文件:

import open3d as o3d

pcd = o3d.io.read_point_cloud("mode/Fantasy Dragon.ply")
o3d.visualization.draw_geometries([pcd], width=1280, height=720)

显示效果如图:在这里插入图片描述
使用转换函数,把他横着放,且头部面向屏幕。那么就是将原来的z轴换到y轴,y轴换到x轴,x轴换到z轴,所以代码为:

import open3d as o3d
mesh = o3d.io.read_triangle_mesh("mode/Fantasy Dragon.ply")
mesh.compute_vertex_normals()
mesh.transform([[0, 1, 0, 0], [0, 0, 1, 0], [1, 0, 0, 0], [0, 0, 0, 1]])
o3d.visualization.draw_geometries([mesh], width=1280, height=720)

效果:在这里插入图片描述

二、转化为点云的方式

1、转化为numpy数组再重新绘制成点云

import open3d as o3d
import numpy as np

mesh = o3d.io.read_triangle_mesh("mode/Fantasy Dragon.ply")
mesh.compute_vertex_normals()
v_mesh = np.asarray(mesh.vertices)

pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(v_mesh)
o3d.visualization.draw_geometries([pcd], width=1280, height=720)

在这里插入图片描述
对于ply格式的文件还好,但若是stl这种三角形网格,转化的结果会有点不理想。
在这里插入图片描述

2、采样

open3d提供了一种采样方式,可设置采样点,简化模型。

import open3d as o3d

mesh = o3d.io.read_triangle_mesh("mode/ganyu.STL")
mesh.compute_vertex_normals()
pcd = o3d.geometry.TriangleMesh.sample_points_uniformly(mesh, number_of_points=10000) # 采样点云
o3d.visualization.draw_geometries([pcd], width=1280, height=720)

在这里插入图片描述

三、体素化

体素化,能简化模型,得到均匀网格。

将三角网格转化为体素网格

import open3d as o3d
import numpy as np

print("Load a ply point cloud, print it, and render it")
mesh = o3d.io.read_triangle_mesh("mode/ganyu.STL")
mesh.compute_vertex_normals()

mesh.scale(1 / np.max(mesh.get_max_bound() - mesh.get_min_bound()), center=mesh.get_center())

voxel_grid = o3d.geometry.VoxelGrid.create_from_triangle_mesh(mesh, voxel_size=0.05)

o3d.visualization.draw_geometries([voxel_grid], width=1280, height=720)

在这里插入图片描述

点云生成体素网格

import open3d as o3d
import numpy as np

print("Load a ply point cloud, print it, and render it")
pcd = o3d.io.read_point_cloud("mode/Fantasy Dragon.ply")

pcd.scale(1 / np.max(pcd.get_max_bound() - pcd.get_min_bound()), center=pcd.get_center())
pcd.colors = o3d.utility.Vector3dVector(np.random.uniform(0,1,size=(2000,3)))

print('voxelization')
voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, voxel_size=0.05)

o3d.visualization.draw_geometries([voxel_grid], width=1280, height=720)

在这里插入图片描述

四、顶点法线估计

voxel_down_pcd = pcd.voxel_down_sample(voxel_size=0.05)
voxel_down_pcd.estimate_normals(
    search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.1, max_nn=30))
o3d.visualization.draw_geometries([voxel_down_pcd], point_show_normal=True, width=1280, height=720)

estimate_normals计算每个点的法线。该函数查找相邻点并使用协方差分析计算相邻点的主轴。
该函数将KDTreeSearchParamHybrid类的实例作为参数。两个关键参数为指定搜索半径和最大最近邻。
radius=0.1, max_nn=30即以10cm为搜索半径,并最多只考虑30个临近点以节省计算时间。

在这里插入图片描述

读取法线向量

print("打印第一个向量:")
print(voxel_down_pcd.normals[0])

#打印第一个向量:
#[ 0.51941952  0.82116269 -0.23642166]

#打印前十个法线向量
print(np.asarray(voxel_down_pcd.normals)[:10,:])

五、值得注意的点

  1. pcd格式文件属于点云类型,ply可同时使用点云以及网格方式读取,用mesh读取时,可当三角网格处理,用pcd读取可直接当点云数据处理。
  2. 三角网格直接采样再计算法线会出现法线标注出错的情况,即法线全部指向一个方向。
  3. 要避免采样法线出错可使用sample_points_poisson_disk()方法采样。