(3)上兩篇介紹了關於歐幾里德分割,條件分割,最小分割法等等還有以前就有用RANSAC法的分割方法,這一篇是關於區域生成的分割法,ios
區 域生長的基本 思想是: 將具備類似性的像素集合起來構成區域。首先對每一個須要分割的區域找出一個種子像素做爲生長的起點,而後將種子像素周圍鄰域中與種子有相同或類似性質的像素 (根據事先肯定的生長或類似準則來肯定)合併到種子像素所在的區域中。而新的像素繼續做爲種子向四周生長,直到再沒有知足條件的像素能夠包括進來,一個區 域就生長而成了。算法
區域生長算法直觀感受上和歐幾里德算法相差不大,都是從一個點出發,最終佔領整個被分割區域,歐幾里德算法是經過距離遠近,對於普通點雲的區域生長,其可由法線、曲率估計算法得到其法線和曲率值。經過法線和曲率來判斷某點是否屬於該類。ruby
算法的主要思想是:首先依據點的曲率值對點進行排序,之因此排序是由於,區域生長算法是從曲率最小的點開始生長的,這個點就是初始種子點,初始種子點所在的區域即爲最平滑的區域,從最平滑的區域開始生長可減小分割片斷的總數,提升效率,設置一空的種子點序列和空的聚類區域,選好初始種子後,將其加入到種子點序列中,並搜索鄰域點,對每個鄰域點,比較鄰域點的法線與當前種子點的法線之間的夾角,小於平滑閥值的將當前點加入到當前區域,而後檢測每個鄰域點的曲率值,小於曲率閥值的加入到種子點序列中,刪除當前的種子點,循環執行以上步驟,直到種子序列爲空,this
其算法能夠總結爲:spa
顯然,上述算法是針對小曲率變化面設計的。尤爲適合對連續階梯平面進行分割:好比SLAM算法所得到的建築走廊。設計
那麼就看一下代碼的效果3d
#include <iostream> #include <vector> #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include <pcl/search/search.h> #include <pcl/search/kdtree.h> #include <pcl/features/normal_3d.h> #include <pcl/visualization/cloud_viewer.h> #include <pcl/filters/passthrough.h> #include <pcl/segmentation/region_growing.h> int main (int argc, char** argv) { //點雲的類型 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); //打開點雲 if ( pcl::io::loadPCDFile <pcl::PointXYZ> ("region_growing_tutorial.pcd", *cloud) == -1) { std::cout << "Cloud reading failed." << std::endl; return (-1); } //設置搜索的方式或者說是結構 pcl::search::Search<pcl::PointXYZ>::Ptr tree = boost::shared_ptr<pcl::search::Search<pcl::PointXYZ> > (new pcl::search::KdTree<pcl::PointXYZ>); //求法線 pcl::PointCloud <pcl::Normal>::Ptr normals (new pcl::PointCloud <pcl::Normal>); pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator; normal_estimator.setSearchMethod (tree); normal_estimator.setInputCloud (cloud); normal_estimator.setKSearch (50); normal_estimator.compute (*normals); //直通濾波在Z軸的0到1米之間 pcl::IndicesPtr indices (new std::vector <int>); pcl::PassThrough<pcl::PointXYZ> pass; pass.setInputCloud (cloud); pass.setFilterFieldName ("z"); pass.setFilterLimits (0.0, 1.0); pass.filter (*indices); //聚類對象<點,法線> pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg; reg.setMinClusterSize (50); //最小的聚類的點數 reg.setMaxClusterSize (1000000); //最大的 reg.setSearchMethod (tree); //搜索方式 reg.setNumberOfNeighbours (30); //設置搜索的鄰域點的個數 reg.setInputCloud (cloud); //輸入點 //reg.setIndices (indices); reg.setInputNormals (normals); //輸入的法線 reg.setSmoothnessThreshold (3.0 / 180.0 * M_PI); //設置平滑度 reg.setCurvatureThreshold (1.0); //設置曲率的閥值 std::vector <pcl::PointIndices> clusters; reg.extract (clusters); std::cout << "Number of clusters is equal to " << clusters.size () << std::endl; std::cout << "First cluster has " << clusters[0].indices.size () << " points." << endl; std::cout << "These are the indices of the points of the initial" << std::endl << "cloud that belong to the first cluster:" << std::endl; int counter = 0; while (counter < clusters[0].indices.size ()) { std::cout << clusters[0].indices[counter] << ", "; counter++; if (counter % 10 == 0) std::cout << std::endl; } std::cout << std::endl; //可視化聚類的結果 pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud (); pcl::visualization::CloudViewer viewer ("Cluster viewer"); viewer.showCloud(colored_cloud); while (!viewer.wasStopped ()) { } return (0); }
看一下結果code
原始點雲orm
區域生成後的點雲對象
(4)基於顏色的區域生長分割法
除了普通點雲以外,還有一種特殊的點雲,成爲RGB點雲。顯而易見,這種點雲除告終構信息以外,還存在顏色信息。將物體經過顏色分類,是人類在辨認果實的 過程當中進化出的能力,顏色信息能夠很好的將複雜場景中的特殊物體分割出來。好比Xbox Kinect就能夠輕鬆的捕捉顏色點雲。基於顏色的區域生長分割原理上和基於曲率,法線的分割方法是一致的。只不過比較目標換成了顏色,去掉了點雲規模上 限的限制。能夠認爲,同一個顏色且捱得近,是一類的可能性很大,不須要上限來限制。因此這種方式比較適合用於室內場景分割。尤爲是複雜室內場景,顏色分割 能夠輕鬆的將連續的場景點雲變成不一樣的物體。哪怕是高低不平的地面,無法用採樣一致分割器抽掉,顏色分割算法一樣能完成分割任務。
算法分爲兩步:
(1)分割,當前種子點和領域點之間色差小於色差閥值的視爲一個聚類
(2)合併,聚類之間的色差小於色差閥值和併爲一個聚類,且當前聚類中點的數量小於聚類點數量的與最近的聚類合併在一塊兒
查看代碼
#include <iostream> #include <vector> #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> #include <pcl/search/search.h> #include <pcl/search/kdtree.h> #include <pcl/visualization/cloud_viewer.h> #include <pcl/filters/passthrough.h> #include <pcl/segmentation/region_growing_rgb.h> int main (int argc, char** argv) { pcl::search::Search <pcl::PointXYZRGB>::Ptr tree = boost::shared_ptr<pcl::search::Search<pcl::PointXYZRGB> > (new pcl::search::KdTree<pcl::PointXYZRGB>); pcl::PointCloud <pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud <pcl::PointXYZRGB>); if ( pcl::io::loadPCDFile <pcl::PointXYZRGB> ("region_growing_rgb_tutorial.pcd", *cloud) == -1 ) { std::cout << "Cloud reading failed." << std::endl; return (-1); } //存儲點雲的容器 pcl::IndicesPtr indices (new std::vector <int>); //濾波 pcl::PassThrough<pcl::PointXYZRGB> pass; pass.setInputCloud (cloud); pass.setFilterFieldName ("z"); pass.setFilterLimits (0.0, 1.0); pass.filter (*indices); //基於顏色的區域生成的對象 pcl::RegionGrowingRGB<pcl::PointXYZRGB> reg; reg.setInputCloud (cloud); reg.setIndices (indices); //點雲的索引 reg.setSearchMethod (tree); reg.setDistanceThreshold (10); //距離的閥值 reg.setPointColorThreshold (6); //點與點之間顏色容差 reg.setRegionColorThreshold (5); //區域之間容差 reg.setMinClusterSize (600); //設置聚類的大小 std::vector <pcl::PointIndices> clusters; reg.extract (clusters); pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud (); pcl::visualization::CloudViewer viewer ("Cluster viewer"); viewer.showCloud (colored_cloud); while (!viewer.wasStopped ()) { boost::this_thread::sleep (boost::posix_time::microseconds (100)); } return (0); }
恩 就這樣實際應用就是調參數,
-------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------
版權全部,轉載請註明出處