(1)Euclidean分割
歐幾里德分割法是最簡單的。檢查兩點之間的距離。如果小於閾值,則兩者被認為屬於同一簇。它的工作原理就像一個洪水填充算法:在點雲中的一個點被“標記”則表示為選擇在一個的集群中。然后,它像病毒一樣擴散到其他足夠近的點,從這些點到更多點,直到沒有新的添加為止。這樣,就是一個初始化的新的群集,並且該過程將以剩余的無標記點再次進行。
在PCL中,Euclidean分割法如下:
#include <pcl/io/pcd_io.h> #include <pcl/segmentation/extract_clusters.h> #include <iostream> int main(int argc, char** argv) { // 申明存儲點雲的對象. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // 讀取一個PCD文件 if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1], *cloud) != 0) { return -1; } // 建立kd-tree對象用來搜索 . pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>); kdtree->setInputCloud(cloud); // Euclidean 聚類對象. pcl::EuclideanClusterExtraction<pcl::PointXYZ> clustering; // 設置聚類的最小值 2cm (small values may cause objects to be divided // in several clusters, whereas big values may join objects in a same cluster). clustering.setClusterTolerance(0.02); // 設置聚類的小點數和最大點雲數 clustering.setMinClusterSize(100); clustering.setMaxClusterSize(25000); clustering.setSearchMethod(kdtree); clustering.setInputCloud(cloud); std::vector<pcl::PointIndices> clusters; clustering.extract(clusters); // For every cluster... int currentClusterNum = 1; for (std::vector<pcl::PointIndices>::const_iterator i = clusters.begin(); i != clusters.end(); ++i) { //添加所有的點雲到一個新的點雲中 pcl::PointCloud<pcl::PointXYZ>::Ptr cluster(new pcl::PointCloud<pcl::PointXYZ>); for (std::vector<int>::const_iterator point = i->indices.begin(); point != i->indices.end(); point++) cluster->points.push_back(cloud->points[*point]); cluster->width = cluster->points.size(); cluster->height = 1; cluster->is_dense = true; // 保存 if (cluster->points.size() <= 0) break; std::cout << "Cluster " << currentClusterNum << " has " << cluster->points.size() << " points." << std::endl; std::string fileName = "cluster" + boost::to_string(currentClusterNum) + ".pcd"; pcl::io::savePCDFileASCII(fileName, *cluster); currentClusterNum++; } }
那么 比如我要分割一張點雲文件可視化如下
那么可以看到結果
很明顯每一個英文字幕都會被提取出來,比如我們顯示其中的一個聚類
當然我們把點雲中的所有聚類生成了一個個的單獨文件,那么有人在我的微信公眾號后台提問,如何把所有的聚類的結果,在一個可視化窗口中顯示呢?所以該如何解決,個人理解就是雖然聚類的結果分解出來了,但是,每一個聚類對象相對與原來點雲的坐標以及性質都沒有改變所以我們直接就把聚類的結果相加就可以實現了,那么我們只需要在結尾的地方添加如下幾行代碼
*add_cloud+=*cloud_cluster; pcl::io::savePCDFileASCII("add_cloud.pcd",*add_cloud);
當然前面要聲明add_cloud的數據格式,所以我們就看一下顯示的試驗結果。我們用table_scene_lms400.pcd文件來查看結果
原始PCD文件可視化的結果
那么我們只想看除去兩個平面的其他聚類,所以我們只需要添加兩行代碼即可,可視化的結果如下
(2)Conditional Euclidean分割
條件歐幾里德分割的工作方式與(1)所示的標准的歐幾里德分割方法基本一樣,條件分割除了要距離檢查,點還需要滿足一個特殊的,可以自定義的要求的限制,這樣它們被添加到一個集群。此條件是用戶指定的。它歸結為如下:對於每一對點(第一個點,作為種子點,第二個點,作為候選點,是一個臨近點的選擇與計算比較等操作)將會有自定義函數。此函數具有一定的特性:這兩個點具有副本,以便我們可以執行我們自己的選擇計算的平方距離
函數並返回布爾值。如果值為true,則可以將候選添加到群集。如果假,它不會被添加,即使它通過距離檢查。
#include <pcl/io/pcd_io.h> #include <pcl/segmentation/conditional_euclidean_clustering.h> #include <iostream> // 如果這個函數返回的是真,這這個候選點將會被加入聚類中 bool customCondition(const pcl::PointXYZ& seedPoint, const pcl::PointXYZ& candidatePoint, float squaredDistance) { // Do whatever you want here.做你想做的條件的篩選 if (candidatePoint.y < seedPoint.y) //如果候選點的Y的值小於種子點的Y值(就是之前被選擇為聚類的點),則不滿足條件,返回假 return false; return true; } int main(int argc, char** argv) { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1], *cloud) != 0) { return -1; } pcl::ConditionalEuclideanClustering<pcl::PointXYZ> clustering; clustering.setClusterTolerance(0.02); clustering.setMinClusterSize(100); clustering.setMaxClusterSize(25000); clustering.setInputCloud(cloud); //設置每次檢測一對點雲時的函數 clustering.setConditionFunction(&customCondition); std::vector<pcl::PointIndices> clusters; clustering.segment(clusters); int currentClusterNum = 1; for (std::vector<pcl::PointIndices>::const_iterator i = clusters.begin(); i != clusters.end(); ++i) { pcl::PointCloud<pcl::PointXYZ>::Ptr cluster(new pcl::PointCloud<pcl::PointXYZ>); for (std::vector<int>::const_iterator point = i->indices.begin(); point != i->indices.end(); point++) cluster->points.push_back(cloud->points[*point]); cluster->width = cluster->points.size(); cluster->height = 1; cluster->is_dense = true; if (cluster->points.size() <= 0) break; std::cout << "Cluster " << currentClusterNum << " has " << cluster->points.size() << " points." << std::endl; std::string fileName = "cluster" + boost::to_string(currentClusterNum) + ".pcd"; pcl::io::savePCDFileASCII(fileName, *cluster); currentClusterNum++; } }
關於條件聚類在這里就不再贅述,等用到了在回來研究研究吧,
謝謝暫時就到這里了********************