PCL 點云濾波及分割匯總

點云濾波匯總

立方體濾波

首先是最簡單的容易理解的立方體的剪裁濾波,根據(jù)對角點確定一個立方體然后獲取立方體內(nèi)或外的點,并且還可以在這立方體基礎(chǔ)上加平移或旋轉(zhuǎn),因為根據(jù)兩個點確立的立方體只是坐標(biāo)軸正方向的,不一定能滿足所有需求。

#include <pcl/filters/crop_box.h>
    /// <summary>
    /// 立方體濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="min">最小點位 x y z 1</param>
    /// <param name="max">最大點位 x y z 1</param>
    /// <param name="negative">默認(rèn)值為 false,輸出點云為在設(shè)定字段的設(shè)定范圍內(nèi)的點集,如果設(shè)置為 true 則剛好相反</param>
    void cropFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_out, Eigen::Vector4f &min, Eigen::Vector4f &max, bool negative) {
        pcl::CropBox<pcl::PointXYZ> box_filter;                     //濾波器對象
        box_filter.setMin(min); //Min和Max是指立方體的兩個對角點。每個點由一個四維向量表示,通常最后一個是1.
        box_filter.setMax(max);
        //box_filter.setRotation(rotation); //旋轉(zhuǎn) rx ry rz
        //box_filter.setTranslation(tanslation);//仿射矩陣 Affine3f 旋轉(zhuǎn)加平移
        //box_filter.setTransform(transformax);//平移 tx ty tz
        box_filter.setNegative(negative);
        box_filter.setInputCloud(cloud_in);
        box_filter.filter(*cloud_out);
    }

凸(凹)包濾波

這個濾波實際用下來效果就是把凸出來或凹進(jìn)去的一塊區(qū)域的點云濾出來,入?yún)⑵鋵嵼敳惠斎攵夹芯褪蔷S度,默認(rèn)不輸入就是按點云情況來,pcl::ConvexHull是用來算凸包的, pcl:: ConcaveHull用來算凹包,最后都扔到pcl::CropHull里面。

#include <pcl/surface/concave_hull.h>
#include <pcl/filters/crop_hull.h>

    /// <summary>
    /// 凸包濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="boundingbox">封閉區(qū)域頂點</param>
    /// <param name="dimension">設(shè)置凸包維度</param>
    /// <param name="negative">默認(rèn)值為 false,輸出點云為在設(shè)定字段的設(shè)定范圍內(nèi)的點集,如果設(shè)置為 true 則剛好相反</param>
    /// <param name="keepOrganized"> false=刪除點(默認(rèn)),true=重新定義點,保留結(jié)構(gòu)</param>
    void cropHullFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, pcl::PointCloud<pcl::PointXYZ>::Ptr& boundingbox, int dimension, bool negative, bool keepOrganized) {
        pcl::PointCloud<pcl::PointXYZ>::Ptr surface_hull(new pcl::PointCloud<pcl::PointXYZ>);   //描述凸包形狀的點云
        std::vector<pcl::Vertices> polygons;// polygons保存的是所有凸包多邊形的頂點在surface_hull中的下標(biāo)

        pcl::ConvexHull<pcl::PointXYZ> hull;
        hull.setInputCloud(boundingbox);//設(shè)置輸入點云:封閉區(qū)域頂點點云
        hull.setDimension(dimension);//設(shè)置凸包維度

        //surface_hull存儲最終產(chǎn)生的凹多邊形上的頂點,polygons存儲一系列頂點集,每個頂點集構(gòu)成的一個多邊形,Vertices數(shù)據(jù)結(jié)構(gòu)包含一組點的索引,索引是point中的點對應(yīng)的索引。
        hull.reconstruct(*surface_hull, polygons);

        pcl::CropHull<pcl::PointXYZ> CH;//創(chuàng)建CropHull濾波對象
        CH.setDim(dimension);   //設(shè)置維度,與凸包維度一致
        CH.setInputCloud(cloud_in);     //設(shè)置需要濾波的點云
        CH.setHullIndices(polygons);    //輸入封閉區(qū)域的頂點
        CH.setHullCloud(surface_hull);  //輸入封閉區(qū)域的形狀
        CH.setNegative(negative);
        CH.setKeepOrganized(keepOrganized);
        CH.filter(*cloud_out);
    }

體素采樣濾波

體素濾波可以按照給定長寬高的立方體來填充點云,每個立方體的質(zhì)心點留下來以此讓減少點云中點的數(shù)目,有效的提升后續(xù)點云處理速度,一般用來下采樣。

#include <pcl/filters/voxel_grid.h>

    /// <summary>
    /// 體素采樣濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="lx">立方體X軸長度</param>
    /// <param name="ly">立方體Y軸長度</param>
    /// <param name="lz">立方體Z軸長度</param>
    void voxelFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_out, float lx, float ly, float lz) {
        std::cout << "size before voxelFilter: " << cloud_in->size() << std::endl;
        pcl::VoxelGrid<pcl::PointXYZ> vox_grid;
        vox_grid.setLeafSize(lx, ly, lz);//設(shè)置濾波時創(chuàng)建的體素大小為lx m*ly m*lz m的立方體
        vox_grid.setInputCloud(cloud_in);
        vox_grid.filter(*cloud_out);
        std::cout << "size after voxelFilter: " << cloud_out->size() << std::endl;
    }

近似體素重心采樣濾波

