2.PCL点云数据的处理

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博客

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PCL(Point Cloud Library)是一个开源的点云数据处理库,它提供了一系列用于处理、分析和可视化点云数据算法和工具。下面是PCL点云数据处理的一般原理: 1. 数据获取:从传感器(如激光雷达、RGB-D相机等)获取原始点云数据。 2. 数据处理:对原始点云进行预处理,包括滤波、降采样、去噪等。滤波可以去除离群点或噪声,降采样可以减少点云密度,去噪可以去除传感器噪声。 3. 特征提取:从点云中提取有意义的特征信息,如表面法线、曲率、边缘等。这些特征可以用于后续的分割、配准、识别等任务。 4. 分割:将点云分割成不同的部分,每个部分可以代表一个对象或物体。分割可以基于几何属性(如平面、曲率等)或语义信息(如颜色、纹理等)进行。 5. 配准:将多个点云对齐到同一个坐标系中,以便进行后续的融合或比较。配准可以基于特征匹配、ICP(Iterative Closest Point)等算法进行。 6. 重建:将点云数据转换为更高级的表示形式,如三维网格或体素格。这可以方便后续的形状分析、表面重建等任务。 7. 可视化:将处理后的点云数据进行可视化,以便观察和分析。可视化可以通过三维渲染引擎或点云显示工具进行。 以上是PCL点云数据处理的一般原理,具体的实现过程可以根据具体的应用场景和算法选择进行调整和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值