0.引言
因笔者课题涉及点云处理,需要通过PCL进行点云数据一系列处理分析,查阅现有网络资料,对常用PCL点云滤波器进行代码实现,本文记录滤波器实现过程。
1.CloudCompare界面设计滤波(filter)按钮
(1)设计.ui文件
①设计按钮
②编译.ui
(2)修改mainwindow.h文件
//点云滤波
void doActionPCLPassThrough(); // 直通滤波器
void doActionPCLStatisticalOutlierRemoval(); // 统计滤波器
void doActionPCLRadiusOutlierRemoval(); // 半径滤波器
void doActionPCLConditionRemoval(); // 条件滤波器
void doActionPCLProjectInliers(); // 投影滤波器
void doActionPCLModelOutlierRemoval(); // 模型滤波器
void doActionPCLGaussianKernel(); // 高斯滤波器
(3)修改mainwindow.cpp文件
①添加头文件
#include <pcl/filters/passthrough.h>// 直通滤波器
#include <pcl/filters/statistical_outlier_removal.h>// 统计滤波器
#include <pcl/filters/radius_outlier_removal.h>// 半径滤波器
#include <pcl/filters/conditional_removal.h>// 条件滤波器
#include <pcl/filters/project_inliers.h>// 投影滤波器
#include <pcl/filters/model_outlier_removal.h>// 模型滤波器
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/convolution_3d.h>// GaussianKernel高斯滤波器
②添加实现代码
// 直通滤波器
void MainWindow::doActionPCLPassThrough()
{
}
// 统计滤波器
void MainWindow::doActionPCLStatisticalOutlierRemoval()
{
}
// 半径滤波器
void MainWindow::doActionPCLRadiusOutlierRemoval()
{
}
// 条件滤波器
void MainWindow::doActionPCLConditionRemoval()
{
}
// 投影滤波器
void MainWindow::doActionPCLProjectInliers()
{
}
// 模型滤波器
void MainWindow::doActionPCLModelOutlierRemoval()
{
}
// 高斯滤波器
void MainWindow::doActionPCLGaussianKernel()
{
}
③添加信号槽函数
connect(m_UI->actionPassThrough, &QAction::triggered, this, &MainWindow::doActionPCLPassThrough);//直通滤波器
connect(m_UI->actionStatisticalOutlierRemoval, &QAction::triggered, this, &MainWindow::doActionPCLStatisticalOutlierRemoval);//统计滤波器
connect(m_UI->actionRadiusOutlierRemoval, &QAction::triggered, this, &MainWindow::doActionPCLRadiusOutlierRemoval);//半径滤波器
connect(m_UI->actionConditionRemoval, &QAction::triggered, this, &MainWindow::doActionPCLConditionRemoval);//条件滤波器
connect(m_UI->actionProjectInliers, &QAction::triggered, this, &MainWindow::doActionPCLProjectInliers);//投影滤波器
connect(m_UI->actionModelOutlierRemoval, &QAction::triggered, this, &MainWindow::doActionPCLModelOutlierRemoval);//模型滤波器
connect(m_UI->actionGaussianKernel, &QAction::triggered, this, &MainWindow::doActionPCLGaussianKernel);//GaussianKernel高斯滤波器
(4)生成
2.PassThrough直通滤波器
(1)实现代码
// 直通滤波器
void MainWindow::doActionPCLPassThrough()
{
if (getSelectedEntities().size() != 1)
{
ccLog::Print(QStringLiteral("只能选择一个点云实体"));
return;
}
ccHObject* entity = getSelectedEntities()[0];
ccPointCloud* ccCloud = ccHObjectCaster::ToPointCloud(entity);
// ---------------------------读取数据到PCL----------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(ccCloud->size());
for (int i = 0; i < cloud->size(); ++i)
{
const CCVector3* point = ccCloud->getPoint(i);
cloud->points[i].x = point->x;
cloud->points[i].y = point->y;
cloud->points[i].z = point->z;
}
// -----------------------------对话框---------------------------------------
//float radius = QInputDialog::getDouble(this, QStringLiteral("参数设置"), QStringLiteral("搜索半径: "), 0.1, 0, 100, 4);
// ----------------------------直通滤波器--------------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PassThrough<pcl::PointXYZ> us;
us.setInputCloud(cloud);
us.setFilterFieldName("z");//设置滤波所需字段z
us.setFilterLimits(-0.1,1);//设置z字段过滤范围
us.setFilterLimitsNegative(true);//默认false,保留范围内的点云;true,保存范围外的点云
us.filter(*filtered);
// ------------------------PCL->CloudCompare--------------------------------
if (!filtered->empty())
{
ccPointCloud* newPointCloud = new ccPointCloud(QString("PassThrough"));
for (int i = 0; i < filtered->size(); ++i)
{
double x = filtered->points[i].x;
double y = filtered->points[i].y;
double z = filtered->points[i].z;
newPointCloud->addPoint(CCVector3(x, y, z));
}
newPointCloud->setRGBColor(ccColor::Rgba(255, 255, 255, 255));
newPointCloud->showColors(true);
if (ccCloud->getParent())
{
ccCloud->getParent()->addChild(newPointCloud);
}
ccCloud->setEnabled(false);
addToDB(newPointCloud);
refreshAll();
updateUI();
}
else
{
ccCloud->setEnabled(true);
// Display a warning message in the console
dispToConsole("Warning: example shouldn't be used as is", ccMainAppInterface::WRN_CONSOLE_MESSAGE);
}
}
(2)滤波结果
①滤波前
②滤波后
3.StatisticalOutlierRemoval统计滤波器
(1)实现代码
// 统计滤波器
void MainWindow::doActionPCLStatisticalOutlierRemoval()
{
if (getSelectedEntities().size() != 1)
{
ccLog::Print(QStringLiteral("只能选择一个点云实体"));
return;
}
ccHObject* entity = getSelectedEntities()[0];
ccPointCloud* ccCloud = ccHObjectCaster::ToPointCloud(entity);
// ---------------------------读取数据到PCL----------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(ccCloud->size());
for (int i = 0; i < cloud->size(); ++i)
{
const CCVector3* point = ccCloud->getPoint(i);
cloud->points[i].x = point->x;
cloud->points[i].y = point->y;
cloud->points[i].z = point->z;
}
// -----------------------------对话框---------------------------------------
//float radius = QInputDialog::getDouble(this, QStringLiteral("参数设置"), QStringLiteral("搜索半径: "), 0.1, 0, 100, 4);
// ----------------------------统计滤波器--------------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered(new pcl::PointCloud<pcl::PointXYZ>);
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> us;
us.setInputCloud(cloud); //设置待滤波点云
us.setMeanK(50); //设置查询点近邻点的个数
us.setStddevMulThresh(1.0); //设置标准差乘数,来计算是否为离群点的阈值
//sor.setNegative(true); //默认false,保存内点;true,保存滤掉的离群点
us.filter(*filtered);
// ------------------------PCL->CloudCompare--------------------------------
if (!filtered->empty())
{
ccPointCloud* newPointCloud = new ccPointCloud(QString("StatisticalOutlierRemoval"));
for (int i = 0; i < filtered->size(); ++i)
{
double x = filtered->points[i].x;
double y = filtered->points[i].y;
double z = filtered->points[i].z;
newPointCloud->addPoint(CCVector3(x, y, z));
}
newPointCloud->setRGBColor(ccColor::Rgba(255, 255, 255, 255));
newPointCloud->showColors(true);
if (ccCloud->getParent())
{
ccCloud->getParent()->addChild(newPointCloud);
}
ccCloud->setEnabled(false);
addToDB(newPointCloud);
refreshAll();
updateUI();
}
else
{
ccCloud->setEnabled(true);
// Display a warning message in the console
dispToConsole("Warning: example shouldn't be used as is", ccMainAppInterface::WRN_CONSOLE_MESSAGE);
}
}
(2)滤波结果
①滤波前
②滤波后
4.RadiusOutlierRemoval半径滤波器
(1)实现代码
// 半径滤波器
void MainWindow::doActionPCLRadiusOutlierRemoval()
{
if (getSelectedEntities().size() != 1)
{
ccLog::Print(QStringLiteral("只能选择一个点云实体"));
return;
}
ccHObject* entity = getSelectedEntities()[0];
ccPointCloud* ccCloud = ccHObjectCaster::ToPointCloud(entity);
// ---------------------------读取数据到PCL----------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(ccCloud->size());
for (int i = 0; i < cloud->size(); ++i)
{
const CCVector3* point = ccCloud->getPoint(i);
cloud->points[i].x = point->x;
cloud->points[i].y = point->y;
cloud->points[i].z = point->z;
}
// -----------------------------对话框---------------------------------------
float radius = QInputDialog::getDouble(this, QStringLiteral("参数设置"), QStringLiteral("半径: "), 0.05, 0, 100, 4);
// ----------------------------半径滤波器--------------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered(new pcl::PointCloud<pcl::PointXYZ>);
pcl::RadiusOutlierRemoval<pcl::PointXYZ> us;
us.setInputCloud(cloud); //设置待滤波点云
us.setRadiusSearch(radius); //设置查询点的半径范围
us.setMinNeighborsInRadius(5); //设置判断是否为离群点的阈值,即半径内至少包括的点数
us.setNegative(true); //默认false,保存内点;true,保存滤掉的外点
us.filter(*filtered);
// ------------------------PCL->CloudCompare--------------------------------
if (!filtered->empty())
{
ccPointCloud* newPointCloud = new ccPointCloud(QString("RadiusOutlierRemoval"));
for (int i = 0; i < filtered->size(); ++i)
{
double x = filtered->points[i].x;
double y = filtered->points[i].y;
double z = filtered->points[i].z;
newPointCloud->addPoint(CCVector3(x, y, z));
}
newPointCloud->setRGBColor(ccColor::Rgba(255, 255, 255, 255));
newPointCloud->showColors(true);
if (ccCloud->getParent())
{
ccCloud->getParent()->addChild(newPointCloud);
}
ccCloud->setEnabled(false);
addToDB(newPointCloud);
refreshAll();
updateUI();
}
else
{
ccCloud->setEnabled(true);
// Display a warning message in the console
dispToConsole("Warning: example shouldn't be used as is", ccMainAppInterface::WRN_CONSOLE_MESSAGE);
}
}
(2)滤波结果
①滤波前
②滤波后
5.ConditionRemoval条件滤波器
(1)实现代码
// 条件滤波器
void MainWindow::doActionPCLConditionRemoval()
{
if (getSelectedEntities().size() != 1)
{
ccLog::Print(QStringLiteral("只能选择一个点云实体"));
return;
}
ccHObject* entity = getSelectedEntities()[0];
ccPointCloud* ccCloud = ccHObjectCaster::ToPointCloud(entity);
// ---------------------------读取数据到PCL----------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(ccCloud->size());
for (int i = 0; i < cloud->size(); ++i)
{
const CCVector3* point = ccCloud->getPoint(i);
cloud->points[i].x = point->x;
cloud->points[i].y = point->y;
cloud->points[i].z = point->z;
}
// -----------------------------对话框---------------------------------------
//float radius = QInputDialog::getDouble(this, QStringLiteral("参数设置"), QStringLiteral("搜索半径: "), 0.1, 0, 100, 4);
// ----------------------------条件滤波器--------------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered(new pcl::PointCloud<pcl::PointXYZ>);
/*创建条件限定下的滤波器*/
pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_cond(new pcl::ConditionAnd<pcl::PointXYZ>());//创建条件定义对象range_cond
//为条件定义对象添加比较算子
range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
pcl::FieldComparison<pcl::PointXYZ>("x", pcl::ComparisonOps::GT, -0.1)));//添加在x字段上大于 -0.1 的比较算子
range_cond->addComparison(pcl::FieldComparison<pcl::PointXYZ>::ConstPtr(new
pcl::FieldComparison<pcl::PointXYZ>("x", pcl::ComparisonOps::LT, 1.0)));//添加在x字段上小于 1.0 的比较算子
pcl::ConditionalRemoval<pcl::PointXYZ> us; //创建滤波器对象
us.setCondition(range_cond); //用条件定义对象初始化
us.setInputCloud(cloud); //设置待滤波点云
us.filter(*filtered);
// ------------------------PCL->CloudCompare--------------------------------
if (!filtered->empty())
{
ccPointCloud* newPointCloud = new ccPointCloud(QString("ConditionRemoval"));
for (int i = 0; i < filtered->size(); ++i)
{
double x = filtered->points[i].x;
double y = filtered->points[i].y;
double z = filtered->points[i].z;
newPointCloud->addPoint(CCVector3(x, y, z));
}
newPointCloud->setRGBColor(ccColor::Rgba(255, 255, 255, 255));
newPointCloud->showColors(true);
if (ccCloud->getParent())
{
ccCloud->getParent()->addChild(newPointCloud);
}
ccCloud->setEnabled(false);
addToDB(newPointCloud);
refreshAll();
updateUI();
}
else
{
ccCloud->setEnabled(true);
// Display a warning message in the console
dispToConsole("Warning: example shouldn't be used as is", ccMainAppInterface::WRN_CONSOLE_MESSAGE);
}
}
(2)滤波结果
①滤波前
②滤波后
6.ProjectInliers投影滤波器
(1)实现代码
// 投影滤波器
void MainWindow::doActionPCLProjectInliers()
{
if (getSelectedEntities().size() != 1)
{
ccLog::Print(QStringLiteral("只能选择一个点云实体"));
return;
}
ccHObject* entity = getSelectedEntities()[0];
ccPointCloud* ccCloud = ccHObjectCaster::ToPointCloud(entity);
// ---------------------------读取数据到PCL----------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(ccCloud->size());
for (int i = 0; i < cloud->size(); ++i)
{
const CCVector3* point = ccCloud->getPoint(i);
cloud->points[i].x = point->x;
cloud->points[i].y = point->y;
cloud->points[i].z = point->z;
}
// -----------------------------对话框---------------------------------------
float radius = QInputDialog::getDouble(this, QStringLiteral("参数设置"), QStringLiteral("搜索半径: "), 0.1, 0, 100, 4);
// ----------------------------投影滤波器--------------------------------------
//创建 x+y+z=0 平面
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
coefficients->values.resize(4); //设置模型系数的大小
coefficients->values[0] = 1.0; //x系数
coefficients->values[1] = 1.0; //y系数
coefficients->values[2] = 1.0; //z系数
coefficients->values[3] = 0.0; //常数项
//投影滤波
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered(new pcl::PointCloud<pcl::PointXYZ>);
pcl::ProjectInliers<pcl::PointXYZ> us;
us.setModelType(pcl::SACMODEL_PLANE); //设置对象对应的投影模型
us.setInputCloud(cloud); //设置输入点云
us.setModelCoefficients(coefficients);//设置模型对应的系数
us.filter(*filtered);
// ------------------------PCL->CloudCompare--------------------------------
if (!filtered->empty())
{
ccPointCloud* newPointCloud = new ccPointCloud(QString("ProjectInliers"));
for (int i = 0; i < filtered->size(); ++i)
{
double x = filtered->points[i].x;
double y = filtered->points[i].y;
double z = filtered->points[i].z;
newPointCloud->addPoint(CCVector3(x, y, z));
}
newPointCloud->setRGBColor(ccColor::Rgba(255, 255, 255, 255));
newPointCloud->showColors(true);
if (ccCloud->getParent())
{
ccCloud->getParent()->addChild(newPointCloud);
}
ccCloud->setEnabled(false);
addToDB(newPointCloud);
refreshAll();
updateUI();
}
else
{
ccCloud->setEnabled(true);
// Display a warning message in the console
dispToConsole("Warning: example shouldn't be used as is", ccMainAppInterface::WRN_CONSOLE_MESSAGE);
}
}
(2)滤波结果
①滤波前
②滤波后
7.ModelOutlierRemoval模型滤波器
(1)实现代码
// 模型滤波器
void MainWindow::doActionPCLModelOutlierRemoval()
{
if (getSelectedEntities().size() != 1)
{
ccLog::Print(QStringLiteral("只能选择一个点云实体"));
return;
}
ccHObject* entity = getSelectedEntities()[0];
ccPointCloud* ccCloud = ccHObjectCaster::ToPointCloud(entity);
// ---------------------------读取数据到PCL----------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(ccCloud->size());
for (int i = 0; i < cloud->size(); ++i)
{
const CCVector3* point = ccCloud->getPoint(i);
cloud->points[i].x = point->x;
cloud->points[i].y = point->y;
cloud->points[i].z = point->z;
}
// -----------------------------对话框---------------------------------------
//float radius = QInputDialog::getDouble(this, QStringLiteral("参数设置"), QStringLiteral("搜索半径: "), 0.1, 0, 100, 4);
// ----------------------------模型滤波器--------------------------------------
//设置模型系数
pcl::ModelCoefficients model_coeff;
model_coeff.values.resize(4);
model_coeff.values[0] = 1.0;
model_coeff.values[1] = 1.0;
model_coeff.values[2] = 1.0;
model_coeff.values[3] = 0.0;
///模型滤波
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered(new pcl::PointCloud<pcl::PointXYZ>);
pcl::ModelOutlierRemoval<pcl::PointXYZ> us;
us.setModelCoefficients(model_coeff); //为模型对象添加模型系数
us.setThreshold(0.1); //设置判断是否为模型内点的阈值
us.setModelType(pcl::SACMODEL_PLANE); //设置模型类别
us.setInputCloud(cloud); //输入待滤波点云
us.setNegative(true); //默认false,保存内点;true,保存滤掉的外点
us.filter(*filtered);
// ------------------------PCL->CloudCompare--------------------------------
if (!filtered->empty())
{
ccPointCloud* newPointCloud = new ccPointCloud(QString("ModelOutlierRemoval"));
for (int i = 0; i < filtered->size(); ++i)
{
double x = filtered->points[i].x;
double y = filtered->points[i].y;
double z = filtered->points[i].z;
newPointCloud->addPoint(CCVector3(x, y, z));
}
newPointCloud->setRGBColor(ccColor::Rgba(255, 255, 255, 255));
newPointCloud->showColors(true);
if (ccCloud->getParent())
{
ccCloud->getParent()->addChild(newPointCloud);
}
ccCloud->setEnabled(false);
addToDB(newPointCloud);
refreshAll();
updateUI();
}
else
{
ccCloud->setEnabled(true);
// Display a warning message in the console
dispToConsole("Warning: example shouldn't be used as is", ccMainAppInterface::WRN_CONSOLE_MESSAGE);
}
}
(2)滤波结果
①滤波前
②滤波后
8.GaussianKernel高斯滤波器
(1)实现代码
// 高斯滤波器
void MainWindow::doActionPCLGaussianKernel()
{
if (getSelectedEntities().size() != 1)
{
ccLog::Print(QStringLiteral("只能选择一个点云实体"));
return;
}
ccHObject* entity = getSelectedEntities()[0];
ccPointCloud* ccCloud = ccHObjectCaster::ToPointCloud(entity);
// ---------------------------读取数据到PCL----------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->resize(ccCloud->size());
for (int i = 0; i < cloud->size(); ++i)
{
const CCVector3* point = ccCloud->getPoint(i);
cloud->points[i].x = point->x;
cloud->points[i].y = point->y;
cloud->points[i].z = point->z;
}
// -----------------------------对话框---------------------------------------
float radius = QInputDialog::getDouble(this, QStringLiteral("参数设置"), QStringLiteral("搜索半径: "), 0.1, 0, 100, 4);
// ----------------------------高斯滤波器--------------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered(new pcl::PointCloud<pcl::PointXYZ>);
//pcl::BilateralFilter<pcl::PointXYZ> us;
//-----------基于高斯核函数的卷积滤波实现------------------------
pcl::filters::GaussianKernel<pcl::PointXYZ, pcl::PointXYZ> kernel;
kernel.setSigma(4);//高斯函数的标准方差,决定函数的宽度
kernel.setThresholdRelativeToSigma(4);//设置相对Sigma参数的距离阈值
kernel.setThreshold(0.05);//设置距离阈值,若点间距离大于阈值则不予考虑
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
tree->setInputCloud(cloud);
//---------设置Convolution 相关参数---------------------------
pcl::filters::Convolution3D<pcl::PointXYZ, pcl::PointXYZ, pcl::filters::GaussianKernel<pcl::PointXYZ, pcl::PointXYZ>> convolution;
convolution.setKernel(kernel);//设置卷积核
convolution.setInputCloud(cloud);
convolution.setNumberOfThreads(8);
convolution.setSearchMethod(tree);
convolution.setRadiusSearch(radius);
convolution.convolve(*filtered);
// ------------------------PCL->CloudCompare--------------------------------
if (!filtered->empty())
{
ccPointCloud* newPointCloud = new ccPointCloud(QString("GaussianKernel"));
for (int i = 0; i < filtered->size(); ++i)
{
double x = filtered->points[i].x;
double y = filtered->points[i].y;
double z = filtered->points[i].z;
newPointCloud->addPoint(CCVector3(x, y, z));
}
newPointCloud->setRGBColor(ccColor::Rgba(255, 255, 255, 255));
newPointCloud->showColors(true);
if (ccCloud->getParent())
{
ccCloud->getParent()->addChild(newPointCloud);
}
ccCloud->setEnabled(false);
addToDB(newPointCloud);
refreshAll();
updateUI();
}
else
{
ccCloud->setEnabled(true);
// Display a warning message in the console
dispToConsole("Warning: example shouldn't be used as is", ccMainAppInterface::WRN_CONSOLE_MESSAGE);
}
}
(2)滤波结果
①滤波前
②滤波后
文章来源:https://www.toymoban.com/news/detail-449519.html
参考资料:
[1] 来吧!我在未来等你!. CloudCompare二次开发之如何配置PCL点云库?; 2023-05-14 [accessed 2023-05-15].
[2] 悠缘之空. PCL函数库摘要——点云滤波; 2021-05-30 [accessed 2023-05-15].
[3] 孙 悟 空. PCL:点云滤波汇总:算法原理 + 代码实现; 2021-03-08 [accessed 2023-05-15].
[4] 学习OpenCV. PCL点云滤波器总结; 2022-03-03 [accessed 2023-05-15].
[5] 学习OpenCV. PCL点云处理_点云滤波(3); 2022-03-03 [accessed 2023-05-15].
[6] 点云侠. PCL 高斯滤波; 2021-02-27 [accessed 2023-05-15].文章来源地址https://www.toymoban.com/news/detail-449519.html
到了这里,关于CloudCompare二次开发之如何通过PCL进行点云滤波?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!