ApproximateVoxelGrid近似體素濾波企圖以 更快的速度 實現(xiàn)與VoxelGrid 體素濾波相同的下采樣,它通過 散列函數(shù)(Hashing Function)快速逼近質(zhì)心,而不是精細(xì)確定質(zhì)心并對點云進(jìn)行下采樣。采樣結(jié)果是近似逼近的體素質(zhì)心,并不是體素中心。

#include <pcl/filters/approximate_voxel_grid.h>

    /// <summary>
    /// 近似體素重心采樣濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="lx">立方體X軸長度</param>
    /// <param name="ly">立方體Y軸長度</param>
    /// <param name="lz">立方體Z軸長度</param>
    /// <param name="downsampleAllData">如果只有XYZ字段,則設(shè)置為false,如果對所有字段,如intensity,都進(jìn)行下采樣,則設(shè)置為true</param>
    void approximateVoxelGridFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, float lx, float ly, float lz, bool downsampleAllData) {
        std::cout << "size before voxelFilter: " << cloud_in->size() << std::endl;
        pcl::ApproximateVoxelGrid<pcl::PointXYZ> vox_grid;
        vox_grid.setLeafSize(lx, ly, lz);//設(shè)置濾波時創(chuàng)建的體素大小為lx m*ly m*lz m的立方體
        vox_grid.setInputCloud(cloud_in);
        vox_grid.setDownsampleAllData(downsampleAllData);
        vox_grid.filter(*cloud_out);
        std::cout << "size after voxelFilter: " << cloud_out->size() << std::endl;
    }

均勻采樣濾波

均勻采樣濾波原理和體素濾波是很相似的,但是體素采用單位立方體,而均勻采樣取給定半徑的球體內(nèi)的點保留質(zhì)心。

#include <pcl/filters/uniform_sampling.h>

    /// <summary>
    /// 均勻采樣濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="radius_seach">半徑范圍內(nèi)搜尋鄰居點</param>
    void uniformSamplingFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, double radius_seach) {
        pcl::UniformSampling<pcl::PointXYZ> filter;
        filter.setRadiusSearch(radius_seach);
        filter.setInputCloud(cloud_in);
        filter.filter(*cloud_out);
    }

隨機采樣濾波

隨機選擇n個點,每個點被選到的概率相同,可以得到固定的點數(shù)量;
缺點:如果原點云是不均勻的,比如有的地方密度大,有的地方密度小,那么RandomSample采樣后的點云同樣是不均勻的,分布同云點云。雖然每個點被選到的概率一樣,但密度大的區(qū)域內(nèi)點比較多,這個區(qū)域內(nèi)被采樣的機會就更多,因此原來密度大的地方,采樣后,密度還是大。

#include <pcl/filters/random_sample.h>

    /// <summary>
    /// 隨機采樣濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="sample">設(shè)置下采樣點云的點數(shù)</param>
    /// <param name="seed">隨機函數(shù)種子點</param>
    /// <param name="negative">默認(rèn)值為 false,輸出點云為在設(shè)定字段的設(shè)定范圍內(nèi)的點集,如果設(shè)置為 true 則剛好相反</param>
    /// <param name="keepOrganized"> false=刪除點(默認(rèn)),true=重新定義點,保留結(jié)構(gòu)</param>
    void randomSamplingFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, unsigned int sample, unsigned int seed, bool negative, bool keepOrganized) {
        pcl::RandomSample<pcl::PointXYZ> filter;
        filter.setSample(sample);
        filter.setSeed(seed);
        filter.setNegative(negative);
        filter.setKeepOrganized(keepOrganized);
        filter.setInputCloud(cloud_in);
        filter.filter(*cloud_out);
    }

移動最小二乘增采樣濾波

增采樣是一種表面重建方法,當(dāng)你有比你想象的要少的點云數(shù)據(jù)時,增采樣可以幫你恢復(fù)原有的表面(S),通過內(nèi)插你目前擁有的點云數(shù)據(jù),這是一個復(fù)雜的猜想假設(shè)的過程。所以構(gòu)建的結(jié)果不會百分之一百準(zhǔn)確,但有時它是一種可選擇的方案。所以,在你的點云云進(jìn)行下采樣時,一定要保存一份原始數(shù)據(jù)!

#include <pcl/surface/mls.h>

    /// <summary>
    /// 移動最小二乘增采樣濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="tree">提取搜索方法的樹對象,一般用近鄰的kdTree即可</param>
    /// <param name="upsamplingMethod">Upsampling 采樣的方法有 DISTINCT_CLOUD, RANDOM_UNIFORM_DENSITY</param>
    /// <param name="searchRadius">設(shè)置搜索鄰域的半徑</param>
    /// <param name="upsamplingRadius">采樣的半徑</param>
    /// <param name="upsamplingStepSize">采樣步數(shù)的大小</param>
    void movingLeastSquaresFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, pcl::search::Search<pcl::PointXYZ>::Ptr tree, pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointXYZ>::UpsamplingMethod upsamplingMethod, double searchRadius, double upsamplingRadius, double upsamplingStepSize) {
        pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointXYZ> filter;
        filter.setInputCloud(cloud_in);
        filter.setSearchMethod(tree);
        //設(shè)置搜索鄰域的半徑
        filter.setSearchRadius(searchRadius);
        // Upsampling 采樣的方法有 DISTINCT_CLOUD, RANDOM_UNIFORM_DENSITY
        filter.setUpsamplingMethod(upsamplingMethod);
        // 采樣的半徑
        filter.setUpsamplingRadius(upsamplingRadius);
        // 采樣步數(shù)的大小
        filter.setUpsamplingStepSize(upsamplingStepSize);
        filter.process(*cloud_out);
    }

