环境:Win10+ VS2019
参考文章:使用CSF对kitti的点云数据过滤出地面点云,结合PCL使用,C++实现
下载代码后,新建build文件夹
打开CMake-gui
点击Configure, 出现红色的设置提醒,好像没啥好设置的,再点击Configure,Generate
按照该博主的步骤,打开CSF.sln,右键ALL_BUILD,点击生成。
出现报错:2>cl : 命令行 error D8021: 无效的数值参数“/Werror”
命令行 error D8021: 无效的数值参数“/Wextra”
百度有博主说是python文件夹下的setup.py文件里面有设置了这个参数,但查找该代码下的内容,并未找到。
按照错误提示找到D:\Program Files (x86)\CSF\CSF-master\src\CMakeLists.txt,
删除target_compile_options里面的内容,只剩下(CSF PRIVATE -Wall ),保存。
重新打开CSF.sln,右键ALL_BUILD,点击生成。
虽然有很多报错,但是显示生成成功。并生成了lib文件。
按照参考文章的步骤配置环境,博主给的代码如下:
#include
#include
#include //PCL对各种格式的点的支持头文件
#include //PCL的PCD格式文件的输入输出头文件
#include //点云查看窗口头文件
#include //滤波相关头文件
#include
#include
#include "CSF.h"
using namespace std;
void clothSimulationFilter(const vector< csf::Point >& pc,vector<int> &groundIndexes,vector<int> & offGroundIndexes)
{
//step 1 read point cloud
CSF csf;
csf.setPointCloud(pc);// or csf.readPointsFromFile(pointClouds_filepath);
//pc can be vector< csf::Point > or PointCloud defined in point_cloud.h
//step 2 parameter settings
//Among these paramters:
//time_step interations class_threshold can remain as defualt in most cases.
csf.params.bSloopSmooth = false;
csf.params.cloth_resolution = 0.5;
csf.params.rigidness = 3;
csf.params.time_step = 0.65;
csf.params.class_threshold = 0.5;
csf.params.interations = 500;
//step 3 do filtering
//result stores the index of ground points or non-ground points in the original point cloud
csf.do_filtering(groundIndexes, offGroundIndexes);
//csf.do_filtering(groundIndexes, offGroundIndexes,true);
//if the third parameter is set as true, then a file named "cloth_nodes.txt" will be created,
//it respresents the cloth nodes.By default, it is set as false
}
void addPointCloud(const vector<int>& index_vec, const pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_filtered)
{
auto& points = cloud_filtered->points;
const auto& pointclouds = cloud->points;
for_each(index_vec.begin(), index_vec.end(), [&](const auto& index) {
pcl::PointXYZI pc;
pc.x = pointclouds[index].x;
pc.y = pointclouds[index].y;
pc.z = pointclouds[index].z;
pc.intensity = pointclouds[index].intensity;
points.push_back(pc);
});
cloud_filtered->height = 1;
cloud_filtered->width = cloud_filtered->points.size();
}
int main()
{
string pcd_path = "E:\\kitti\\data_object_velodyne\\testing\\pcd\\000060.pcd";
// Generate pointcloud data,新建指针cloud存放点云
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>);
if (pcl::io::loadPCDFile<pcl::PointXYZI>(pcd_path, *cloud) == -1)//打开点云文件。
{
PCL_ERROR("Couldn't read that pcd file\n");
return(-1);
}
vector<csf::Point> pc;
const auto& pointclouds = cloud->points;
pc.resize(cloud->size());
transform(pointclouds.begin(), pointclouds.end(), pc.begin(), [&](const auto& p)->csf::Point {
csf::Point pp;
pp.x = p.x;
pp.y = p.y;
pp.z = p.z;
return pp;
});
std::vector<int> groundIndexes, offGroundIndexes;
clothSimulationFilter(pc, groundIndexes, offGroundIndexes);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZI>);
addPointCloud(groundIndexes, cloud,cloud_filtered);
pcl::PCDWriter writer;
writer.write<pcl::PointXYZI>("groundPointCloud.pcd", *cloud_filtered, false);
cloud_filtered->points.clear();
addPointCloud(offGroundIndexes, cloud,cloud_filtered);
writer.write<pcl::PointXYZI>("nonGroundPointCloud.pcd", *cloud_filtered, false);
//pcl::visualization::CloudViewer viewer("this is a point cloud viewer haha!!");
//viewer.showCloud(cloud_filtered);
//while (!viewer.wasStopped())
//{
//}
return 0;
}
用点云库PCL从入门到精通\第十二章\9Identifying ground returns using Progressive Morphological Filter segmentation\Source\samp11-utm.pcd 测试一下
源点云:
分割后:蓝色为地面点云
分割自己的数据:桥墩部分,有一些被分成地面了
参考链接:PCL滤波—使用索引滤波器过滤地面
作者给出的代码
//索引滤波
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int
main(int argc, char** argv)
{
//sensor_msgs::PointCloud2::Ptr cloud_blob (new sensor_msgs::PointCloud2), cloud_filtered_blob (new sensor_msgs::PointCloud2);
pcl::PCLPointCloud2::Ptr cloud_blob(new pcl::PCLPointCloud2);
pcl::PCLPointCloud2::Ptr 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("C:\\Users\\oh_clm\\Desktop\\桥梁\\桥梁点云文件\\7\\test.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); //执行采样保存数据cloud_filtered_blob
//统计滤波器,删除离群点
pcl::StatisticalOutlierRemoval<pcl::PCLPointCloud2> Static; //创建滤波器对象
Static.setInputCloud(cloud_filtered_blob); //设置待滤波的点云
Static.setMeanK(50); //设置在进行统计时考虑查询点临近点数
Static.setStddevMulThresh(0.5); //设置判断是否为离群点的阀值
Static.filter(*cloud_filtered_blob); //存储
// 转化为模板点云
//pcl::fromROSMsg(*cloud_filtered_blob, *cloud_filtered);
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("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; //创建分割对象
//可选
seg.setOptimizeCoefficients(true); //设置对估计的模型参数进行优化处理
//必选
seg.setModelType(pcl::SACMODEL_PLANE); //设置分割模型类别
seg.setMethodType(pcl::SAC_RANSAC); //设置用哪个随机参数估计方法
seg.setMaxIterations(100); //设置最大迭代次数
seg.setDistanceThreshold(0.15); //设置判断是否为模型内点的距离阈值
// 创建滤波器对象
pcl::ExtractIndices<pcl::PointXYZ> extract;
int i = 0, nr_points = (int)cloud_filtered->points.size();
//为了处理点云中包含多个模型,在一个循环中执行该过程,
//并在每次模型被提取后,我们保存剩余的点,进行迭代;
//模型内点通过分割过程获取;
//当还有60%原始点云数据时退出循环
while (cloud_filtered->points.size() > 0.6 * nr_points)
{
// 从余下的点云中分割最大平面组成部分
seg.setInputCloud(cloud_filtered);
seg.segment(*inliers, *coefficients);
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);
extract.setNegative(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 << "C:\\Users\\oh_clm\\Desktop\\桥梁\\桥梁点云文件\\7\\table_scene_lms400_plane_" << i << ".pcd";
// writer.write(ss.str(), *cloud_p, false);
// 创建滤波器对象
extract.setNegative(true);
extract.filter(*cloud_f);
cloud_filtered.swap(cloud_f);
i++;
}
cout << "迭代次数:" << i << endl;
pcl::visualization::CloudViewer viewer("Cloud Viewer"); //创建viewer对象
viewer.showCloud(cloud_f);
// viewer.runOnVisualizationThreadOnce(viewerOneOff);
while (!viewer.wasStopped())
{
//在此处可以添加其他处理
}
return (0);
}
参考文章:PCL 渐进式形态学滤波
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int
main(int argc, char** argv)
{
// --------------------------------加载点云数据----------------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PCDReader reader;
if (reader.read("C:\\Users\\oh_clm\\Desktop\\桥梁\\桥梁点云文件\\7\\test.pcd", *cloud) < 0)
{
PCL_ERROR("Could not read file\n");
return (-1);
}
printf("从点云数据中加载 %lld 个点\n", cloud->points.size());
// ------------------------------------渐进式形态学滤波---------------------------------------
pcl::StopWatch time;
pcl::ProgressiveMorphologicalFilter<pcl::PointXYZ> pmf;
pmf.setInputCloud(cloud); // 待处理点云
pmf.setMaxWindowSize(20); // 最大窗口大小
pmf.setSlope(1.0f); // 地形坡度参数
pmf.setInitialDistance(0.5f); // 初始高差阈值
pmf.setMaxDistance(3.0f); // 最大高差阈值
/*可选参数*/
pmf.setCellSize(3); // 设置窗口的大小
pmf.setBase(3); //设置计算渐进窗口大小时使用的基数
pmf.setExponential(true);//设置是否以指数方式增加窗口大小
pcl::PointIndicesPtr ground(new pcl::PointIndices);
pmf.extract(ground->indices); // 获取地面点的索引
cout << "渐进式形态学滤波算法运行时间:" << time.getTimeSeconds() << "秒" << endl;
// ----------------------------------------提取地面-------------------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr ground_cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::ExtractIndices<pcl::PointXYZ> extract;
extract.setInputCloud(cloud);
extract.setIndices(ground);
extract.filter(*ground_cloud);
printf("地面点的个数为: %lld\n", ground_cloud->size());
pcl::PCDWriter writer;
writer.write("C:\\Users\\oh_clm\\Desktop\\桥梁\\桥梁点云文件\\7\\samp11-utm_ground.pcd", *ground_cloud, true); //设置为true,可提高效率
// --------------------------------------提取非地面------------------------------------------
pcl::PointCloud<pcl::PointXYZ>::Ptr non_ground_cloud(new pcl::PointCloud<pcl::PointXYZ>);
extract.setNegative(true);
extract.filter(*non_ground_cloud);
printf("非地面点的个数为: %lld\n", non_ground_cloud->size());
writer.write("C:\\Users\\oh_clm\\Desktop\\桥梁\\桥梁点云文件\\7\\samp11-utm_object.pcd", *non_ground_cloud, true);
// ---------------------------------------可视化---------------------------------------------
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D-viewer"));
viewer->setWindowName("渐进式形态学地面滤波");
viewer->addPointCloud(ground_cloud, pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>(ground_cloud, 255, 0, 0), "ground");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "ground");
pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZ> fildColor(non_ground_cloud, "z"); // 按照z字段进行渲染
viewer->addPointCloud<pcl::PointXYZ>(non_ground_cloud, fildColor, "non_ground");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "non_ground");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, 0.7, "non_ground");// 设置透明度
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(1000));
}
return (0);
}