29 基于PCL的点云平面分割拟合算法技术路线(针对有噪声的点云数据)
0 引言
最近項目中用到了基于PCL開發(fā)的基于平面的點云和CAD模型的配準算法,點云平面提取采用的算法如下。
1 基于PCL的點云平面分割擬合算法
?2 參數(shù)及其意義介紹
(1)點云下采樣
1. 參數(shù):leafsize
2. 意義:Voxel Grid的leafsize參數(shù),物理意義是下采樣網(wǎng)格的大小,直接影響處理后點云密集程度,并對后期各種算法的處理速度產(chǎn)生直接影響。
3. 值越大,點云密度越低,處理速度越快;值越小,點云密度越高,處理速度越慢。通常保持這個值,使得其他的與點數(shù)有關(guān)的參數(shù)可以比較穩(wěn)定而不作大的改動。
4. 對應的代碼:
PointCloudPtr cloud(new pointCloud); ParameterReader pd(ParameterFilePath); double leafsize = stod(pd.getData("leafsize")); pcl::VoxelGrid<PointT> sor; sor.setInputCloud(CRTP::cloud_org); sor.setLeafSize(leafsize, leafsize, leafsize); sor.filter(*cloud);(2)點云法線估計
1. 參數(shù):Ksearch
2. 意義:估計法線時鄰域內(nèi)點的個數(shù)
3. 值越小,對點云的輪廓描述越精細;值越大,對點云的輪廓描述越粗糙。
4. 對應的代碼:
ParameterReader pd(ParameterFilePath); pcl::NormalEstimation<PointT, pcl::Normal> ne; pcl::PointCloud<pcl::Normal>::Ptr mynormals(new pcl::PointCloud<pcl::Normal>); pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>); tree->setInputCloud(cloud_filter); ne.setInputCloud(cloud_filter); ne.setSearchMethod(tree); ne.setKSearch(stoi(pd.getData("Ksearch"))); ne.compute(*mynormals);?(3)RegionGrowing生長聚類算法對可能是平面的點云進行分割
算法步驟:
1. 算法首先計算所有點的曲率值,并將曲率最小的點作為種子(seeds),開始進行生長?
2.?以法線夾角閾值(Angle threshold)作為判斷標準,對鄰域內(nèi)的點進行遍歷判斷?,符合條件則加入當前點集,不符合則reject,并加入reject點集
3. 以曲率閾值(Curvature threshold)作為判斷標準,將鄰域內(nèi)符合條件的點加入到種子隊列中?
4. 移除當前種子?
5. 如果當前種子隊列空了,表明當前子區(qū)域分割停止,遍歷其他種子區(qū)域,直到停止整個點云均被遍歷完為止生長
參數(shù)分析:?
1. 參數(shù):MinClusterSize(最小聚類點云數(shù)目),MaxClusterSize(最大聚類點云數(shù)據(jù))
NumberOfNeighbours(尋找種子seed點最近的點判斷是否為同類),SmoothnessThreshold(聚類的法線夾角閾值)
? ? ? ?CurvatureThreshold(聚類的曲率閾值,可以直觀地將圓柱面等區(qū)別開)
2. 對應的代碼
ParameterReader pd(ParameterFilePath); pcl::RegionGrowing<PointT, pcl::Normal> reg; pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>); reg.setMinClusterSize(stoi(pd.getData("MinClusterSize"))); reg.setMaxClusterSize(stoi(pd.getData("MaxClusterSize"))); reg.setSearchMethod(tree); reg.setNumberOfNeighbours(stoi(pd.getData("NumberOfNeighbours"))); reg.setInputCloud(CloudFilter); reg.setInputNormals(Normals); reg.setSmoothnessThreshold(stod(pd.getData("SmoothnessThreshold")) / 180.0 * M_PI); reg.setCurvatureThreshold(stod(pd.getData("CurvatureThreshold"))); std::vector <pcl::PointIndices> clusters; reg.extract(clusters); /* wk 添加: 可視化調(diào)試 */ pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_segmented(new pcl::PointCloud<pcl::PointXYZRGB>()); cloud_segmented = reg.getColoredCloud(); pcl::visualization::CloudViewer viewer("Cluster viewer"); viewer.showCloud(cloud_segmented); while (!viewer.wasStopped()) { } /* wk 添加: 可視化調(diào)試 */(4)SACSegmentation 利用RANSAC算法對平面點云進行分割并擬合
1. 參數(shù):MaxIterations(最大迭代次數(shù)),threshold(距離閾值,判斷點是否為當前擬合平面的內(nèi)點,理論上該值越大平面越粗糙)
2. 代碼
/*RanSAC擬合平面,并將平面內(nèi)點分割出來*/pcl::SACSegmentation<PointT> seg; pcl::PointIndices::Ptr inliers(new pcl::PointIndices); pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients); seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_PLANE); seg.setMethodType(pcl::SAC_RANSAC); seg.setMaxIterations(stoi(pd.getData("Maxci"))); seg.setDistanceThreshold(stod(pd.getData("threshold"))); seg.setInputCloud(cloud); seg.segment(*inliers, *coefficients);// 分割內(nèi)點,另存 pcl::ExtractIndices<PointT> extract; PointCloudPtr cloud_plane(new pointCloud); extract.setInputCloud(cloud); extract.setIndices(inliers); extract.setNegative(false); extract.filter(*cloud_plane);??3 部分效果圖展示
(1)原圖
?
(2)RegionGrowing分割效果圖
?4 算法的局限性
區(qū)域生長算法分割平面步驟及問題分析:針對分辨率低、掃描質(zhì)量比較差的點云,如圖所示,算法無法將破碎、扭曲的大塊區(qū)域識別為平面區(qū)域,只能將這部分點判斷為非平面點集舍棄掉。
區(qū)域生長算法通常在分割細節(jié)處比較平滑的平面點云時,具有相當?shù)膬?yōu)勢。但是在處理“波紋”狀點云時,就沒什么優(yōu)勢了。而實際掃描點云的細節(jié)部位很多時候是如上圖所示的,為了將曲率較小的曲面區(qū)別開,而調(diào)低平滑及曲率閾值時,這類從大視角上看明顯是平面的點云會被rejected,從而導致分割失效。如下圖所示,RegionGrowing更適合處理接近理想點云的這類點云,而不適合處理波動起伏狀的、掃描精度較差的點云。
?
轉(zhuǎn)載于:https://www.cnblogs.com/ghjnwk/p/10178975.html
總結(jié)
以上是生活随笔為你收集整理的29 基于PCL的点云平面分割拟合算法技术路线(针对有噪声的点云数据)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设置tomcat使用指定的jdk版本
- 下一篇: 字符串的操作方法(第二天)