深度傳感器的測量是不準(zhǔn)確的,和由此產(chǎn)生的點云也是存在的測量誤差,比如離群點,孔等表面,可以用一個算法重建表面,遍歷所有的點云和插值數(shù)據(jù),試圖重建原來的表面。

統(tǒng)計濾波

統(tǒng)計濾波器用于去除明顯離群點(離群點往往由測量噪聲引入)。
其特征是在空間中分布稀疏,可以理解為:每個點都表達(dá)一定信息量,某個區(qū)域點越密集則可能信息量越大。噪聲信息屬于無用信息,信息量較小。所以離群點表達(dá)的信息可以忽略不計。考慮到離群點的特征,則可以定義某處點云小于某個密度,既點云無效。計算每個點到其最近的k(設(shè)定)個點平均距離。則點云中所有點的距離應(yīng)構(gòu)成高斯分布。給定均值與方差,可剔除n個西格瑪之外的點

激光掃描通常會產(chǎn)生密度不均勻的點云數(shù)據(jù)集,另外測量中的誤差也會產(chǎn)生稀疏的離群點,此時,估計局部點云特征(例如采樣點處法向量或曲率變化率)時運算復(fù)雜,這會導(dǎo)致錯誤的數(shù)值,反過來就會導(dǎo)致點云配準(zhǔn)等后期的處理失敗。
解決辦法:對每個點的鄰域進(jìn)行一個統(tǒng)計分析,并修剪掉一些不符合標(biāo)準(zhǔn)的點。
具體方法為在輸入數(shù)據(jù)中對點到臨近點的距離分布的計算,對每一個點,
計算它到所有臨近點的平均距離(假設(shè)得到的結(jié)果是一個高斯分布,
其形狀是由均值和標(biāo)準(zhǔn)差決定),那么平均距離在標(biāo)準(zhǔn)范圍之外的點,
可以被定義為離群點并從數(shù)據(jù)中去除。

#include <pcl/filters/statistical_outlier_removal.h>

    /// <summary>
    /// 統(tǒng)計濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="meanK">K近鄰搜索點個數(shù)</param>
    /// <param name="std_dev_mul">標(biāo)準(zhǔn)差倍數(shù)</param>
    /// <param name="negative">默認(rèn)值為 false,輸出點云為在設(shè)定字段的設(shè)定范圍內(nèi)的點集,如果設(shè)置為 true 則剛好相反</param>
    /// <param name="keepOrganized"> false=刪除點(默認(rèn)),true=重新定義點,保留結(jié)構(gòu)</param>
    void sorFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_out, int meanK, float std_dev_mul,bool negative, bool keepOrganized) {
        std::cout << "size before statisticalOutlierRemoval: " << cloud_in->size() << std::endl;
        pcl::StatisticalOutlierRemoval<pcl::PointXYZ> filter(true);
        filter.setInputCloud(cloud_in);
        filter.setMeanK(meanK);
        filter.setStddevMulThresh(std_dev_mul);
        filter.setNegative(negative);
        filter.setKeepOrganized(keepOrganized);
        filter.filter(*cloud_out);
        std::cout << "size after statisticalOutlierRemoval: " << cloud_out->size() << std::endl;
    }

半徑濾波

球半徑濾波器與統(tǒng)計濾波器相比更加簡單粗暴。
以某點為中心 畫一個球計算落在該球內(nèi)的點的數(shù)量,當(dāng)數(shù)量大于給定值時,
則保留該點,數(shù)量小于給定值則剔除該點。
此算法運行速度快,依序迭代留下的點一定是最密集的,
但是球的半徑和球內(nèi)點的數(shù)目都需要人工指定。

#include <pcl/filters/radius_outlier_removal.h>

    /// <summary>
    /// 半徑濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="radiusSearch">半徑范圍內(nèi)搜尋鄰居點</param>
    /// <param name="minNeighborsInRadius">鄰居少于點數(shù)認(rèn)為是離群點</param>
    /// <param name="negative">默認(rèn)值為 false,輸出點云為在設(shè)定字段的設(shè)定范圍內(nèi)的點集,如果設(shè)置為 true 則剛好相反</param>
    /// <param name="keepOrganized"> false=刪除點(默認(rèn)),true=重新定義點,保留結(jié)構(gòu)</param>
    void rorFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_out, int radiusSearch, float minNeighborsInRadius, bool negative, bool keepOrganized) {
        std::cout << "size before radiusOutlierRemoval: " << cloud_in->size() << std::endl;

        pcl::RadiusOutlierRemoval<pcl::PointXYZ> ror;
        ror.setInputCloud(cloud_in);
        ror.setRadiusSearch(radiusSearch);
        ror.setMinNeighborsInRadius(minNeighborsInRadius);
        ror.setNegative(negative);
        ror.setKeepOrganized(keepOrganized);
        ror.filter(*cloud_out);

        std::cout << "size after radiusOutlierRemoval: " << cloud_out->size() << std::endl;

    }

直通濾波

直通濾波是直接根據(jù)某一個軸的最大最小值,直接過濾出在這范圍里的點云

