图形处理(八)点云重建(上)点云滤波、尖锐特征边增采样、移除离群点

之前帮导师搞过一个项目,涉及点云尖锐的特征边重建技术,很多文献看起来效果很好,然而都是坑爹的算法,鲁邦性很差,比如这篇paper《Feature Sensitive Surface Extraction from Volume Data》把我坑的好惨,网上没有提供源代码,最主要的是这篇paper的引用率貌似还可以,于是我花了一周的时间,终于把代码写出来了,结果效果鲁棒性好差。下面的图,就是那篇paper的坑爹图,最后一张看起来,尖锐特征边的重建效果,真不是一般的好,坑害了多少菜鸟。


点云的尖锐特征边重建,有一些文献,如《Dual Marching Cubes: Primal Contouring of Dual Grids》、《Cubical Marching Squares: Adaptive Feature Preserving Surface Extraction from Volume Data》、《Feature Preserving Point Set Surfaces based on Non-Linear Kernel Regression》,然而搞了一个月,最后我感觉这些paper都不靠谱。

最后我是用了,在预处理阶段,进行特征边点云的增采样,才勉强把特征边重建出比较好的结果。我们知道,对于点云的重建,其实最关键的还是对点云的滤波,法矢求取等步骤,因此预处理对点云重建至关重要。最后我的预处理算法,主要是参考了paper的特征边增采样技术。

下面我以正方体点云模型的重建为示例,讲解算法如何,重建出正方体模型的特征边流程。

       

正方体点云模型(普通视图、前视图)

主要算法参考文献为《Edge-Aware Point Set Resampling》,算法具体流程如下:

①法矢初步估算

这一步主要是使用了加权的PCA算法,PCA算法是点云法矢计算的常用算法。

a.均匀权的pi点法矢计算公式为:


其中pj为p点的k近邻。然后通过求解协方差矩阵M的最小特征值的特征向量,作为p点的法向量,这就是所谓的主元分析方法PCA

b.基于高斯权重的主元分析方法:

原来的方法,采用的是均匀权重的方法(1/k),把均匀权改为高斯权:


通过求解M的最小特征值的特征向量,获得p点的法向量,其中参数σ可以选择跟点云密度相关的参数。看一下我用两个不同的权的计算结果的区别:

     

由以上结果可知,采用高斯权重,对于正方体的尖锐特征边的法矢求取显然效果好很多。因为法矢的求取好坏直接决定了三维点云重建的效果好坏的关键。因此我们选用高斯权重进行PCA法矢求取。

② bilateral normal smoothing(法矢平滑)

这一步是通过双边滤波的方法进行异向法矢平滑,因为仅仅靠第一步的算法,鲁棒性还不够,因此paper《Edge-Aware Point Set Resampling》接着又进行了异向法矢平滑。通过①我们可计算得每个点的初步法矢,接着根据下面公式进行迭代,可获得平滑后的法矢,p点法矢的迭代公式为:

同样的pj为p点的k近邻。其中,参数σ可以选择跟点云密度相关的参数,σn为角度阈值(默认选择15°),迭代次数选择2~5次合适(默认选择迭代2次,效果还不错),最后法矢异性滤波结果如下:


由结果可知,相比于第一步的结果,我们的法矢求取效果又提升了不少,这是点云重建预处理的关键一步。

③异向优化投影WLOP

上面那一步是对点云的法矢进行保特征滤波,这一步的目的是对点云进行保边缘滤波。文献的作者选择了WLOP算法,进行点云滤波去噪。这一步不仅可以实现去噪,同时可实现把特征边上的点位置调整,使靠近特征边的点远离特征边,如下图所示:


异向WLOP滤波算法,迭代公式为:





其中,u为常数(默认选择0.45),其中p表示最原始的点云位置,p’表示迭代后新位置,k为邻接顶点的个数(默认选择16)、分别为相关的权值系数,其计算公式如下:

             

OK,接着看一下我用这个算法接着进行点云滤波的结果图:


是不是感觉滤波后,效果又更上一层楼了,进行WLOP滤波后,特征边的地方点云的密度会大大减小,因此接着paper提出了文献的创新点,特征边曾采样技术。

④resampling(特征区域采样)

实现对特征边密集采样,因为增采样是人为插值的点,所以自然其法矢的求取效果很OK,增采样如图所示:


其中算法采样点算法如下

a、定义点云顶点pi的计算公式为(b为三维点)


其中pi’为pi点的邻接顶点,n为对应的法矢;

b、遍历


其中ni为当前点的法矢,ni'表示当前点邻接顶点的法矢,NSi为当前点的邻接顶点集合,ρ为常数,ρ的取值对结果的影响如下图所示,我的算法实现默认取ρ=4。


