一、点云格式
问题出现于示例代码的voxel_grid和extract_indices中。
从GitHub下载的部分代码不能编译通过,对pcl点云格式pcl::PCLPointCloud2::Ptr进行学习和理解。源代码是sensor_msgs::PointCloud2,显然是运行于ROS里的。另外,涉及到点云数据格式的转换。
体素滤波可运行代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
int main (int argc, char** argv)
{
//sensor_msgs::PointCloud2::Ptr cloud (new sensor_msgs::PointCloud2 ());
//sensor_msgs::PointCloud2::Ptr cloud_filtered (new sensor_msgs::PointCloud2 ());
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);
// 填入点云数据
pcl::PCDReader reader;
// 把路径改为自己存放文件的路径
reader.read ("../table_scene_lms400.pcd", *cloud);
std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height
<< " data points (" << pcl::getFieldsList (*cloud) << ").";
// 创建滤波器对象
//pcl::VoxelGrid<sensor_msgs::PointCloud2> sor;
pcl::VoxelGrid<pcl::PointXYZ> sor;
sor.setInputCloud (cloud);
sor.setLeafSize (0.01f, 0.01f, 0.01f);
sor.filter (*cloud_filtered);
std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height
<< " data points (" << pcl::getFieldsList (*cloud_filtered) << ").";
pcl::PCDWriter writer;
//writer.write ("2f.pcd", *cloud_filtered, Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), false);
writer.write ("2f.pcd", *cloud_filtered, false);
return (0);
}
索引滤波可运行代码
#include <iostream>
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/extract_indices.h>
int main (int argc, char** argv)
{
pcl::PCLPointCloud2::Ptr cloud_blob (new pcl::PCLPointCloud2), cloud_filtered_blob (new pcl::PCLPointCloud2);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>), cloud_p (new pcl::PointCloud<pcl::PointXYZ>), cloud_f (new pcl::PointCloud<pcl::PointXYZ>);
// 填入点云数据
pcl::PCDReader reader;
reader.read ("../table_scene_lms400.pcd", *cloud_blob);
std::cerr << "PointCloud before filtering: " << cloud_blob->width * cloud_blob->height << " data points." << std::endl;
//创建滤波器对象:使用叶大小为1cm的下采样
pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
sor.setInputCloud (cloud_blob);
sor.setLeafSize (0.01f, 0.01f, 0.01f);
sor.filter (*cloud_filtered_blob);
// 转化为模板点云
pcl::fromPCLPointCloud2 (*cloud_filtered_blob, *cloud_filtered);
std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height << " data points." << std::endl;
// 将下采样后的数据存入磁盘
pcl::PCDWriter writer;
writer.write<pcl::PointXYZ> ("../table_scene_lms400_downsampled.pcd", *cloud_filtered, false);
pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients ());
pcl::PointIndices::Ptr inliers (new pcl::PointIndices ());
// 创建分割对象
pcl::SACSegmentation<pcl::PointXYZ> seg;//创建分割对象
// Optional
seg.setOptimizeCoefficients (true);//设置对估计模型参数进行优化处理
// Mandatory
seg.setModelType (pcl::SACMODEL_PLANE);//设置分割模型类别
seg.setMethodType (pcl::SAC_RANSAC);//设置用哪个随机参数估计方法
seg.setMaxIterations (1000);//设置最大迭代次数
seg.setDistanceThreshold (0.01);//判断是否为模型内点的距离阀值
// 创建滤波器对象
pcl::ExtractIndices<pcl::PointXYZ> extract;
int i = 0, nr_points = (int) cloud_filtered->size ();
//当还有30%原始点云数据时
while (cloud_filtered->size () > 0.3 * nr_points)
{
// 从余下的点云中分割最大平面组成部分
seg.setInputCloud (cloud_filtered);
seg.segment (*inliers, *coefficients); //inliers为分割后的索引
std::cout<<"THIS SEG POINTS: "<<inliers->indices.size()<<std::endl;
if (inliers->indices.size () == 0)
{
std::cerr << "Could not estimate a planar model for the given dataset." << std::endl;
break;
}
// 分离内层
extract.setInputCloud (cloud_filtered);
extract.setIndices (inliers); //提取的点云索引inliers中的点
extract.setNegative (false); //提取范围内的点,所以为false
extract.filter (*cloud_p);
std::cerr << "PointCloud representing the planar component: " << cloud_p->width * cloud_p->height << " data points." << std::endl;
std::stringstream ss;
ss << "../table_scene_lms400_plane_" << i << ".pcd";
writer.write<pcl::PointXYZ> (ss.str (), *cloud_p, false);
// 创建滤波器对象
extract.setNegative (true); //提取范围外的点
extract.filter (*cloud_f);
cloud_filtered.swap (cloud_f); //交换,所以第二次的点云会与第一次不会有交集
i++;
}
return (0);
}
参考链接
pcl::PCLPointCloud2::Ptr 和 pcl::PointCloud<pcl::PointXYZ>数据结构区别:
见参考链接: PCL中点云数据格式之间的转化
二、半径滤波
这个示例的运行方式不一样,如果只在终端输入./remove_outliers ,会提示:please specify command line arg ‘-r’ or ‘-c’
正确输入指令为:
./remove_outliers -r
可以调整代码outrem.setRadiusSearch(10)括号中的值,观察滤波差异。
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/radius_outlier_removal.h>
#include <pcl/filters/conditional_removal.h>
int main (int argc, char** argv)
{
if (argc != 2)
{
std::cerr << "please specify command line arg '-r' or '-c'" << std::endl;
exit(0);
}
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);
// 填入点云数据
cloud->width = 5;
cloud->height = 1;
cloud->points.resize (cloud->width * cloud->height);
for (size_t i = 0; i < cloud->points.size (); ++i)
{
cloud->points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
cloud->points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
cloud->points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
}
if (strcmp(argv[1], "-r") == 0){
pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
// 创建滤波器
outrem.setInputCloud(cloud);
outrem.setRadiusSearch(10);
outrem.setMinNeighborsInRadius (2);
// 应用滤波器
outrem.filter (*cloud_filtered);
}
else if (strcmp(argv[1], "-c") == 0){
// 创建环境
pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_cond (new
pcl::ConditionAnd<pcl::PointXYZ> ());
range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::GT, 0.0)));
range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::LT, 0.01)));
// 创建滤波器
//pcl::ConditionalRemoval<pcl::PointXYZ> condrem (range_cond);
pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
condrem.setCondition(range_cond);
condrem.setInputCloud (cloud);
condrem.setKeepOrganized(true);
// 应用滤波器
condrem.filter (*cloud_filtered);
}
else{
std::cerr << "please specify command line arg '-r' or '-c'" << std::endl;
exit(0);
}
std::cerr << "Cloud before filtering: " << std::endl;
for (size_t i = 0; i < cloud->points.size (); ++i)
std::cerr << " " << cloud->points[i].x << " "
<< cloud->points[i].y << " "
<< cloud->points[i].z << std::endl;
// 显示滤波后的点云
std::cerr << "Cloud after filtering: " << std::endl;
for (size_t i = 0; i < cloud_filtered->points.size (); ++i)
std::cerr << " " << cloud_filtered->points[i].x << " "
<< cloud_filtered->points[i].y << " "
<< cloud_filtered->points[i].z << std::endl;
return (0);
}
报错代码:
pcl::ConditionalRemoval<pcl::PointXYZ> condrem(range_cond);
解决方法:
替换成以下两行,应该是函数定义更新了。
pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
condrem.setCondition(range_cond);