#include <pcl/filters/passthrough.h>

    /// <summary>
    /// 直通濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="field_name">坐標(biāo)軸名稱:x ,y ,z</param>
    /// <param name="limit_min">最大值</param>
    /// <param name="limit_max">最小值</param>
    /// <param name="negative">默認(rèn)值為 false,輸出點云為在設(shè)定字段的設(shè)定范圍內(nèi)的點集,如果設(shè)置為 true 則剛好相反</param>
    void passThroughFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_out, const std::string &field_name, const float &limit_min, const float &limit_max, bool negative) {
        pcl::PassThrough<pcl::PointXYZ> pass;
        pass.setInputCloud(cloud_in);            //設(shè)置輸入點云
        pass.setFilterFieldName(field_name);         //設(shè)置過濾時所需要點云類型的字符串字段 "x" "y" "z"
        pass.setFilterLimits(limit_min, limit_max);        //設(shè)置在過濾字段的范圍
        pass.setFilterLimitsNegative (negative);   //設(shè)置保留范圍內(nèi)還是過濾掉范圍內(nèi)
        pass.filter(*cloud_out);            //執(zhí)行濾波,保存過濾結(jié)果在cloud_out

    }

條件濾波

條件濾波相比直通濾波更加靈活的設(shè)置各種值范圍過濾點云,用pcl::ConditionAnd創(chuàng)建與條件,用pcl::ConditionOr創(chuàng)建或條件,最后扔到pcl::ConditionalRemoval里。

#include <pcl/filters/conditional_removal.h>

    /// <summary>
    /// 條件濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="range_cond">條件范圍</param>
    /// <param name="keepOrganized">false=刪除點(默認(rèn)),true=重新定義點,保留結(jié)構(gòu)</param>
    void conditionalRemovalFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, ConditionBaseT::Ptr condition, bool keepOrganized) {
        //pcl::ConditionAnd<pcl::PointXYZ>::Ptr condition(new pcl::ConditionAnd<pcl::PointXYZ>());//創(chuàng)建與條件
        //pcl::ConditionOr表示或條件
        //condition->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
        //  pcl::FieldComparison<pcl::PointXYZ>("z", pcl::ComparisonOps::GT, 0.0)));
        //condition->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
        //  pcl::FieldComparison<pcl::PointXYZ>("z", pcl::ComparisonOps::LT, 0.8)));
        //GT表示大于等于,LT表示小于等于,EQ表示等于,GE表示大于,LE表示小于
        pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
        condrem.setCondition(condition);
        condrem.setInputCloud(cloud_in);
        condrem.setKeepOrganized(keepOrganized);
        condrem.filter(*cloud_out);
    }

投影濾波

投影濾波比較高級用的比較多的是向一個平面投影,很多時候把3維的數(shù)據(jù)降維到2維很多復(fù)雜的處理都能因此變得簡單,標(biāo)準(zhǔn)的降維打擊,設(shè)置ModelType類型為pcl::SACMODEL_PLANE,按照平面方程公式ax+by+cz+d=0,把a,b,c,d值依次放入pcl::ModelCoefficients類型對象中即可。

#include <pcl/filters/project_inliers.h>
#include <pcl/ModelCoefficients.h>

    /// <summary>
    /// 投影濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="coefficients">設(shè)置模型對應(yīng)的系數(shù),類似數(shù)組提供coefficients->values.resize(n)定義大小,coefficients->values[0]=賦值,平面的話值對應(yīng)ax+by+cz+d=0</param>
    /// <param name="modelType">設(shè)置對應(yīng)的投影模型,平面用pcl::SACMODEL_PLANE</param>
    void projectInliersFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_out, pcl::ModelCoefficients::Ptr &coefficients, int modelType) {

        pcl::ProjectInliers<pcl::PointXYZ> proj;        //創(chuàng)建投影濾波對象
        proj.setModelType(modelType);           //設(shè)置對象對應(yīng)的投影模型
        proj.setInputCloud(cloud_in);           //設(shè)置輸入點云
        proj.setModelCoefficients(coefficients);        //設(shè)置模型對應(yīng)的系數(shù)
        proj.filter(*cloud_out);    //執(zhí)行投影濾波存儲結(jié)果cloud_projected

    }

雙邊濾波

雙邊濾波利用的并非XYZ字段的數(shù)據(jù)進(jìn)行,而是利用強度數(shù)據(jù)字段進(jìn)行雙邊濾波算法的實現(xiàn),所以在使用該類時點云的類型中字段必須有強度字段,否則無法進(jìn)行雙邊濾波處理。

#include <pcl/filters/bilateral.h>

    /// <summary>
    /// 雙邊濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="sigma_s">高斯雙邊濾波窗口大小</param>
    /// <param name="sigma_r">高斯標(biāo)準(zhǔn)差表示強度差異</param>
    /// <param name="tree">提取搜索方法的樹對象,一般用近鄰的kdTree即可</param>
    void bilateralFilter(pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud_in, pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud_out, const float& sigma_s, const float& sigma_r, pcl::search::Search<pcl::PointXYZI>::Ptr tree) {
        pcl::BilateralFilter<pcl::PointXYZI> bf;
        bf.setInputCloud(cloud_in);            //設(shè)置輸入點云
        bf.setSearchMethod(tree);
        bf.setHalfSize(sigma_s);
        bf.setStdDev(sigma_r);
        bf.filter(*cloud_out);
    }

