29 基於PCL的點雲平面分割擬合算法技術路線(針對有噪聲的點雲數據)


0 引言

最近項目中用到了基於PCL開發的基於平面的點雲和CAD模型的配准算法,點雲平面提取采用的算法如下。

1 基於PCL的點雲平面分割擬合算法

 2 參數及其意義介紹

(1)點雲下采樣

  1. 參數:leafsize

  2. 意義:Voxel Grid的leafsize參數,物理意義是下采樣網格的大小,直接影響處理后點雲密集程度,並對后期各種算法的處理速度產生直接影響。

  3. 值越大,點雲密度越低,處理速度越快;值越小,點雲密度越高,處理速度越慢。通常保持這個值,使得其他的與點數有關的參數可以比較穩定而不作大的改動。

  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. 參數:Ksearch

  2. 意義:估計法線時鄰域內點的個數

  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)作為判斷標准,對鄰域內的點進行遍歷判斷 ,符合條件則加入當前點集,不符合則reject,並加入reject點集

  3. 以曲率閾值(Curvature threshold)作為判斷標准,將鄰域內符合條件的點加入到種子隊列中 

  4. 移除當前種子 

  5. 如果當前種子隊列空了,表明當前子區域分割停止,遍歷其他種子區域,直到停止整個點雲均被遍歷完為止生長

 參數分析: 

  1. 參數:MinClusterSize(最小聚類點雲數目),MaxClusterSize(最大聚類點雲數據)

  NumberOfNeighbours(尋找種子seed點最近的點判斷是否為同類),SmoothnessThreshold(聚類的法線夾角閾值)

       CurvatureThreshold(聚類的曲率閾值,可以直觀地將圓柱面等區別開)

  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 添加: 可視化調試 */
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 添加: 可視化調試 */

(4)SACSegmentation 利用RANSAC算法對平面點雲進行分割並擬合

  1. 參數:MaxIterations(最大迭代次數),threshold(距離閾值,判斷點是否為當前擬合平面的內點,理論上該值越大平面越粗糙)

  2. 代碼

/*RanSAC擬合平面,並將平面內點分割出來*/

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);

// 分割內點,另存
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 算法的局限性

  區域生長算法分割平面步驟及問題分析:針對分辨率低、掃描質量比較差的點雲,如圖所示,算法無法將破碎、扭曲的大塊區域識別為平面區域,只能將這部分點判斷為非平面點集舍棄掉。

        

  區域生長算法通常在分割細節處比較平滑的平面點雲時,具有相當的優勢。但是在處理“波紋”狀點雲時,就沒什么優勢了。而實際掃描點雲的細節部位很多時候是如上圖所示的,為了將曲率較小的曲面區別開,而調低平滑及曲率閾值時,這類從大視角上看明顯是平面的點雲會被rejected,從而導致分割失效。如下圖所示,RegionGrowing更適合處理接近理想點雲的這類點雲,而不適合處理波動起伏狀的、掃描精度較差的點雲。

         

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM