1.读取点云和打印点云
代码如下:
#include<iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
using namespace std;
using namespace pcl;
int main() {
//1.创建一个保存点云的对象
PointCloud<PointXYZ>::Ptr cloud(new PointCloud<PointXYZ>);
//2.从文件中加载点云
if (io::loadPCDFile<PointXYZ>("E:\\vs\\daima\\PCLpratict\\Projects\\isprs\\isprs\\1.pcd", *cloud) == -1) //* load the file
{
PCL_ERROR("Couldn't read file test_pcd.pcd \n");
return (-1);
}
cout << "Loaded "
<< cloud->width <<" " << cloud->height
<< " data points from test_pcd.pcd with the following fields: "
<< endl;
//3.打印点云
for (size_t i = 0; i < cloud->points.size(); ++i)
cout << " " << cloud->points[i].x
<< " " << cloud->points[i].y
<< " " << cloud->points[i].z << endl;
return 0;
}
2.创建点云
代码如下:
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
using namespace std;
using namespace pcl;
int genwrite() {
PointCloud<PointXYZ> cloud;
//1.创建点云
cloud.width = 10000;
cloud.height = 1;
cloud.is_dense = false;
cloud.points.resize(cloud.width * cloud.height);
for (size_t i = 0; i < cloud.points.size(); ++i)
{
// 坐标范围在[0,1024),正方体内随机取点
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));
}
//2.保持点云数据
io::savePCDFileASCII("test.pcd", cloud);
return 0;
}
int main() {
//创建点云数据
genwrite();
//读取点云数据
PointCloud<PointXYZ>::Ptr cloud(new PointCloud<PointXYZ>);
if (io::loadPCDFile<PointXYZ>("test.pcd", *cloud) == -1)//*打开点云文件
{
PCL_ERROR("Couldn't read file test_pcd.pcd\n");
return(-1);
}
boost::shared_ptr<visualization::PCLVisualizer> viewer(new
visualization::PCLVisualizer("3D Viewer"));//页面名称是3D Viewer
viewer->setBackgroundColor(0, 0, 0);//页面背景是黑色
viewer->addPointCloud<PointXYZ>(cloud, "sample cloud");
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}
生成的点云可以通过鼠标拖动观察不同角度的立体效果,如下图拖动前后的效果:
3.点云的体素网格算法
算法原理可以参考1.open3d处理点云数据的常见方法-CSDN博客。一般当点云数据密度很大时,往往用体素网格稀疏点云数量,既方便计算又能减小计算量。
3.1 体素网格算法的数据处理
代码如下:
#include <iostream>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/voxel_grid.h>
using namespace std;
using namespace pcl;
int main() {
PCLPointCloud2::Ptr cloud(new PCLPointCloud2);
PCLPointCloud2::Ptr cloud_filterd(new PCLPointCloud2);
pcl::PCDReader reader;
reader.read("E:\\vs\\daima\\PCLpratict\\Projects\\isprs\\isprs\\1.pcd", *cloud);
cout << "过滤前的点个数:" << cloud->width * cloud->height <<endl;
cout << "数据类型:" << getFieldsList(*cloud) <<endl;
float leafSize = 0.5f;
// 执行降采样------------------------
pcl::VoxelGrid<PCLPointCloud2> voxel;
// 设置输入点云
voxel.setInputCloud(cloud);
// 设置体素网格的大小
voxel.setLeafSize(leafSize, leafSize, leafSize);
// 执行滤波, 并将结果保存到cloud_filterd
voxel.filter(*cloud_filterd);
cout << "---------------------------------------------" << endl;
cout << "过滤后的点个数:" << cloud_filterd->width * cloud_filterd->height <<endl;
cout << "数据类型:" << getFieldsList(*cloud_filterd) << endl;
PCDWriter writer;
writer.write("E:\\vs\\daima\\PCLpratict\\Projects\\isprs\\isprs\\1_1.pcd", *cloud_filterd);//保存点云数据
return 0;
}
过滤前后的数据量结果如下:
3.2 处理前后的可视化比较
代码如下:
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
// 包含相关头文件
#include <pcl/visualization/pcl_visualizer.h>
typedef pcl::PointXYZ PointT;
using namespace std;
using namespace pcl;
int main() {
cout << "................welcom..................." << endl;
// 读取点云
PointCloud<PointT>::Ptr cloud2(new pcl::PointCloud<PointT>);
io::loadPCDFile("E:\\vs\\daima\\PCLpratict\\Projects\\isprs\\isprs\\1_1.pcd", *cloud2);
// 定义对象
visualization::PCLVisualizer viewer;
//设置背景颜色,默认黑色,可以不设
viewer.setBackgroundColor(100, 100, 100); // rgb
visualization::PointCloudColorHandlerCustom<PointT> red(cloud2, 255, 0, 0); // rgb
// 将点云设置颜色,默认白色
viewer.addPointCloud(cloud2, red, "cloud2");
// --- 显示网格数据 ---
PolygonMesh mesh;
pcl::io::loadPLYFile("read.ply", mesh);
viewer.addPolygonMesh(mesh);
// 开始显示2种方法,任选其一
// 1. 阻塞式
viewer.spin();
system("pause");
return 0;
}
处理前点云数据量是50多万,处理后的数据量是4.9万多,数据量减小到十分之一。处理前后的效果比较如下:
当把体素网格的大小设置为0.8f时,此时点云的数据量还剩2万多,此时的可视化结果如下:
显然,可视化图中点云变得稀疏。所以,我们在用体素网格算法时,要根据实际情况调整网格的大小。
4.直通滤波
原理:参考博客PCL教程-点云滤波之直通滤波器_pcl直通滤波-CSDN博客
直通滤波的作用是过滤掉在指定维度方向上取值不在给定值域内的点。
实现原理如下:
首先,指定一个维度以及该维度下的值域,其次,遍历点云中的每个点,判断该点在指定维度上的取值是否在值域内,删除取值不在值域内的点,最后,遍历结束,留下的点即构成滤波后的点云。直通滤波器简单高效,适用于消除背景等操作。
一般对某一个或多个维度只是对某个区间范围计算点云时,往往用直通滤波去除该范围之外的点云。
代码如下:
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>
using namespace std;
using namespace pcl;
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
// 包含相关头文件
#include <pcl/visualization/pcl_visualizer.h>
typedef pcl::PointXYZ PointT;
int main() {
cout << "................welcom..................." << endl;
// 读取点云
PointCloud<PointT>::Ptr cloud2(new PointCloud<PointT>);
PointCloud<PointXYZ>::Ptr cloud_filtered(new PointCloud<PointXYZ>);
io::loadPCDFile("E:\\vs\\daima\\PCLpratict\\Projects\\isprs\\isprs\\1_1.pcd", *cloud2);
cout << cloud2->width << " " << cloud2->height<< endl;
//直通滤波
PassThrough<pcl::PointXYZ> pass;//创建滤波器对象
pass.setInputCloud(cloud2); //设置待滤波的点云
pass.setFilterFieldName("x"); //设置在x轴方向上进行滤波
pass.setFilterLimits(-50.0, 50.0); //设置滤波范围为-50~50,在范围之外的点会被剪除
//pass.setFilterLimitsNegative (true);//是否反向过滤,默认为false
pass.filter(*cloud_filtered); //开始过滤
cout << "................直通滤波后的点云数量..................." << endl;
cout << cloud_filtered->width << " " << cloud_filtered->height << endl;
//...............................................直通滤波后的可视化.................................................//
// 定义对象
visualization::PCLVisualizer viewer;
//设置背景颜色,默认黑色,可以不设
viewer.setBackgroundColor(100, 100, 100); // rgb
visualization::PointCloudColorHandlerCustom<PointT> red(cloud_filtered, 255, 0, 0); // rgb
// 将点云设置颜色,默认白色
viewer.addPointCloud(cloud_filtered, red, "cloud_filtered");
// --- 显示网格数据 ---
PolygonMesh mesh;
io::loadPLYFile("read.ply", mesh);
viewer.addPolygonMesh(mesh);
// 开始显示2种方法,任选其一
// 1. 阻塞式
viewer.spin();
system("pause");
//...............................................直通滤波后的可视化.................................................//
return 0;
}
滤波前后的数量和可视化效果如下:
数量对比:
直通滤波前后的可视化效果对比:
很明显,x方向是把左图的上边部分去除了。
5.统计滤波
原理:可以参考我写的另一篇博客2.常见的点云数据滤波的方法总结(C++)_点云统计滤波-CSDN博客的第5部分内容,这里主要是代码实现和结果的可视化对比。
代码如下:
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h> //统计滤波器头文件
using namespace std;
using namespace pcl;
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
// 包含相关头文件
#include <pcl/visualization/pcl_visualizer.h>
typedef pcl::PointXYZ PointT;
int main() {
cout << "................welcom..................." << endl;
// 读取点云
PointCloud<PointT>::Ptr cloud2(new PointCloud<PointT>);
PointCloud<PointXYZ>::Ptr cloud_filtered(new PointCloud<PointXYZ>);
io::loadPCDFile("E:\\vs\\daima\\PCLpratict\\Projects\\isprs\\isprs\\1_1.pcd", *cloud2);
cout << cloud2->width << " " << cloud2->height<< endl;
//统计滤波
// 2.创建滤波器,对每个点分析的临近点的个数设置为50 ,并将标准差的倍数设置为1 这意味着如果一
//个点的距离超出了平均距离一个标准差以上,则该点被标记为离群点,并将它移除,存储起来
StatisticalOutlierRemoval<pcl::PointXYZ> sor; //创建滤波器对象
sor.setInputCloud(cloud2); //设置待滤波的点云
sor.setMeanK(50); //设置在进行统计时考虑查询点临近点数
sor.setStddevMulThresh(1.0); //设置判断是否为离群点的阀值
sor.filter(*cloud_filtered); //存储
cout << "................统计滤波后的数据量..................." << endl;
cout << cloud_filtered->width << " " << cloud_filtered->height << endl;
//...............................................统计滤波后的可视化.................................................//
// 定义对象
visualization::PCLVisualizer viewer;
//设置背景颜色,默认黑色,可以不设
viewer.setBackgroundColor(100, 100, 100); // rgb
visualization::PointCloudColorHandlerCustom<PointT> red(cloud_filtered, 255, 0, 0); // rgb
// 将点云设置颜色,默认白色
viewer.addPointCloud(cloud_filtered, red, "cloud_filtered");
// --- 显示网格数据 ---
PolygonMesh mesh;
io::loadPLYFile("read.ply", mesh);
viewer.addPolygonMesh(mesh);
// 开始显示2种方法,任选其一
// 1. 阻塞式
viewer.spin();
system("pause");
//...............................................统计滤波后的可视化.................................................//
return 0;
}
滤波前后的数量和可视化效果如下:
数量对比:
直通滤波前后的可视化效果对比:
下面是将离群点的阀值设为0.5时的效果:
显然,右图中少了一些离散的点,且离群点的阀值越小,去除的点越多。其实是保留的方差范围内的点的个数越少了,导致了去除的点越多,这个大家可以自己思考。
6.半径滤波
原理可以参考我写的另一篇博客2.常见的点云数据滤波的方法总结(C++)_点云统计滤波-CSDN博客,
代码如下:
#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/radius_outlier_removal.h> //半径滤波
using namespace std;
using namespace pcl;
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
// 包含相关头文件
#include <pcl/visualization/pcl_visualizer.h>
typedef pcl::PointXYZ PointT;
int main() {
cout << "................welcom..................." << endl;
// 读取点云
PointCloud<PointT>::Ptr cloud2(new PointCloud<PointT>);
PointCloud<PointXYZ>::Ptr cloud_filtered(new PointCloud<PointXYZ>);
io::loadPCDFile("E:\\vs\\daima\\PCLpratict\\Projects\\isprs\\isprs\\1_1.pcd", *cloud2);
cout << cloud2->width << " " << cloud2->height<< endl;
//半径滤波
RadiusOutlierRemoval<pcl::PointXYZ> sor; // 创建滤波器
sor.setInputCloud(cloud2); //设置输入点云
sor.setRadiusSearch(10); //设置在radius半径的范围内找邻近点
sor.setMinNeighborsInRadius(200); //设置查询点的邻近点集数小于15的删除
sor.setNegative(false);
sor.filter(*cloud_filtered); //执行条件滤波,存储结果到cloud_filte
cout << "................半径滤波后的数据量..................." << endl;
cout << cloud_filtered->width << " " << cloud_filtered->height << endl;
//...............................................统计滤波后的可视化.................................................//
// 定义对象
visualization::PCLVisualizer viewer;
//设置背景颜色,默认黑色,可以不设
viewer.setBackgroundColor(100, 100, 100); // rgb
visualization::PointCloudColorHandlerCustom<PointT> red(cloud_filtered, 255, 0, 0); // rgb
// 将点云设置颜色,默认白色
viewer.addPointCloud(cloud_filtered, red, "cloud_filtered");
// --- 显示网格数据 ---
PolygonMesh mesh;
io::loadPLYFile("read.ply", mesh);
viewer.addPolygonMesh(mesh);
// 开始显示2种方法,任选其一
// 1. 阻塞式
viewer.spin();
system("pause");
//...............................................统计滤波后的可视化.................................................//
return 0;
}
该算法中,主要有两个参数,radius半径越小,删除的点越多;邻近点集数越大,删除的点越多,在这里不用看对比效果了。
其他几种滤波原理和代码都可以看我的另一篇博客2.常见的点云数据滤波的方法总结(C++)_点云统计滤波-CSDN博客。