#include <pcl/filters/fast_bilateral.h>

    /// <summary>
    /// 快速雙邊濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="sigma_s">高斯雙邊濾波窗口大小</param>
    /// <param name="sigma_r">高斯標(biāo)準(zhǔn)差表示強度差異</param>
    void fastBilateralFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, const float& sigma_s, const float& sigma_r) {
        pcl::FastBilateralFilter<pcl::PointXYZ> fbf;
        fbf.setInputCloud(cloud_in);            //設(shè)置輸入點云
        fbf.setSigmaS(sigma_s);
        fbf.setSigmaR(sigma_r);
        fbf.filter(*cloud_out);
    }

索引濾波

根據(jù)點云給定索引過濾出對應(yīng)點云,一般不會單獨用,都是配合一些特征提取完對應(yīng)索引后來用。

#include <pcl/filters/extract_indices.h>

    /// <summary>
    /// 索引濾波
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cloud_out">輸出點云</param>
    /// <param name="indices">過濾的點云索引</param>
    /// <param name="negative">默認(rèn)值為 false,輸出點云為在設(shè)定字段的設(shè)定范圍內(nèi)的點集,如果設(shè)置為 true 則剛好相反</param>
    void extractIndicesFilter(pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_out, pcl::PointIndices::Ptr &indices, bool negative) {

        pcl::ExtractIndices<pcl::PointXYZ> extract;
        extract.setInputCloud(cloud_in);
        extract.setIndices(indices);
        extract.setNegative(negative);
        extract.filter(*cloud_out);
    }

總結(jié)

一般場景這些濾波組合能解決95%的應(yīng)用場景,其他的濾波應(yīng)用場景是在很少如pcl::BoxClipper3D用來空間剪裁也可以指定立方體,pcl::filters::Convolution是卷積濾波設(shè)置卷積核,pcl::filters::GaussianKernelpcl::filters::GaussianKernelRGB是高斯卷積核濾波,基本其他這些在實際場景里很少用到

點云分割匯總

這里的分割結(jié)果基本為索引再配合上問的索引濾波可以提取出對應(yīng)點云。

歐式距離分割

歐式距離分割是基于歐氏距離進(jìn)行聚類分割的類,這里注意這個類pcl::gpu::EuclideanClusterExtraction這么寫會在gpu上跑,而pcl::EuclideanClusterExtraction這么寫則會在cpu上,這類寫法同樣適用pcl內(nèi)其他的類,另外還有一些別的歐式聚類的類看名稱就能猜到用途,如LabeledEuclideanClusterExtraction就是多了一個setMaxLabels設(shè)置點云標(biāo)簽的最大數(shù)量。

這個方法用的也算頻繁的,大部分場景 下采樣-歐式聚類-投影,這時候就直接變二維圖像了,opencv提取個輪廓基本工業(yè)場景的視覺要做的就完成了很大一部分。

#include <pcl/segmentation/extract_clusters.h>

    /// <summary>
    /// 歐式距離分割
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cluster_indices_out">輸出索引</param>
    /// <param name="tolerance">近鄰搜索的搜索半徑 m</param>
    /// <param name="min_cluster_size">一個聚類需要的最少點數(shù)目</param>
    /// <param name="max_cluster_size">一個聚類需要的最大點數(shù)目</param>
    void euclideanClusterExtraction(pcl::PointCloud<pcl::PointXYZ>::Ptr &cloud_in, std::vector<pcl::PointIndices> &cluster_indices_out, double tolerance, int min_cluster_size, int max_cluster_size) {
        // 創(chuàng)建用于提取搜索方法的kdtree樹對象
        pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
        tree->setInputCloud(cloud_in);

        pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;      //歐式聚類對象
        ec.setClusterTolerance(tolerance);                      // 設(shè)置近鄰搜索的搜索半徑為tolerance m
        ec.setMinClusterSize(min_cluster_size);                     //設(shè)置一個聚類需要的最少的點數(shù)目為100
        ec.setMaxClusterSize(max_cluster_size);                 //設(shè)置一個聚類需要的最大點數(shù)目為200000
        ec.setSearchMethod(tree);                       //設(shè)置點云的搜索機制
        ec.setInputCloud(cloud_in);
        ec.extract(cluster_indices_out);                    //從點云中提取聚類,并將點云索引保存在cluster_indices中
    }

采樣一致性分割

采樣一致性分割算法的目的主要是從原點云中提取目標(biāo)模型,比如說面,球體,圓柱等等,從而為后續(xù)的目標(biāo)識別或者點云匹配等等做準(zhǔn)備。這里只詳細(xì)講比較有代表性的pcl::SACSegmentation,這一類還有SACSegmentationFromNormals其在算法實現(xiàn)時采用了法線信息,即該類在進(jìn)行運算輸出之前需要設(shè)定法線信息。

采樣一致性算法
1. 隨機采樣一致性算法(SAC_RANSAC)

pcl::RandomSampleConsensus< PointT > Class Template Reference
RandomSampleConsensus 表示隨機采樣一致性算法的實現(xiàn),該算法的工作原理如下:
從云中隨機選擇樣本,數(shù)量與確定模型所需的數(shù)量一樣多;
從樣本中計算模型的系數(shù);
在給定閾值的情況下,計算云中有多少點屬于模型。 這些被稱為內(nèi)點;
重復(fù)直到找到一個好的模型或達(dá)到最大迭代次數(shù),返回具有最多內(nèi)點的模型。

2. 最小平方中值算法(SAC_LMEDS)