看下正方体特征边增采样的结果图:

⑤泊松重建

预处理结束后,接着就是进行点云到三角网格曲面的重建了,重建过程我选用了泊松重建算法实现的,最后的重建效果如下图所示:

 

OK,至此完成点云重建,对于尖锐特征边的重建,paper有一些,效果看起来相当棒,但是千万不要被忽悠,因为大部分是坑爹的效果图。上面这种算法,通过特征边增采样的方法进行重建,效果鲁棒性还不错。

本文地址:http://blog.youkuaiyun.com/hjimce/article/details/46415909     作者:hjimce     联系qq:1393852684   更多资源请关注我的博客:http://blog.youkuaiyun.com/hjimce                原创文章,转载请保留本行信息。

<think>好的,我现在需要帮助用户解决如何使用Python实现基于曲率的三维点云离群点滤波的问题。首先,我得回忆一下曲率在点云处理中的作用。曲率高的区域通常对应着缘或噪声点,而平坦区域曲率较低。因此,基于曲率的滤波可以用来检测和去除离群点。 接下来,我应该考虑具体的步骤。首先,用户需要计算每个点的曲率。这通常涉及到法线估计,因为曲率计算依赖于法线。根据用户提供的引用,法线估计在点云处理中是常见的步骤,比如引用[1]提到了法线估计。Open3D库可能已经提供了相关的方法,但用户可能需要自己实现曲率计算的部分。 然后,计算曲率的方法。曲率可以通过协方差矩阵的特征值来计算。对于每个点,找到其邻域内的点,构建协方差矩阵,进行特征分解,最小的特征值除以三个特征值之和即为该点的曲率。这需要先确定每个点的邻域,可以使用K近邻或者半径搜索。 接下来是离群点的去除。根据曲率值,设定一个阈值,将曲率高于阈值的点视为离群点并过滤掉。或者使用统计方法,比如选择曲率分布的高百分位数作为阈值。 然后,我需要考虑如何将这些步骤转化为Python代码。用户可能需要使用Open3D或者PCL等库。不过,PCL的Python绑定可能不太友好,所以Open3D可能更适合。不过,Open3D是否有直接的曲率计算功能呢?我记得Open3D的compute_point_cloud_normals可以计算法线,但曲率可能需要自己计算。 所以,可能的步骤是: 1. 读取点云数据。 2. 计算法线(使用Open3D的voxel_down_sample预处理可能更好,如引用[1]中的例子)。 3. 对每个点,计算其邻域。 4. 计算协方差矩阵,特征值分解,得到曲率。 5. 根据曲率阈值或统计方法过滤离群点。 现在,我需要验证这些步骤是否正确。例如,曲率的计算是否正确,是否需要归一化等。另外,邻域的选择会影响结果,需要调整参数如K近邻的数量或半径大小。 用户可能需要代码示例,所以需要提供一个基本的实现框架。同时,需要注意性能问题,因为点云处理可能数据量大,效率很重要。可以考虑使用Open3D的KDTree来加速邻域搜索。 可能的问题点:如何高效计算每个点的邻域?Open3D的KDTree是否支持批量查询?是的,Open3D提供了KDTreeFlann类,可以用于K近邻或半径搜索。 然后,关于曲率计算的公式是否正确。根据资料,曲率通常由协方差矩阵的最小特征值除以特征值之和。例如,协方差矩阵的特征值为λ1 ≤ λ2 ≤ λ3,曲率为λ1 / (λ1 + λ2 + λ3)。这个公式是否正确?是的,这个公式能够反映点所在曲面的弯曲程度,曲率越大,越可能是缘或噪声点。 最后,根据曲率值进行滤波。比如,计算所有点的曲率,然后去除曲率最大的前5%的点,或者设定一个固定阈值。这部分需要用户根据具体数据调整参数。 现在,将这些步骤整合成代码示例。需要注意可能需要安装Open3D库,并且确保数据输入正确。代码中需要包含读取点云、计算法线(可能需要)、计算曲率、过滤离群点等步骤。 另外,用户提到的引用中,引用[2]和[3]都提到滤波是预处理的重要步骤,去除噪声和离群点。所以,基于曲率的滤波属于其中的一种方法,符合用户需求。 可能的代码结构: 1. 导入Open3D和其他必要的库。 2. 读取点云。 3. 预处理,如下采样(如引用[1]中的体素下采样)。 4. 计算法线(可能需要,但曲率计算是否需要法线?或者协方差矩阵是否需要法线?实际上,协方差矩阵是基于点的坐标,不需要法线。法线估计可能是一个单独的步骤,但曲率计算可能不需要法线。需要确认这一点。可能用户的问题中,是否需要先计算法线?或者直接通过坐标计算协方差矩阵即可。) 例如,计算某点的邻域点的协方差矩阵,然后分解得到特征值,从而计算曲率。这里不需要法线,法线可能用于其他应用。因此,代码中可以跳过法线计算,直接进行邻域搜索和协方差计算。 因此,步骤修正为: 1. 读取点云。 2. 预处理(可选)。 3. 建立KDTree进行邻域搜索。 4. 对每个点,获取邻域点。 5. 计算协方差矩阵。 6. 特征分解,计算曲率。 7. 根据曲率过滤离群点。 这样,代码不需要计算法线,但需要处理协方差矩阵。这可能更直接。 然后,代码示例需要包括这些步骤。例如,使用Open3D的KDTreeFlann来查询每个点的K近邻,然后计算协方差矩阵。 现在,编写代码的大致流程: import open3d as o3d import numpy as np # 读取点云 pcd = o3d.io.read_point_cloud("input.pcd") # 下采样预处理 downsampled = pcd.voxel_down_sample(voxel_size=0.01) # 转换为numpy数组 points = np.asarray(downsampled.points) # 构建KD树 kdtree = o3d.geometry.KDTreeFlann(downsampled) # 存储每个点的曲率 curvatures = [] # 设置K近邻的参数 K = 30 # 邻域点数 for i in range(len(points)): # 查询第i个点的K近邻 [k, idx, _] = kdtree.search_knn_vector_3d(downsampled.points[i], K) # 获取邻域点的坐标 neighborhood = points[idx, :] # 计算协方差矩阵 cov_matrix = np.cov(neighborhood.T) # 特征分解 eigenvalues, _ = np.linalg.eigh(cov_matrix) # 按升序排列 eigenvalues.sort() # 计算曲率 curvature = eigenvalues[0] / (eigenvalues.sum() + 1e-8) # 防止除以零 curvatures.append(curvature) curvatures = np.array(curvatures) # 设定阈值,例如曲率的前5%作为离群点 threshold = np.percentile(curvatures, 95) inliers = curvatures < threshold # 过滤后的点云 filtered_pcd = downsampled.select_by_index(np.where(inliers)[0]) # 可视化 o3d.visualization.draw_geometries([filtered_pcd]) 这个代码的大致结构是否正确?是的,但可能存在性能问题,因为循环每个点在大规模点云中会很慢。可以优化吗?比如使用并行计算或者向量化操作,但对于示例代码来说,可能暂时忽略性能问题,重点在正确性。 此外,用户可能需要调整参数K和阈值。比如,K的大小影响邻域的范围,K太小可能对噪声敏感,太大可能过度平滑。需要根据具体数据调整。 另外,曲率计算是否正确?是的,因为协方差矩阵的特征值反映了点在邻域内的分布情况。如果点在平面上,最大的特征值对应于平面的法线方向,而较小的两个特征值对应于平面内的变化。所以,最小的特征值可能接近于0,此时曲率较小。而如果点在缘或者角点,三个特征值可能都较大,或者最小的特征值相对于总和的比例较高,导致曲率较大。或者可能我的理解有误? 例如,协方差矩阵的特征值分解后,假设λ0 ≤ λ1 ≤ λ2,那么曲率定义为λ0/(λ0+λ1+λ2)。这个值越大,表示该点的邻域在某个方向上的变化越小,而其他方向变化大,可能对应缘或角点。或者可能相反?例如,在平面区域,λ0和λ1较小,λ2较大,所以λ0/(sum) 很小。而在缘区域,可能λ0和λ1中等,λ2较大,或者需要再确认。 例如,对于一个平面,协方差矩阵的两个较小的特征值接近于0,最大的特征值较大。此时,曲率λ0/(sum) 近似于0。而对于线状结构,可能最大的特征值很大,次之的较小,最小的更小。此时曲率可能较低。或者,我可能混淆了特征值的解释。正确的理解是,协方差矩阵的特征值反映了数据在各个主成分方向上的方差。在平坦区域,数据主要在平面内分布,所以最大的两个特征值较大,而最小的特征值较小。此时,曲率由最小的特征值除以总和,此时曲率较小。而在缘或角点处,可能三个方向都有较大的方差,导致最小的特征值相对较大,因此曲率较高?或者可能对于离群点,其周围的邻域点较少,协方差矩阵的特征值可能都较小,但总和也小,所以曲率可能较大? 这个可能需要进一步验证。假设某点是离群点,周围只有很少的点,协方差矩阵可能计算不准确,或者特征值可能较小,导致曲率计算异常。或者,当邻域点数K较小时,协方差矩阵可能无法准确反映局部几何形状,导致曲率估计不可靠。因此,选择合适的K值非常重要。 例如,当K=30时,每个点的邻域足够大,可以准确计算局部几何特征。如果K太小,比如K=5,协方差矩阵可能受噪声影响较大,导致曲率估计不稳定。 因此,在代码中,用户需要根据实际数据调整K值和阈值的选择。 此外,是否需要对曲率进行归一化或其他处理?比如,曲率的范围可能在0到1/3之间,因为最小的特征值不可能超过总和的三分之一。所以,阈值可能在0.05到0.1之间,或者更高,具体取决于数据。 另外,用户可能需要的是去除离群点,即曲率较高的点。但可能离群点的曲率反而较低,比如处于孤立点,周围没有其他点,此时协方差矩阵的特征值可能都接近于0,导致曲率计算为0/0,但由于代码中加了1e-8,所以分母不为零。这种情况下,曲率可能为0,但这样的点可能属于离群点。所以,单纯基于曲率的滤波可能无法有效去除所有类型的离群点,可能需要结合其他方法,如统计滤波(引用[1]中提到统计滤波),或者将曲率与其他特征结合。 因此,基于曲率的滤波可能更适合去除缘点或者高曲率区域,而统计滤波更适合去除离群点。用户的问题明确提到基于曲率的离群点滤波,所以可能需要明确这种方法的适用性。 综上,代码示例的大体结构是正确的,但需要在实际应用中调整参数,并且可能需要结合其他方法。此外,用户可能需要了解这种方法的效果和局限性。 最后,生成相关问题,可能涉及曲率计算的其他方法、参数调整、与其他滤波方法的比较等。</think>### 基于曲率的三维点云离群点滤波实现 基于曲率的离群点滤波通过分析点云局部几何特征(曲率)来识别噪声或异常点。曲率较高的区域通常对应缘或噪声,而平坦区域曲率较低。以下是使用Python和Open3D库实现的步骤及代码示例: --- #### **实现步骤** 1. **数据预处理** 使用体素下采样减少数据量并保留几何特征[^1]: $$ \text{downsampled} = \text{point\_cloud.voxel\_down\_sample(voxel\_size=0.01)} $$ 2. **曲率计算** 对每个点计算其邻域点的协方差矩阵,通过特征值分解得到曲率[^3]: $$ \text{曲率} = \frac{\lambda_{\text{min}}}{\lambda_0 + \lambda_1 + \lambda_2} $$ 其中 $\lambda_{\text{min}}$ 为协方差矩阵的最小特征值。 3. **离群点过滤** 根据曲率分布设定阈值(如保留曲率低于95%分位数的点)。 --- #### **代码示例** ```python import open3d as o3d import numpy as np # 读取点云 pcd = o3d.io.read_point_cloud("input.pcd") # 体素下采样预处理 downsampled = pcd.voxel_down_sample(voxel_size=0.01) points = np.asarray(downsampled.points) # 构建KD树加速邻域搜索 kdtree = o3d.geometry.KDTreeFlann(downsampled) # 计算每个点的曲率 K = 30 # 邻域点数 curvatures = [] for i in range(len(points)): [_, idx, _] = kdtree.search_knn_vector_3d(downsampled.points[i], K) neighborhood = points[idx] cov_matrix = np.cov(neighborhood.T) eigenvalues = np.linalg.eigh(cov_matrix)[0] eigenvalues.sort() # 升序排列 curvature = eigenvalues[0] / (eigenvalues.sum() + 1e-8) curvatures.append(curvature) # 基于曲率过滤离群点(保留曲率低于95%分位数的点) threshold = np.percentile(curvatures, 95) filtered_pcd = downsampled.select_by_index(np.where(curvatures < threshold)[0]) # 可视化结果 o3d.visualization.draw_geometries([filtered_pcd]) ``` --- #### **参数说明** - `K`:邻域点数,影响局部几何特征的稳定性,需根据点云密度调整。 - `voxel_size`:下采样体素大小,过大会丢失细节,过小则计算效率低。 - `threshold`:曲率阈值,可通过统计分布(如分位数)动态设定。 --- #### **优化建议** 1. **并行计算**:使用多线程或`numpy`向量化操作加速曲率计算。 2. **混合滤波**:结合统计滤波(如移除密度过低的点)提升效果[^2]。 3. **法线归一化**:在计算协方差矩阵前对邻域点坐标进行中心化处理。 ---
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值