PCL中分割方法的介紹(2)


(2)關於上一篇博文中提到的歐幾里德分割法稱之為標准的距離分離,當然接下來介紹其他的與之相關的延伸出來的聚類的方法,我稱之為條件歐幾里德聚類法,(是我的個人理解),這個條件的設置是可以由我們自定義的,因為除了距離檢查,聚類的點還需要滿足一個特殊的自定義的要求,就是以第一個點為標准作為種子點,候選其周邊的點作為它的對比或者比較的對象,如果滿足條件就加入到聚類的對象中,至於到底怎么翻譯我也蒙了,只能這樣理解了

主要的缺點:該算法沒有初始化種子系統,沒有過度分割或者分割不足的控制,還有就是從主循環運算中調用條件函數時,效率比較低,

看一下代碼吧,至於到底怎么理解各個有個人的理解吧

 

#include <pcl/io/pcd_io.h>
#include <pcl/segmentation/conditional_euclidean_clustering.h>

#include <iostream>


//如果此函數返回true,則將添加候選點到種子點的簇類中。
bool
customCondition(const pcl::PointXYZ& seedPoint, const pcl::PointXYZ& candidatePoint, float squaredDistance)
{
    // 在這里你可以添加你自定義的條件
    if (candidatePoint.y < seedPoint.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)
    {
        // ...add all its points to a new cloud...
        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;

        // ...and save it to disk.
        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++;
    }
}

 

 

上面執行的條件是檢查候選點的Y坐標是否小於種子的Y坐標,沒有什么實際意義。所以我就再查看結果了。

那么同時我暫時也用不到,如果有想法的時候再回來研究吧

(2)最小分割算法

該算法是將一幅點雲圖像分割為兩部分:前景點雲(目標物體)和背景物體(剩余部分)

關於該算法的論文的地址:http://gfx.cs.princeton.edu/pubs/Golovinskiy_2009_MBS/paper_small.pdf

The Min-Cut (minimum cut) algorithm最小割算法是圖論中的一個概念,其作用是以某種方式,將兩個點分開,當然這兩個點中間可能是通過無數的點再相連的。如圖

                           

如果要分開最左邊的點和最右邊的點,紅綠兩種割法都是可行的,但是紅線跨過了三條線,綠線只跨過了兩條。單從跨線數量上來論可以得出綠線這種切割方法更優 的結論。但假設線上有不同的權值,那么最優切割則和權值有關了。當你給出了點之間的 “圖” ,以及連線的權值時,最小割算法就能按照要求把圖分開。

所以那么怎么來理解點雲的圖呢?

顯而易見,切割有兩個非常重要的因素,第一個是獲得點與點之間的拓撲關系,這種拓撲關系就是生成一張 “圖”。第二個是給圖中的連線賦予合適的權值。只要這兩個要素合適,最小割算法就會正確的分割出想要的結果。點雲是分開的點。只要把點雲中所有的點連起來就可以了。連接算法如下:

  1. 找到每個點臨近的n個點
  2. 將這n個點和父點連接
  3. 找到距離最小的兩個塊(A塊中某點與B塊中某點距離最小),並連接
  4. 重復3,直至只剩一個塊

 

經過上面的步驟現在已經有了點雲的“圖”,只要給圖附上合適的權值,就滿足了最小分割的前提條件。物體分割比如圖像分割給人一個直觀印象就是屬於該物體的點,應該相互之間不會太遠。也就是說,可以用點與點之間的歐式距離來構造權值。所有線的權值可映射為線長的函數。

                                                    

我們知道這種分割是需要指定對象的,也就是我們指定聚類的中心點(center)以及聚類的半徑(radius),當然我們指定了中心點和聚類的半徑,那么就要被保護起來,保護的方法就是增加它的權值

                                                 

接下來我們就來看看代碼

 

#include <pcl/io/pcd_io.h>
#include <pcl/search/kdtree.h>
#include <pcl/features/normal_3d.h>
#include <pcl/segmentation/region_growing.h>
#include <pcl/segmentation/min_cut_segmentation.h>
#include <iostream>
#include <pcl/segmentation/region_growing_rgb.h>

int
main(int argc, char** argv)
{
    //申明點雲的類型
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    // 法線
    pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);

    if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1], *cloud) != 0)
    {
        return -1;
    }
       // 申明一個Min-cut的聚類對象
    pcl::MinCutSegmentation<pcl::PointXYZ> clustering;
    clustering.setInputCloud(cloud);   //設置輸入
        //創建一個點雲,列出所知道的所有屬於對象的點 
    // (前景點)在這里設置聚類對象的中心點(想想是不是可以可以使用鼠標直接選擇聚類中心點的方法呢?)
    pcl::PointCloud<pcl::PointXYZ>::Ptr foregroundPoints(new pcl::PointCloud<pcl::PointXYZ>());
    pcl::PointXYZ point;
    point.x = 100.0;
    point.y = 100.0;
    point.z = 100.0;
    foregroundPoints->points.push_back(point);
    clustering.setForegroundPoints(foregroundPoints);  //設置聚類對象的前景點
       
        //設置sigma,它影響計算平滑度的成本。它的設置取決於點雲之間的間隔(分辨率)
    clustering.setSigma(0.02);
    // 設置聚類對象的半徑.
    clustering.setRadius(0.01);

         //設置需要搜索的臨近點的個數,增加這個也就是要增加邊界處圖的個數
    clustering.setNumberOfNeighbours(20);

        //設置前景點的權重(也就是排除在聚類對象中的點,它是點雲之間線的權重,)
    clustering.setSourceWeight(0.6);

    std::vector <pcl::PointIndices> clusters;
    clustering.extract(clusters);

    std::cout << "Maximum flow is " << clustering.getMaxFlow() << "." << std::endl;

    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++;
    }
}

 看一下實際運行的最小分割法的結果

                                                                                              原始的點雲

                                                          最小分割法的結果

對於實際應用中我們應該設置正確的參數這是最為關鍵的!

 


免責聲明!

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



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