pcl::LeastMedianSquares< PointT > Class Template Reference
LeastMedianSquares 為最小平方中值算法的實現(xiàn)。LMedS 是一種類似于 RANSAC 的模型擬合算法,可以容忍高達(dá) 50% 的異常值,而無需設(shè)置閾值。與 RANSAC 相比,LMedS 在查找模型時不會將點分為內(nèi)點和異常點。 相反,它使用所有點模型距離的中值作為模型好壞的衡量標(biāo)準(zhǔn)。 只有在最后確定哪些點屬于找到的模型時才需要一個閾值。

3. M-估計量樣本一致性算法(SAC_MSAC)

pcl::MEstimatorSampleConsensus< PointT > Class Template Reference
MEstimatorSampleConsensus 表示 M-估計量樣本一致性算法的實現(xiàn)。RANSAC 在給定閾值的情況下計算內(nèi)點數(shù)。 內(nèi)點越多,模型越好——內(nèi)點與模型的實際距離有多近并不重要,只要它們在閾值內(nèi)即可。 MSAC 通過使用所有點模型距離的總和作為質(zhì)量度量來改變這一點,但是異常值僅添加閾值而不是它們的真實距離。 與 RANSAC 相比,這種方法可以產(chǎn)生更好的結(jié)果。

4. 快點的隨機采樣一致性算法(SAC_RRANSAC)

pcl::RandomizedRandomSampleConsensus< PointT > Class Template Reference
RandomizedRandomSampleConsensus 表示 RRANSAC的實現(xiàn),該算法的工作原理與 RANSAC 類似,但有一個補充:計算模型系數(shù)后,隨機選擇一小部分點;如果這些點中的任何一個點在給定的閾值內(nèi)不屬于擬合模型,則繼續(xù)下一次迭代,而不是檢查所有點。 如果預(yù)先測試的分?jǐn)?shù)選擇得當(dāng),則可能會加快模型的擬合速度。

5. 隨機M-估計量樣本一致性(SAC_RMSAC)

pcl::RandomizedMEstimatorSampleConsensus< PointT > Class Template Reference
RandomizedMEstimatorSampleConsensus 表示 隨機M-估計量樣本一致性算法的實現(xiàn),RMSAC 在大部分樣本數(shù)據(jù)屬于模型的情況下很有用。是MEstimatorSampleConsensus和RandomizedRandomSampleConsensus的綜合版本,首先隨機選取一些采樣點,如果這些點中的任何一個點在給定閾值范圍內(nèi)不屬于待擬合的模型,則繼續(xù)下一次迭代,而不是檢查所有點。同時使用所有點模型距離的總和作為質(zhì)量度量來改變這一點,異常值僅添加閾值而不是它們的真實距離。

6. 最大似然估計樣本一致性算法(SAC_MLESAC)

pcl::MaximumLikelihoodSampleConsensus< PointT > Class Template Reference
MaximumLikelihoodSampleConsensus 表示 最大似然估計樣本一致性算法的實現(xiàn)。通過最小化概率損失作為評價指標(biāo)。使用由內(nèi)點和外點產(chǎn)生的誤差的概率模型來評估模型的適應(yīng)性,選取模型適應(yīng)性最高的模型參數(shù)作為最終結(jié)果。

7. 漸進(jìn)樣本一致性算法(SAC_PROSAC)

pcl::ProgressiveSampleConsensus< PointT > Class Template Reference
ProgressiveSampleConsensus 表示 漸進(jìn)樣本一致性算法的實現(xiàn),漸進(jìn)一致性算法 (PROSAC) 是對經(jīng)典 RANSAC采樣的一種優(yōu)化。相比經(jīng)典 RANSAC 方法均勻地從整個樣本集合中采樣,PROSAC 不是從所有數(shù)據(jù)點中進(jìn)行隨機采樣,而是先對數(shù)據(jù)點進(jìn)行排序,然后在評價函數(shù)值最高的數(shù)據(jù)點子集中進(jìn)行隨機采樣。該方法從采樣點的選取方式入手,選擇評價函數(shù)值最高的數(shù)據(jù)進(jìn)行隨機采樣。所以這種方法可以節(jié)省計算量,提高運行速度。

采樣一致性的幾何模型的類型
SACMODEL_PLANE模型

定義為平面模型,共設(shè)置4個參數(shù)[ normal_x, normal_y, normal_z d],其中(normal_x, normal_y, normal_z)為Hessian 范式中法向量的坐標(biāo)及常量d值,ax+by+cz+d=0,從點云中分割提取的內(nèi)點都處在估計參數(shù)對應(yīng)的平面上或與平面距離在一定范圍內(nèi)。

SACMODEL_LINE模型

定義為直線模型,共設(shè)置6個參數(shù)[point_on_line.x, point_on_line.y, point_on_line.z, line_direction.x, line_direction.y, line_direction.z],其中(point_on_line.x,point_on_line.y,point_on_line.z)為直線上一點的三維坐標(biāo),(line_direction.x, line_direction.y, line_direction.z)為直線方向向量的三維坐標(biāo),從點云中分割提取的內(nèi)點都處在估計參數(shù)對應(yīng)直線上或與直線的距離在一定范圍內(nèi)。

SACMODEL_CIRCLE2D模型

