均匀点云边界检测——密度查找(1/2)

点云边界

点云的边界一般认为是数据点的边缘,边缘寻找的方法大家第一时间想到的应该是都熟知的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。这种分割因素过于单一,就会造成密度稀疏的区域好分割,而密度高的区域就不明显了。

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
基于PCL(Point Cloud Library)的点云边界提取可以通过以下步骤实现: 首先,需要加载点云数据,可以从文件中加载或者实时采集。 其次,利用PCL中的NormalEstimation类估计点云数据的法向量。法向量是计算边界的重要依据,能够帮助确定点云中的表面变化。 然后,使用PCL中的BoundaryEstimation类来估计点云的边界。该类会根据法向量和点云数据的几何信息来确定点云的边界点,生成一个包含边界点索引的输出向量。 最后,可以根据边界点的索引,从原始点云数据中提取出边界点的信息,包括坐标和其他属性。 以下是一个简单的C++代码示例,演示了如何使用PCL进行点云的边界提取: ```cpp #include <pcl/point_cloud.h> #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d.h> #include <pcl/features/boundary.h> int main () { // 读取点云数据 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile ("cloud.pcd", *cloud); // 估计法向量 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; ne.setInputCloud (cloud); pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ()); ne.setSearchMethod (tree); pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>); ne.setKSearch (20); ne.compute (*normals); // 边界提取 pcl::BoundaryEstimation<pcl::PointXYZ, pcl::Normal, pcl::Boundary> est; pcl::PointCloud<pcl::Boundary> boundaries; est.setInputCloud (cloud); est.setInputNormals (normals); est.setRadiusSearch (0.02); est.setAngleThreshold (M_PI/4); est.setSearchMethod (tree); est.compute (boundaries); // 提取边界点 for (size_t i = 0; i < boundaries.points.size (); ++i) { if (boundaries.points[i].boundary_point) std::cout << "边界点索引: " << i << " - " << cloud->points[i].x << " " << cloud->points[i].y << " " << cloud->points[i].z << std::endl; } return (0); } ``` 这段代码首先加载了一个点云数据文件"cloud.pcd",然后进行法向量估计和边界提取,最后输出了边界点的坐标信息。通过这个代码示例,可以实现基于PCL的点云边界提取功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三尺流流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值