点云边界
点云的边界一般认为是数据点的边缘,边缘寻找的方法大家第一时间想到的应该是都熟知的alpha shape方法,但是alphashape的方法适用于二维平面的点云,对于三维的点云的处理效果表现为凸起的块体描边。
这种边界很精细,但是也存在缺点。对于空间中近似平面的单层三维点云,alphashape并不怎么好用。需要转换一下边界的判断思路。
kd树
我们现持有一份均匀的单层点云,想要知道某处点云的密度,首先需要理解临近搜索的原理。
针对三维数据,需要在三个维度上建立点云数据之间的拓扑信息。点云建立拓扑结构的三维划分规则,基于结构中点划分两个区域,最终将整体点划分成每一枝上的子树上只有一个点的树结构。
kd = o3d.geometry.KDTreeFlann(pcd)
kd树的结构能够帮我们快速的反映出当前查询点周围一定范围内点的个数。
Kd树半径搜索
半径搜索是基于kd树结构的临近范围内点查找,其中idx即为周围点的索引矩阵。
pcd.points[i]:当前查询点。
0.08:查询半径。
[k, idx, _] = kd.search_radius_vector_3d(pcd.points[i], 0.08)
边界密度特征
单层点云中靠近边界点的密度一般都会比内部的点密度要小。
图中,P1周围点密度是要比P2点密度更低的。但是某些特殊点云不一定符合这类特征,我们在下一节再讨论。
完整代码
import open3d as o3d
import numpy as np
pcd = o3d.io.read_point_cloud(".../crack001_pcd.pcd")
pcd.paint_uniform_color([0.5, 0.5, 0.5])
pcd_tree = o3d.geometry.KDTreeFlann(pcd)
k_recordlist = []
idx1_recordlist = []
for i in range(len(pcd.points)):
[k1, idx1, _] = pcd_tree.search_radius_vector_3d(pcd.points[i], 0.1)#半径搜索
k_recordlist.append(k1)
idx1_recordlist.append(idx1)
if k_recordlist[i] <= 15:#max(k_de_recordlist) - k_de_recordlist[0] > 15 or
np.asarray(pcd.colors)[i] = [0, 0, 1]
o3d.visualization.draw_geometries([pcd])
图中可以看到左侧的点即使是在边界仍然有部分点未能被分割出来。这是由于我们的分割阈值为15:k_recordlist[i] <= 15。这种分割因素过于单一,就会造成密度稀疏的区域好分割,而密度高的区域就不明显了。