定義為二維圓的圓周模型,共設(shè)置3個參數(shù)[center.x, center.y, radius],其中(center.x, center.y)為圓周中心點的二維坐標(biāo),radius為圓周半徑,從點云中分割提取的內(nèi)點都處在估計參數(shù)對應(yīng)的圓周上或距離圓周邊線的距離在一定范圍內(nèi)。

SACMODEL_SPHERE模型

定義為三維球體模型,共設(shè)置4個參數(shù)[center.x, center.y, center.z radius],其中(center. x, center. y, center. z)為球體中心的三維坐標(biāo),radius為球體半徑,從點云中分割提取的內(nèi)點都處在估計參數(shù)對應(yīng)的球體上或距離球體邊線的距離在一定范圍內(nèi)。

SACMODEL_NORMAL_SPHERE模型

定義為有條件限制的三維球體模型,參數(shù)設(shè)置參見SampleConsensusModelNormalSphere模型。

SACMODEL_CYLINDER模型

定義為圓柱體模型,共設(shè)置7個參數(shù)[point_on_axis.x, point_on_axis.y, point_on_axis.z, axis_direction.x ,axis_direction.y ,axis_diection.z, radius],其中,(point_on_axis.x, point_on_axis.y, point_on_axis.z)為軸線上點的三維坐標(biāo),(direction.x ,axis_direction.y, axis_direction.z)為軸線方向向量的三維坐標(biāo),radius為圓柱體半徑,從點云中分割提取的內(nèi)點都處在估計參數(shù)對應(yīng)的圓柱體上或距離圓柱體表面的距離在一定范圍內(nèi)。

SACMODEL_CONE模型

定義為圓錐模型,共設(shè)置7個參數(shù)[apex.x, apex.y, apex.z, axis_direction.x, axis_direction.y, axis_direction.z, opening_angle],其中(apex.x, apex.y, apex.z)圓錐頂點,(axis_direction.x, axis_direction.y, axis_direction.z)為圓錐軸方向的三維坐標(biāo),opening_angle為圓錐的開口角度

SACMODEL_TORUS模型

定義為圓環(huán)面模型,尚未實現(xiàn)。

SACMODEL_PARALLEL_LINE 模型

定義為有條件限制的直線模型,在規(guī)定的最大角度偏差限制下,直線模型與給定軸線平行,共設(shè)置6個參數(shù)[point_on_line.x, point_on_line.y, point_on_line.z, line_direction.x, line_direction.y, line_direction.z],其中(point_on_line.x, point_on_line.y, point_on_line.z)為線上一個點的三維坐標(biāo),(line_direction.x, line_direction.y, line_direction.z)為直線方向的三維坐標(biāo)。

SACMODEL_PERPENDICULAR_PLANE模型

定義為有條件限制的平面模型,在規(guī)定的最大角度偏差限制下,平面模型與給定軸線垂直,參數(shù)設(shè)置參見SAC-MODEL_PLANE模型。

SACMODEL_NORMAL_PLANE模型

定義為有條件限制的平面模型,在規(guī)定的最大角度偏差限制下,每一個局內(nèi)點的法線必須與估計的平面模型的法線平行,參數(shù)設(shè)置參見SACMODEL_PLANE模型。

SACMODEL_PARALLEL_PLANE模型

定義為有條件限制的平面模型,在規(guī)定的最大角度偏差限制下,平面模型與給定的軸線平行,參數(shù)設(shè)置參見SACMODEL_PLANE模型。

SACMODEL_NORMAL_PARALLEL_PLANE模型

定義為有條件限制的平面模型,在法線約束下,三維平面模型必須與用戶設(shè)定的軸線平行,共4個參數(shù)[a,b,c,d],其中a是平面法線的 X 坐標(biāo)(歸一化),b是平面法線的 Y 坐標(biāo)(歸一化),c是平面法線的 Z 坐標(biāo)(歸一化),d是平面方程的第四個 Hessian 分量。

SACMODEL_STICK模型

定義棒是用戶給定最小/最大寬度的線。共7個參數(shù)[point_on_line.x, point_on_line.y, point_on_line.z, line_direction.x, line_direction.y, line_direction.z, line_width],其中(point_on_line.x, point_on_line.y, point_on_line.z)為線上一個點的三維坐標(biāo),(line_direction.x, line_direction.y, line_direction.z)為直線方向的三維坐標(biāo),line_width為線的寬度。

具體實現(xiàn)

