PointCloudLib 法线微分算法(Don)分割点云 C++版本

0.实现效果

原始点云

不同尺度上计算法向量

计算出don特征量,并以颜色显示在点云上

可以看出平面中心的点 不涉及到周围点变化的点 特征量比较低,以红色表示

边缘过渡剧烈的点,特征量比较高,以蓝色表示

以Don算法特征量来作为阈值分割点云,可以分割出剧烈变化的点云

欧式聚类 分割出不同的点云

### 使用法线向量对点云进行分割 点云分割是一种常见的技术,用于将点云中的不同部分分离出来以便进一步处理。通过利用法线向量的信息可以有效地完成这一任务。以下是基于法线向量的点云分割算法的具体实现方法: #### 法线计算 为了使用法线向量进行分割,首先需要为点云中的每个点估计其局部表面法线方向。这通常可以通过拟合平面到邻近点来完成。具体来说,对于每一个点 \( p_i \),在其 k 近邻范围内找到一组点并对其进行最小二乘拟合得到一个最佳拟合平面[^1]。 ```python import numpy as np from sklearn.neighbors import NearestNeighbors def estimate_normals(points, k=10): """ Estimate normals for each point in the given point cloud. :param points: Numpy array of shape (n_points, 3), representing the point cloud. :param k: Number of nearest neighbors to consider for normal estimation. :return: Array of estimated normals, same size as `points`. """ nbrs = NearestNeighbors(n_neighbors=k).fit(points) _, indices = nbrs.kneighbors(points) normals = [] for i in range(len(points)): neighborhood = points[indices[i]] cov_matrix = np.cov((neighborhood - points[i]).T) eigenvalues, eigenvectors = np.linalg.eig(cov_matrix) normal = eigenvectors[:, np.argmin(eigenvalues)] normals.append(normal / np.linalg.norm(normal)) return np.array(normals) ``` #### 基于法线角度差异的聚类 一旦获得了每一点的法线向量,则可以根据这些法线之间的夹角来进行区域划分。如果两个相邻点的法线之间形成的夹角超过某个阈值,则认为它们属于不同的曲面片段[^2]。 ```python def segment_by_normal_angle(points, normals, angle_threshold=np.radians(30)): """ Segment the point cloud based on differences between their normal vectors' angles. :param points: Point coordinates as an Nx3 matrix. :param normals: Corresponding unit-length normals per point also shaped like Nx3. :param angle_threshold: Maximum allowable deviation from parallelism before considering two regions distinct. :returns List containing sets corresponding to individual segments found within input data set. """ labels = [-1]*len(points) # Initialize all unassigned (-1 means no group yet.) current_label = 0 stack = [] visited = set() def add_to_stack(index): nonlocal stack if index not in visited: stack.append(index) visited.add(index) for start_index in range(len(points)): if labels[start_index]!=-1 or start_index in visited: continue labels[start_index]=current_label stack=[start_index] while len(stack)>0: idx = stack.pop() pt = points[idx] nrm = normals[idx] knn_indices = get_knn_indices(idx,k=15)[1:] # Exclude self for neighbor_idx in knn_indices: diff_vec = normals[neighbor_idx]-nrm cosine_similarity = abs(np.dot(diff_vec/np.linalg.norm(diff_vec),nrm)) if cosine_similarity >= np.cos(angle_threshold): if labels[neighbor_idx]==-1: labels[neighbor_idx]=current_label add_to_stack(neighbor_idx) current_label +=1 unique_labels = list(set(labels)) result_segments = [[]for _ in unique_labels ] for l,pnt in zip(labels,points): result_segments[l].append(pnt) return [np.array(seg) for seg in result_segments],labels ``` 上述代码实现了基本的功能框架,实际应用可能还需要考虑更多细节优化性能以及鲁棒性等问题[^3]。 #### 总结 以上展示了如何借助法线信息执行简单的点云分割操作。这种方法依赖于几何特性,在许多场景下表现良好,但对于复杂结构或者噪声较大的情况则需引入更高级别的模型辅助分析[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

黄晓魚

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

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

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

打赏作者

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

抵扣说明:

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

余额充值