numpy转open3D需要借助Vector3dVector函数,这样可以直接赋值与open3d.PointCloud.points,具体操作如下,假设xyz、nxnynz、rgb分别是一个n*3numpy数组,则对于点数,法向量和颜色的转换都可以借助Vector3dVector函数,具体操作如下:
import numpy as np
import open3D as o3d
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(xyz)
pcd.normals = o3d.utility.Vector3dVector(nxnynz)
pcd.colors = o3d.utility.Vector3dVector(rgb)
import numpy as np
import open3d as o3d
# Load saved point cloud and visualize it
pcd_load = o3d.io.read_point_cloud("../../TestData/sync.ply")
# convert Open3D.o3d.geometry.PointCloud to numpy array
xyz_load = np.asarray(pcd_load.points)
o3d.visualization.draw_geometries([pcd_load])
从numpy中创建mesh
def show_mesh(verts,faces):
mesh=o3d.geometry.TriangleMesh.create_coordinate_frame()
mesh.clear()
mesh.vertices=o3d.utility.Vector3dVector(verts)
mesh.triangles=o3d.utility.Vector3iVector(faces)
mesh.compute_vertex_normals()
frame=o3d.geometry.TriangleMesh.create_coordinate_frame()
frame.scale(2, center=(0,0,0))
o3d.visualization.draw_geometries([mesh,frame])
def show_mesh(verts,faces):
mesh=o3d.geometry.TriangleMesh.create_coordinate_frame()
# mesh.clear()
mesh.vertices=o3d.utility.Vector3dVector(verts)
mesh.triangles=o3d.utility.Vector3iVector(faces)
mesh.compute_vertex_normals()
frame=o3d.geometry.TriangleMesh.create_coordinate_frame()
frame.scale(0.5, center=(0,0,0))
o3d.visualization.draw_geometries([mesh,frame],mesh_show_back_face=True)
mesh_show_back_face=True如果不设置的话模型中会有一些空洞
laptop_points=mean_points[4]
pcd=o3d.geometry.PointCloud()
pcd.points=o3d.utility.Vector3dVector(laptop_points)
# visutil.show_3d(laptop_points,laptop_points,[0,0,0],[0,0,0])
# laptop_mesh,_=pcd.compute_convex_hull()
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):
alpha=0.136
print(f"alpha={alpha:.3f}")
laptop_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(
pcd, alpha, tetra_mesh, pt_map)
laptop_mesh.compute_vertex_normals()
o3d.visualization.draw_geometries([laptop_mesh], mesh_show_back_face=True)
一、无穷值和非数点的剔除
该功能可筛选出点云中坐标值为以下两种类型的点:
坐标值为NaN(not a number,非数)的点,通常为未定义或不可表示的坐标值点。坐标值为Infinite(无穷大)的点,包含正向和负向的无穷大坐标值点。
import open3d as o3d
pcd = o3d.io.read_point_cloud(path) # path为文件路径
pcd_new = o3d.geometry.PointCloud.remove_non_finite_points(
pcd, remove_nan = True, remove_infinite = False)
#remove_nan和remove_infinite参数均包含两个类型值,True和False分别为剔除非数点和无穷值点
二、孤点滤波
此处孤点滤波就是半径滤波,在点云数据中,指定每个的点一定范围内周围至少要有足够多的近邻。例如,如果指定至少要有1个邻居,只有黄色的点会被删除,如果指定至少要有2个邻居,黄色和绿色的点都将被删除。
pcd_new = o3d.geometry.PointCloud.remove_radius_outlier(pcd, knn, radius)
#knn参数为选择邻近点个数,radius参数为设置的半径
三、统计学滤波
统计学滤波用于去除明显离群点。离群点特征是在空间中分布稀疏,考虑到离群点的特征,则可以定义某处点云小于某个密度,既点云无效。对每个点的邻域进行一个统计分析,并修剪掉一些不符合标准的点。具体方法为在输入数据中对点到临近点的距离分布的计算,对每一个点,计算它到所有临近点的平均距离(假设得到的结果是一个高斯分布,其形状是由均值和标准差决定),那么平均距离在标准范围之外的点,可以被定义为离群点并从数据中去除。特点:主要是根据密度去除离群点,对密度差异较大的离群点去除效果较好。
pcd_new = o3d.geometry.PointCloud.remove_statistical_outlier(pcd, knn, std)
#knn参数为选择邻近点个数,std参数为设置的标准差阈值
四、RANSAC分割平面
RANSAC(Random Sample Consensus)是根据一组包含异常数据的样本数据集,计算出数据的数学模型参数,得到有效样本数据的算法。
RANSAC算法的基本假设是样本中包含正确数据(inliers,可以被模型描述的数据),也包含异常数据(outliers,偏离正常范围很远、无法适应数学模型的数据),即数据集中含有噪声。这些异常数据可能是由于错误的测量、错误的假设、错误的计算等产生的。同时RANSAC也假设,给定一组正确的数据,存在可以计算出符合这些数据的模型参数的方法。
在拟合平面(地面)这一需求上,平面的凹凸点(小的坑洼)是有效数据,但对所需平面来说有一定的偏移。而大的凹凸,比如地面上的障碍物、地面的深坑,这些都是偏移量过大的无效数据。最小二乘拟合,旨在照顾所有人的想法,对所有数据进行拟合,在无效数据多且偏移量大的情况下,拟合效果不好。而RANSAC拟合,旨在照顾多数人的意愿,对主体数据进行拟合,手动设置一个阈值,同拟合平面的距离超过阈值的点,就被判定为无效数据。随机拟合多个平面,选取平面内数据点最多的平面,或者说,无效数据最少的平面,作为拟合出的结果。根据如上思路,RANSAC在拟合平面这一需求上,可以得到更准确的结果。
plane_model, inliers = pcd.segment_plane(distance_threshold=dis, ransac_n=rnn, num_iterations=n)
# distance_threshold为距离阈值参数,ransac_n为RANSAC迭代的点数,num_iterations为最大迭代次数
pcd_in = pcd.select_by_index(inliers) # RANSAC分割后的内部点云(拟合平面点)
pcd_out = pcd.select_by_index(inliers, invert=True) # RANSAC分割后的外部点云(拟合平面之外的点
for id,file in enumerate(nut_file_list+screw_file_list+hnm_file_list):
id2file[id+1]=file
file2id[file]=id+1
out=os.path.join(out_path,'{}.ply'.format(id+1))
ms=pymeshlab.MeshSet()
ms.load_new_mesh(os.path.join(cat_path,file))
m=ms.current_mesh()
bbox=m.bounding_box()
max=bbox.max()
min=bbox.min()
ms.save_current_mesh(out)
mesh=trimesh.load(out)
quad=mesh.faces
bbox = mesh.bounding_box.bounds
loc = (bbox[0] + bbox[1]) / 2
mesh.apply_translation(-loc)
result = trimesh.exchange.ply.export_ply(mesh, encoding='ascii')
output_file = open(out, "wb+")
output_file.write(result)
output_file.close()
# trimesh.exchange.export.exp
在trimesh load 过程中会自动merge一些靠近的顶点,导致model 不watertight 解决方法是设置process=False