軟件網(wǎng)站模版灰色行業(yè)關(guān)鍵詞推廣
0、濾波算法概述
????????PCL點(diǎn)云庫(kù)中的濾波算法是處理點(diǎn)云數(shù)據(jù)不可或缺的一部分,它們能夠有效地去除噪聲、提取特征或進(jìn)行數(shù)據(jù)降維。例如,使用體素網(wǎng)格濾波(VoxelGrid)可以減少點(diǎn)云數(shù)據(jù)量,同時(shí)保留重要的形狀特征。此外,統(tǒng)計(jì)濾波器(StatisticalOutlierRemoval)能夠識(shí)別并移除離群點(diǎn),這對(duì)于清理數(shù)據(jù)集中的異常值非常有用。在實(shí)際應(yīng)用中,濾波器的選擇和配置需要根據(jù)具體任務(wù)的需求來(lái)決定,比如在機(jī)器人導(dǎo)航中,可能需要使用半徑濾波器(RadiusOutlierRemoval)來(lái)去除距離傳感器過(guò)近或過(guò)遠(yuǎn)的點(diǎn),以獲得更準(zhǔn)確的環(huán)境模型。通過(guò)這些濾波技術(shù),可以顯著提高點(diǎn)云數(shù)據(jù)的質(zhì)量,為后續(xù)的處理和分析工作打下堅(jiān)實(shí)的基礎(chǔ)。在PCL點(diǎn)云濾波中,還有一種常見(jiàn)的濾波方法是條件濾波(ConditionalRemoval)。這種方法允許用戶(hù)根據(jù)自定義的條件來(lái)移除點(diǎn)云中的某些點(diǎn)。比如,可以根據(jù)點(diǎn)的坐標(biāo)范圍、顏色范圍或者法線(xiàn)方向等條件進(jìn)行過(guò)濾,以提取出滿(mǎn)足特定條件的點(diǎn)云子集。條件濾波的靈活性使得它適用于各種復(fù)雜的場(chǎng)景和需求。
????????除了上述提到的濾波方法外,PCL點(diǎn)云庫(kù)還提供了許多其他類(lèi)型的濾波算法,如雙邊濾波(BilateralFilter)和高斯濾波(GaussianFilter)等。雙邊濾波能夠在保留邊緣特征的同時(shí)平滑點(diǎn)云數(shù)據(jù),非常適合于去除噪聲但又不希望破壞點(diǎn)云中的細(xì)節(jié)結(jié)構(gòu)。而高斯濾波則是一種更為簡(jiǎn)單的平滑濾波方法,它通過(guò)計(jì)算每個(gè)點(diǎn)周?chē)徲騼?nèi)的點(diǎn)的加權(quán)平均來(lái)更新該點(diǎn)的位置,從而達(dá)到平滑的效果。
????????在實(shí)際應(yīng)用中,PCL點(diǎn)云濾波算法的選擇通常需要綜合考慮多個(gè)因素,包括濾波效果、計(jì)算效率以及具體的應(yīng)用場(chǎng)景等。有時(shí),為了獲得更好的濾波效果,可能需要結(jié)合使用多種濾波方法。例如,可以先使用體素網(wǎng)格濾波進(jìn)行數(shù)據(jù)下采樣,然后再使用統(tǒng)計(jì)濾波器去除剩余的噪聲點(diǎn)。這樣的組合使用可以充分發(fā)揮各種濾波算法的優(yōu)勢(shì),達(dá)到最佳的濾波效果??傊?#xff0c;PCL點(diǎn)云庫(kù)中的濾波算法為我們提供了強(qiáng)大的工具來(lái)處理和分析點(diǎn)云數(shù)據(jù)。通過(guò)合理選擇和使用這些濾波方法,我們可以有效地去除噪聲、提取特征或進(jìn)行數(shù)據(jù)降采樣,為后續(xù)的點(diǎn)云處理和分析工作提供有力的支持。下面我們將從條件濾波和直通濾波開(kāi)啟PCL庫(kù)中濾波算法之旅!
1、直通濾波算法(PassThrough? Filter)
1.1、算法原理
????????PCL庫(kù)中點(diǎn)云直通濾波算法是一種簡(jiǎn)單有效的點(diǎn)云數(shù)據(jù)處理方法,其核心思想是根據(jù)要濾波的字段(如,X軸,Y軸,Z軸)和設(shè)定閾值范圍α∈(limitMin,limitMax),如x∈[0.1,0.5],通過(guò)這個(gè)閾值來(lái)決定哪些點(diǎn)是噪聲點(diǎn),哪些點(diǎn)是有效點(diǎn)。直觀式子如下:
????????在實(shí)際操作中,算法會(huì)遍歷點(diǎn)云數(shù)據(jù)集中的每一個(gè)點(diǎn),根據(jù)預(yù)設(shè)的閾值條件來(lái)判斷該點(diǎn)是否保留。通常,這個(gè)條件可能與點(diǎn)的強(qiáng)度、距離、角度或其他特征有關(guān)。通過(guò)這種方式,可以有效地去除那些不符合條件的噪聲點(diǎn),從而得到更加平滑和準(zhǔn)確的點(diǎn)云數(shù)據(jù),為后續(xù)的處理和分析提供更加可靠的輸入。
1.2、主要成員函數(shù)和變量?
????????PCL庫(kù)中的pcl:PassThrough類(lèi)實(shí)現(xiàn)了比較靈活,完全取決于用戶(hù)設(shè)置的限定字段和對(duì)應(yīng)條件的直通濾波算法。主要的成員變量和函數(shù)有如下:
????????1、主要成員變量
????????1)、用戶(hù)所需要過(guò)濾字段名稱(chēng)
std::string filter_field_name_;
????????2)、限制的最小過(guò)濾值?
double filter_limit_min_;
????????3)、限制的最大過(guò)濾值
double filter_limit_max_;
????????2、主要成員函數(shù)
????????1)、設(shè)置限定字段的名稱(chēng)字符串field_name,例如"X"
void setFilterFieldName(const std::string &field_ name)
????????2)、設(shè)置濾波限制條件, 最小值limit_ min和最大值limit_max?
void setFilterLimits(const double &limit_min,const double &limit_max)
????????3)、設(shè)置返回濾波結(jié)果是限制條件外點(diǎn)還是內(nèi)部點(diǎn),limit_negative默認(rèn)值為false,輸出點(diǎn)云為在設(shè)定字段的設(shè)定范圍內(nèi)的點(diǎn)集,如果設(shè)置為true則剛好相反
inline void setFilterLimitsNegative (const bool limit_negative)
1.3、主要部分代碼注解
template <typename PointT> void
pcl::PassThrough<PointT>::applyFilterIndices (std::vector<int> &indices)
{// The arrays to be usedindices.resize (indices_->size ());removed_indices_->resize (indices_->size ());int oii = 0, rii = 0; // oii = 輸出索引, rii = 移除索引// 如果未指定濾波的字段,則僅僅是移除點(diǎn)云數(shù)據(jù)無(wú)效點(diǎn)if (filter_field_name_.empty ()){// 僅僅是移除點(diǎn)云數(shù)據(jù)無(wú)效點(diǎn)for (const auto ii : *indices_) // ii = input index{// // 濾掉無(wú)效點(diǎn)if (!std::isfinite (input_->points[ii].x) ||!std::isfinite (input_->points[ii].y) ||!std::isfinite (input_->points[ii].z)){if (extract_removed_indices_)(*removed_indices_)[rii++] = ii;continue;}indices[oii++] = ii;}}else{// 獲取字段名稱(chēng)的索引,如字段“z",返回索引為:std::vector<pcl::PCLPointField> fields;int distance_idx = pcl::getFieldIndex<PointT> (filter_field_name_, fields);if (distance_idx == -1){PCL_WARN ("[pcl::%s::applyFilter] Unable to find field name in point type.\n", getClassName ().c_str ());indices.clear ();removed_indices_->clear ();return;}// 濾波算法主體,濾掉無(wú)效點(diǎn)和指定的字段限制值for (const auto ii : *indices_) // ii = input index{// 濾掉無(wú)效點(diǎn)if (!std::isfinite (input_->points[ii].x) ||!std::isfinite (input_->points[ii].y) ||!std::isfinite (input_->points[ii].z)){if (extract_removed_indices_)(*removed_indices_)[rii++] = ii;//保留移除點(diǎn)的索引continue;}// 獲取指定字段的值,如x=0.3const std::uint8_t* pt_data = reinterpret_cast<const std::uint8_t*> (&input_->points[ii]);float field_value = 0;memcpy (&field_value, pt_data + fields[distance_idx].offset, sizeof (float));// 判斷獲取指定字段的值是否為無(wú)效點(diǎn),如果是則移除掉if (!std::isfinite (field_value)){if (extract_removed_indices_)(*removed_indices_)[rii++] = ii;continue;}//negative_ 為false, 在字段限制值之外將會(huì)被移除,if (!negative_ && (field_value < filter_limit_min_ || field_value > filter_limit_max_)){if (extract_removed_indices_)(*removed_indices_)[rii++] = ii;continue;}// negative_ 為true,在字段限制值之外將會(huì)保留if (negative_ && field_value >= filter_limit_min_ && field_value <= filter_limit_max_){if (extract_removed_indices_)(*removed_indices_)[rii++] = ii;continue;}// 保留輸出內(nèi)點(diǎn)的索引indices[oii++] = ii;}}// Resize the output arraysindices.resize (oii);removed_indices_->resize (rii);
}
1.4、算法使用示例
/*****************************************************************//**
* \file PCLPassthroughmain.cpp
* \brief
*
* \author YZS
* \date December 2024
*********************************************************************/
#include<iostream>
#include <vector>
#include <ctime>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/auto_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/conditional_removal.h>
void Passthrough()
{// 隨機(jī)種子初始化srand(time(NULL));pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);// 生成點(diǎn)云數(shù)據(jù)3000個(gè)cloud->width = 1000;cloud->height = 1;cloud->points.resize(cloud->width * cloud->height);for (size_t i = 0; i < cloud->points.size(); ++i) {cloud->points[i].x = 10.0f * rand() / (RAND_MAX + 1.0f);cloud->points[i].y = 10.0f * rand() / (RAND_MAX + 1.0f);cloud->points[i].z = 10.0f * rand() / (RAND_MAX + 1.0f);}//保存濾波的結(jié)果pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFilter(new pcl::PointCloud<pcl::PointXYZ>);// 創(chuàng)建PassThrough濾波器對(duì)象pcl::PassThrough<pcl::PointXYZ> pass;//濾波器對(duì)象pass.setInputCloud(cloud); //設(shè)置需要濾波的點(diǎn)云pass.setFilterFieldName("y"); //設(shè)置需要濾波的字段pass.setFilterLimits(0.0, 5.0); //設(shè)置限定范圍//pass.setFilterLimitsNegative (true);//是否反向過(guò)濾,默認(rèn)為falsepass.filter(*cloudFilter); //執(zhí)行濾波//結(jié)果可視化// PCLVisualizer對(duì)象pcl::visualization::PCLVisualizer viewer("FilterVIS");//創(chuàng)建左右窗口的ID v1和v2int v1(0);int v2(1);//設(shè)置V1窗口尺寸和背景顏色viewer.createViewPort(0.0, 0.0, 0.5, 1, v1);viewer.setBackgroundColor(0, 0, 0, v1);//設(shè)置V2窗口尺寸和背景顏色viewer.createViewPort(0.5, 0.0, 1, 1, v2);viewer.setBackgroundColor(0.1, 0.1, 0.1, v2);//設(shè)置cloud1的渲染顏色,點(diǎn)云的ID和指定可視化窗口v1pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud1_color(cloud, 255, 255, 255);viewer.addPointCloud(cloud, cloud1_color, "cloud1", v1);viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud1");//設(shè)置cloud2的渲染顏色,點(diǎn)云的ID和指定可視化窗口v2pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud2_color(cloud, 250, 255, 255);viewer.addPointCloud(cloudFilter, cloud2_color, "cloud2", v2);viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud2");// 可視化循環(huán)主體while (!viewer.wasStopped()){viewer.spinOnce();}
}
int main(int argc, char* argv[])
{Passthrough();std::cout << "Hello World!" << std::endl;std::system("pause");return 0;
}
????????結(jié)果:
2、條件濾波算法(ConditionalRemoval?Filter?)
2.1、算法原理
????????點(diǎn)云濾波條件濾波算法原理基于設(shè)定的條件來(lái)篩選點(diǎn)云數(shù)據(jù)。與直通濾波算法不同,條件濾波算法不限于單一的軸向閾值,而是可以基于點(diǎn)云的多種屬性,如強(qiáng)度、顏色、法線(xiàn)方向等,來(lái)定義更為復(fù)雜的濾波規(guī)則。例如,可以設(shè)置一個(gè)強(qiáng)度閾值,僅保留強(qiáng)度在一定范圍內(nèi)的點(diǎn),或者根據(jù)點(diǎn)的法線(xiàn)方向來(lái)過(guò)濾數(shù)據(jù),只保留那些法線(xiàn)方向符合特定條件的點(diǎn)。因此,條件濾波允許用戶(hù)定義一個(gè)或多個(gè)條件表達(dá)式,這些表達(dá)式會(huì)應(yīng)用于點(diǎn)云數(shù)據(jù)集中的每一個(gè)點(diǎn)。算法會(huì)根據(jù)這些條件表達(dá)式來(lái)決定是否保留某個(gè)點(diǎn)。由于條件可以非常靈活,因此這種算法能夠適應(yīng)各種不同的應(yīng)用場(chǎng)景和需求。在實(shí)際應(yīng)用中,條件濾波算法可以實(shí)現(xiàn)更為精細(xì)的數(shù)據(jù)處理。例如,在自動(dòng)駕駛車(chē)輛的激光雷達(dá)數(shù)據(jù)處理中,可以使用條件濾波來(lái)去除地面反射的點(diǎn),保留車(chē)輛和障礙物的點(diǎn)云數(shù)據(jù)。這樣的處理對(duì)于后續(xù)的物體檢測(cè)和分類(lèi)至關(guān)重要。
2.2、主要成員函數(shù)和變量
????????PCL庫(kù)中的pcl:ConditionalRemoval類(lèi)中提供了多種條件比較,如FieldComparison類(lèi)(字段比較)、PackedRGBComparison類(lèi)(RGB顏色比較)、PackedHSIComparison類(lèi)(HSI色彩比較)和TfQuadraticXYZComparison類(lèi)(二次項(xiàng)比較)等條件類(lèi)型,這些條件類(lèi)型最終通過(guò)ConditionOr類(lèi)和ConditionAnd類(lèi)來(lái)控制調(diào)用,用戶(hù)可以根據(jù)自己的需求來(lái)設(shè)置濾波條件。濾波算法中主要的成員變量有如下:
????????1、主要成員變量
????????1)、是否要保持點(diǎn)云數(shù)據(jù)的原始結(jié)構(gòu),true,保持原始結(jié)構(gòu),被濾波的點(diǎn)用NAN替代,false不保存原始結(jié)果。
bool keep_organized_;
????????2)、濾波比較條件
ConditionBasePtr condition_;
????????濾波條件類(lèi):
????????class ConditionAnd??當(dāng)所有比較條件值都為真時(shí),ConditionAnd的值為真
????????class ConditionOr? ?當(dāng)任何比較條件的值為真時(shí),ConditionOr的值為真
????????3)、用戶(hù)設(shè)置的過(guò)濾限定值
float user_filter_value_;
??????????2、主要成員函數(shù)
????????????1)、設(shè)置是否要保持點(diǎn)云數(shù)據(jù)的原始結(jié)構(gòu)
inline void setKeepOrganized (bool val);
? ? ? ? ? ? 2)、設(shè)置用戶(hù)提供的過(guò)濾限定值?
inline void setUserFilterValue (float val);
? ? ? ? ? ?3)、設(shè)置過(guò)濾器所用條件。每個(gè)參數(shù)條件都必須滿(mǎn)足,以確保數(shù)據(jù)點(diǎn)不會(huì)因不滿(mǎn)足條件而被過(guò)濾器排除。
void setCondition (ConditionBasePtr condition);
?????????比較操作的類(lèi)型如下:
enum CompareOp{GT, GE, LT, LE, EQ};
? ? ? ? 具體含義如下:?
EQ EQUAL等于GT GREATER THAN大于 LT LESS THAN小于GE GREATER THAN OR EQUAL 大于等于LE LESS THAN OR EQUAL 小于等于
?2.3、主要部分代碼注解
template <typename PointT> void
pcl::ConditionalRemoval<PointT>::applyFilter (PointCloud &output)
{........// 將輸入的頭文件賦值給輸出文件output.header = input_->header;if (!keep_organized_){//不保存原來(lái)數(shù)據(jù)結(jié)構(gòu) output.height = 1; output.is_dense = true;}else{//保存原來(lái)數(shù)據(jù)結(jié)構(gòu) output.height = this->input_->height;output.width = this->input_->width;output.is_dense = this->input_->is_dense;}output.points.resize (input_->points.size ());removed_indices_->resize (input_->points.size ());int nr_p = 0;int nr_removed_p = 0;//不保存原來(lái)數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)if (!keep_organized_){for (std::size_t index: (*Filter<PointT>::indices_)){const PointT& point = input_->points[index];// 無(wú)效點(diǎn)判斷if (!std::isfinite (point.x)|| !std::isfinite (point.y)|| !std::isfinite (point.z)){if (extract_removed_indices_){(*removed_indices_)[nr_removed_p] = index;nr_removed_p++;}continue;}//條件判斷實(shí)現(xiàn)接口,if (condition_->evaluate (point)){//將滿(mǎn)足條件的數(shù)據(jù)拷貝到輸出點(diǎn)云中copyPoint (point, output.points[nr_p]);nr_p++;}else{//保存移除點(diǎn)云的索引if (extract_removed_indices_){(*removed_indices_)[nr_removed_p] = index;nr_removed_p++;}}}output.width = nr_p;output.points.resize (nr_p);}else //不保存原來(lái)數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn){//獲取輸入點(diǎn)云數(shù)據(jù)的索引集合std::vector<int> indices = *Filter<PointT>::indices_;std::sort (indices.begin (), indices.end ()); //對(duì)索引集排序bool removed_p = false;std::size_t ci = 0;for (std::size_t cp = 0; cp < input_->points.size (); ++cp){//對(duì)索引集合內(nèi)的點(diǎn)進(jìn)行條件比較if (cp == static_cast<std::size_t> (indices[ci])){if (ci < indices.size () - 1){ci++;if (cp == static_cast<std::size_t> (indices[ci])) continue;}copyPoint (input_->points[cp], output.points[cp]);//條件判斷實(shí)現(xiàn)接口,if (!condition_->evaluate (input_->points[cp])){//滿(mǎn)足點(diǎn)的值設(shè)置為用戶(hù)設(shè)定的值output.points[cp].getVector4fMap ().setConstant (user_filter_value_);removed_p = true;if (extract_removed_indices_){(*removed_indices_)[nr_removed_p] = static_cast<int> (cp);nr_removed_p++;}}}else{//將非索引集合以外的點(diǎn)的值設(shè)置為用戶(hù)設(shè)定的值output.points[cp].getVector4fMap ().setConstant (user_filter_value_);removed_p = true;}}if (removed_p && !std::isfinite (user_filter_value_))output.is_dense = false;}........
}
2.4、算法使用示例
/*****************************************************************//**
* \file ConditionalRemovalmain.cpp
* \brief
*
* \author YZS
* \date December 2024
*********************************************************************/
#include<iostream>
#include <vector>
#include <ctime>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/auto_io.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/conditional_removal.h>using namespace std;void ConditionalRemoval()
{pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>());std::string fileName = "E:/PCLlearnData/9/fragment.pcd";pcl::io::load(fileName, *cloud);std::cout << "Cloud Size:" << cloud->points.size() << std::endl;// 創(chuàng)建過(guò)濾條件pcl::ConditionAnd<pcl::PointXYZRGB>::Ptr range_cond(new pcl::ConditionAnd<pcl::PointXYZRGB>());// x值 大于-0.05range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr \(new pcl::FieldComparison<pcl::PointXYZRGB>("x", pcl::ComparisonOps::GT, -1.3)));// x值 小于-1.3range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZRGB>::ConstPtr \(new pcl::FieldComparison<pcl::PointXYZRGB>("x", pcl::ComparisonOps::LT, -0.05)));//保存濾波后的結(jié)果pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudFilter(new pcl::PointCloud<pcl::PointXYZRGB>());pcl::ConditionalRemoval<pcl::PointXYZRGB> conFilter;// 條件濾波器類(lèi)對(duì)象conFilter.setCondition(range_cond); // 設(shè)置濾波條件conFilter.setInputCloud(cloud);conFilter.setKeepOrganized(false);// 設(shè)置是否保持有序,若輸入為有序點(diǎn)云,可以設(shè)置為trueconFilter.filter(*cloudFilter); // 執(zhí)行濾波,并且保存結(jié)果到cloudFilter中std::cout << "filter Cloud Size:" << cloudFilter->points.size() << std::endl;//結(jié)果可視化
// PCLVisualizer對(duì)象pcl::visualization::PCLVisualizer viewer("FilterVIS");//創(chuàng)建左右窗口的ID v1和v2int v1(0);int v2(1);//設(shè)置V1窗口尺寸和背景顏色viewer.createViewPort(0.0, 0.0, 0.5, 1, v1);viewer.setBackgroundColor(0, 0, 0, v1);//設(shè)置V2窗口尺寸和背景顏色viewer.createViewPort(0.5, 0.0, 1, 1, v2);viewer.setBackgroundColor(0.1, 0.1, 0.1, v2);// 添加2d文字標(biāo)簽viewer.addText("v1", 10, 10, 20, 1, 0, 0, "Txtv1", v1);viewer.addText("v2", 10, 10, 20, 0, 1, 0, "Txtv2", v2);//設(shè)置cloud1的渲染屬性,點(diǎn)云的ID和指定可視化窗口v1viewer.addPointCloud(cloud, "cloud1", v1);viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud1");//設(shè)置cloud2的渲染屬性,點(diǎn)云的ID和指定可視化窗口v2viewer.addPointCloud(cloudFilter, "cloud2", v2);viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "cloud2");// 可視化循環(huán)主體while (!viewer.wasStopped()){viewer.spinOnce();}
}
int main(int argc, char* argv[])
{ConditionalRemoval();std::cout << "Hello World!" << std::endl;std::system("pause");return 0;
}
????????結(jié)果:
????????至此完成第九節(jié)PCL庫(kù)點(diǎn)云濾波算法之直通濾波(PassThrough)和條件濾波(ConditionalRemoval)學(xué)習(xí),下一節(jié)我們將進(jìn)入《PCL庫(kù)中點(diǎn)云濾波之體素濾波(VoxelGrid)》的學(xué)習(xí)。?