#include <pcl/segmentation/sac_segmentation.h>

    /// <summary>
    /// 一致性分割
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cluster_indices_out">輸出索引</param>
    /// <param name="coefficients_out">輸出模型</param>
    /// <param name="methodType">采樣一致性方法的類型</param>
    /// <param name="modelType">采樣一致性所構(gòu)造的幾何模型的類型</param>
    /// <param name="distance">點到模型的距離閾值</param>
    /// <param name="max_iterations">迭代次數(shù)的上限</param>
    /// <param name="probability">選取至少一個局內(nèi)點的概率</param>
    void sacSegmentationExtraction(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, int methodType, pcl::SacModel modelType, double distance, int max_iterations, double probability, pcl::PointIndices &cluster_indices_out, pcl::ModelCoefficients &coefficients_out) {
        pcl::SACSegmentation<pcl::PointXYZ> sac;        //一致性分割
        sac.setInputCloud(cloud_in);
        //設(shè)置使用采樣一致性方法的類型(用戶給定參數(shù)),采樣一致性方法的類型有
        //SAC_RANSAC(隨機采樣一致性)、SAC_LMEDS(最小平方中值)、 SAC_MSAC(M估計采樣一致性)、SAC_RRANSAC(隨機采樣一致性)、SAC_RMSAC(M估計采樣一致性)、SAC_MLESAC(最大似然采樣一致性)、SAC_PROSAC(漸進(jìn)一致性采樣)
        sac.setMethodType(methodType);
        //設(shè)置隨機采樣一致性所構(gòu)造的幾何模型的類型(用戶給定的參數(shù)),model為指定的模型類型參數(shù)SACMODEL_PLANE,SACMODEL_LINE,SACMODEL_CIRCLE2D,SACMODEL_CIRCLE3D,SACMODEL_SPHERE,SACMODEL_CYLINDER,SACMODEL_CONE,SACMODEL_TORUS,SACMODEL_PARALLEL_LINE,SACMODEL_PERPENDICULAR_PLANE,SACMODEL_PARALLEL_LINES,SACMODEL_NORMAL_PLANE,SACMODEL_NORMAL_SPHERE,SACMODEL_REGISTRATION,SACMODEL_REGISTRATION_2D,SACMODEL_PARALLEL_PLANE,SACMODEL_NORMAL_PARALLEL_PLANE,SACMODEL_STICK
        sac.setModelType(modelType);
        //設(shè)置點到模型的距離閾值,如果點到模型的距離不超過這個距離閾值,認(rèn)為該點為局內(nèi)點,否則認(rèn)為是局外點,被剔除。
        sac.setDistanceThreshold(distance);
        sac.setMaxIterations(max_iterations);   //設(shè)置迭代次數(shù)的上限
        sac.setProbability(probability);        //設(shè)置每次從數(shù)據(jù)集中選取至少一個局內(nèi)點的概率
        
        ////設(shè)置是否對估計的模型參數(shù)進(jìn)行優(yōu)化
        //sac.setOptimizeCoefficients(optimize); 
        ////該函數(shù)配合,當(dāng)用戶設(shè)定帶有半徑參數(shù)的模型類型時,設(shè)置模型半徑參數(shù)的最大最小半徑閾值
        //sac.setRadiusLimits(min_radius, max_radius);
        ////該函數(shù)配合,當(dāng)用戶設(shè)定與軸線平行或垂直有關(guān)的模型類型時,設(shè)置垂直或平行于所要建立模型的軸線。
        //sac.setAxis(ax);
        ////該函數(shù)配合,當(dāng)用戶設(shè)定有平行或垂直限定有關(guān)的模型類型時,設(shè)置判斷是否平行或垂直時的角度閾值,ea是最大角度差,采用弧度制。
        //sac.setEpsAngle(ea);
        
        //輸出最終估計的模型參數(shù),以及分割得到的點集合索引
        sac.segment(cluster_indices_out, coefficients_out);
    }

凸包分割

通過設(shè)置一組處于同一平面模型上的點索引向量,并指定一高度,利用指定的點形成二維凸包,再結(jié)合指定高度一起生成一個立體多邊形棱柱模型,該類用于分割出該棱柱模型內(nèi)部的點集,比如分割出放在平面上的物體。

#include <pcl/segmentation/extract_polygonal_prism_data.h>
    /// <summary>
    /// 凸包分割
    /// </summary>
    /// <param name="cloud_in">輸入點云</param>
    /// <param name="cluster_indices_out">輸出索引</param>
    /// <param name="hull_in">凸包點云</param>
    /// <param name="height_min">最大高度</param>
    /// <param name="height_max">最小高度</param>
    /// <param name="vpx">視點坐標(biāo)x</param>
    /// <param name="vpy">視點坐標(biāo)x</param>
    /// <param name="vpz">視點坐標(biāo)z</param>
    void extractPolygonalPrismDataExtraction(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, pcl::PointCloud<pcl::PointXYZ>::Ptr& hull_in, pcl::PointIndices& cluster_indices_out, double height_min, double height_max, float vpx, float vpy, float vpz) {
        pcl::ExtractPolygonalPrismData<pcl::PointXYZ> eppd;
        //設(shè)置高度范圍(height_max為最大高度、height_min為最小高度),當(dāng)給定點云中的點到構(gòu)造棱柱體的平面模型的距離超出指定的這個高度范圍時,該點視為局外點,所有的局外點都會被剔除。
        eppd.setHeightLimits(height_min, height_max);
        eppd.setViewPoint(vpx, vpy, vpz);       //設(shè)置視點,vpx,vpy,vpz分別為視點的三維坐標(biāo)。
        eppd.setInputCloud(cloud_in);
        eppd.setInputPlanarHull(hull_in);       //設(shè)置平面模型上的點集,hull為指向該點集的指針
        eppd.segment(cluster_indices_out);      //從點云中提取聚類,并將點云索引保存在cluster_indices中
    }

其他不常用的

pcl::SeededHueSegmentation是基于顏色信息的點云區(qū)域生長分割算法,該算法在分割時不僅使用了點云的空間信息還使用了點云所帶的可見光信息,非常適合對基于RGBD設(shè)備獲取的點云進(jìn)行分割處理。
pcl::SegmentDifferences可以得到在對應(yīng)點最大偏差距離限制下的兩個配準(zhǔn)后點云的差異,此算法輸入為兩組已經(jīng)配準(zhǔn)的點云,設(shè)置兩組點云對應(yīng)點之間的偏差距離閾值,最后返回兩組點云的差。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容