PCL小笔记

一、常用概念

1,过滤器Filters
消除噪音

2,特征Features
集合点属性:曲面的曲率估计和查询点的法线
通过k-neighborhood计算得到这两个属性作为特征
查找方法:KD-tress、八叉树等

3,关键点Keypoints
可以利用明确标准检测出来的稳定、独特的点,往往较少

4,注册Registration
将点云数据在统一的世界坐标系下进行组合起来

5,Kd-tree
使用FLANN以达到快速进行邻区搜索
FLANN快速最近邻搜索包(Fast_Library_for_Approximate_Nearest_Neighbors)

6,Octree
八叉树通常用于邻区搜索、K邻区搜索、指定半径内搜索等

7,分割Segmentation
一个点云切分成多个片段簇

二、PointT类型

1,PointXYZ,成员变量float x,y,z
每个点云都包含三个信息
points[i]表示第i个点云
points[i].x、points[i].y、points[i].z进行访问

2,PointXYZI,成员变量float x,y,z,intensity

3,PointXYZRGBA,成员变量float x,y,z、uint32_t rgba

4,PointXYZRGB,成员变量float x,y,z,rgb

5,PointXY,成员变量float x,y

6,InterestPoint,成员变量float x,y,z,strength,其中strength表示关键点的强度测量值

7,Normal,成员变量float normal[3], curvature,其中normal结构体表示给定点所在样本曲面上的法线方向以及对应的曲率的测量值
其中法线为normal,曲率为curvature
访问法向量的第一个坐标:points[i].normal[0]

8,PointNormal,成员变量float x,y,z,normal[3],curvature

三、IO模块和类

在这里插入图片描述

四、从PCD文件中读写点云数据

1,自定义点云数据并保存

#include <pcl/io/pcd_io.h> // PCD读写类相关的头文件
#include <pcl/point_types.h> // PCL中支持的点类型的头文件
#include <iostream> // 标准C++库中的输入输出的头文件

int main(int argc,char* argv[])
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	cloud->width = 5;
	cloud->height = 1;
	cloud->is_dense = false;
	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 + 10.f);
		cloud->points[i].y = 1024 * rand() / (RAND_MAX + 10.f);
		cloud->points[i].z = 1024 * rand() / (RAND_MAX + 10.f);
	}

	// 把点云进行保存
	pcl::io::savePCDFileASCII("test_pcd.pcd", *cloud);

	// 输出点云的信息
	for (size_t i = 0; i < cloud->size(); i++) {
		std::cerr << "  " << cloud->points[i].x << "  " << cloud->points[i].y << "  " << cloud->points[i].z << std::endl;
	}

	return 0;
}

在这里插入图片描述
在这里插入图片描述

2,加载自定义点云文件

#include <pcl/io/pcd_io.h> // PCD读写类相关的头文件
#include <pcl/point_types.h> // PCL中支持的点类型的头文件
#include <iostream> // 标准C++库中的输入输出的头文件

int main(int argc,char* argv[])
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();

	// 加载点云
	if (pcl::io::loadPCDFile<pcl::PointXYZ>("test_pcd.pcd",*cloud) == -1) 
	{
		PCL_ERROR("Can't read file test_pcd.pcd \n");
		return -1;
	}

	std::cerr << "Loaded " << cloud->width * cloud->height << " data points" << 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;
	}

	return 0;
}

在这里插入图片描述

3,三个点云进行合并

①点云连接

A+B=C
A,B,C三个点云类型均为pcl::PointXYZ,得到的点云C前几行是A后几行是B

*cloud_c = *cloud_a + *cloud_b; // 把cloud_a和cloud_b连接一起创建cloud_c 后输出

#include <pcl/io/pcd_io.h> // PCD读写类相关的头文件
#include <pcl/point_types.h> // PCL中支持的点类型的头文件
#include <iostream> // 标准C++库中的输入输出的头文件

int main(int agrc,char*agrv[])
{
	// 声明三个点云pcl::PointXYZ类型
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_a = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_b = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_c = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();

	// 创建点云为无需点云
	cloud_a->width = 5;
	cloud_a->height = cloud_b->height = 1;
	cloud_a->points.resize(cloud_a->height * cloud_a->width);


	// 点云连接 a有5个点,b有3个点,合并之后c有8个点
	cloud_b->width = 3;
	cloud_b->points.resize(cloud_b->height * cloud_b->width);
	for (size_t i = 0; i < cloud_a->points.size(); ++i)
	{  
		cloud_a->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud_a->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud_a->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
	}
	for (size_t i = 0; i < cloud_b->points.size(); ++i)
	{   
		cloud_b->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud_b->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud_b->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
	}

	std::cerr << "Cloud A(XYZ): " << std::endl;
	for (size_t i = 0; i < cloud_a->size(); i++) {
		std::cerr << "  " << cloud_a->points[i].x << "  " << cloud_a->points[i].y << "  " << cloud_a->points[i].z << std::endl;
	}
	std::cerr << "Cloud B(XYZ): " << std::endl;
	for (size_t i = 0; i < cloud_b->size(); i++) {
		std::cerr << "  " << cloud_b->points[i].x << "  " << cloud_b->points[i].y << "  " << cloud_b->points[i].z << std::endl;
	}
	*cloud_c = *cloud_a + *cloud_b;//把cloud_a和cloud_b连接一起创建cloud_c  后输出
	std::cerr << "Cloud C(XYZ): " << std::endl;
	for (size_t i = 0; i < cloud_c->points.size(); ++i){
		std::cerr << "    " << cloud_c->points[i].x << " " << cloud_c->points[i].y << " " << cloud_c->points[i].z << " " << std::endl;
	}

	return 0;
}

在这里插入图片描述

②字段间连接

A+B=C
A是pcl::PointXYZ类型,B是pcl::Normal类型,C是pcl::PointNormal类型
将A和B进行字段间连接,也就是C是XYZNormal,A是XYZ,B是Normal,C就是将A和B填到对应的C的位置即可

pcl::concatenateFields(*cloud_a, *cloud_b, *cloud_c);

#include <pcl/io/pcd_io.h> // PCD读写类相关的头文件
#include <pcl/point_types.h> // PCL中支持的点类型的头文件
#include <iostream> // 标准C++库中的输入输出的头文件

int main(int agrc,char*agrv[])
{
	// 声明三个点云pcl::PointXYZ类型
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_a = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	// 声明存储连接时需要的点云类型为pcl::Normal
	pcl::PointCloud<pcl::Normal>::Ptr cloud_b = std::make_shared<pcl::PointCloud<pcl::Normal>>();
	// 声明最终合并的点云类型为pcl::PointNormal
	pcl::PointCloud<pcl::PointNormal>::Ptr cloud_c = std::make_shared<pcl::PointCloud<pcl::PointNormal>>();

	// 创建点云为无序点云
	cloud_a->width = 5;
	cloud_a->height = cloud_b->height = 1;
	cloud_a->points.resize(cloud_a->height * cloud_a->width);


	// 因为cloud_a是5,因为要字段间连接,故需要将cloud_b转换成cloud_bb,且cloud_bb也应该与cloud_a保持一致都是5
	cloud_b->width = 5;
	cloud_b->points.resize(cloud_b->height * cloud_b->width);
	for (size_t i = 0; i < cloud_a->points.size(); ++i)
	{  
		cloud_a->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud_a->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud_a->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
	}
	for (size_t i = 0; i < cloud_b->points.size(); ++i)
	{   
		cloud_b->points[i].normal_x = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud_b->points[i].normal_y = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud_b->points[i].normal_z = 1024 * rand() / (RAND_MAX + 1.0f);
	}

	std::cerr << "Cloud A(XYZ): " << std::endl;
	for (size_t i = 0; i < cloud_a->size(); i++) {
		std::cerr << "  " << cloud_a->points[i].x << "  " << cloud_a->points[i].y << "  " << cloud_a->points[i].z << std::endl;
	}
	std::cerr << "Cloud B(normal): " << std::endl;
	for (size_t i = 0; i < cloud_b->size(); i++) {
		std::cerr << "  " << cloud_b->points[i].normal_x << "  " << cloud_b->points[i].normal_y << "  " << cloud_b->points[i].normal_z << std::endl;
	}
	
	pcl::concatenateFields(*cloud_a, *cloud_b, *cloud_c); // 把cloud_a和cloud_b字段间连接一起创建cloud_c后输出
	std::cerr << "Cloud C(XYZnormal): " << std::endl;
	for (size_t i = 0; i < cloud_c->points.size(); i++){
		std::cerr << "    " << cloud_c->points[i].x << " " << cloud_c->points[i].y << " " << cloud_c->points[i].z << " "
			                << cloud_c->points[i].normal_x << " " << cloud_c->points[i].normal_y << " " << cloud_c->points[i].normal_z << std::endl;
	}

	return 0;
}

在这里插入图片描述

五,kd-tree搜索

1,KNN最小近邻搜索

kdtree.setInputCloud(cloud);
kdtree.nearestKSearch(beyond, K, pointIdxKNN, pointKNNSquareDistance)
查找在cloud点云中,找离beyond这个点最近的K个点的坐标位置,查找出来的点是K个

#include <pcl/point_cloud.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <iostream>
#include <vector>
#include <ctime>

int main(int agrc, char* agrv[])
{
	srand(time(NULL)); // 使用系统时间初始化随机种子
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();

	// 随机生成点云
	cloud->width = 100;
	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.0f * rand() / (RAND_MAX)+(float)1.0f;
		cloud->points[i].y = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;
		cloud->points[i].z = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;
	}

	// 创建KdTreeFlann对象,并把创建的点云作为输入,创建一个searchPoint变量作为查询点
	pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
	// 要搜索的点云
	kdtree.setInputCloud(cloud);
	// 设置查询的点云并赋值
	pcl::PointXYZ beyond;
	beyond.x = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;
	beyond.y = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;
	beyond.z = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;

	// 上述表示,在点云cloud中搜索beyond这个点云

	// k-neighborhood
	int K = 10; // 查找beyond这个点附近的K个点
	std::vector<int> pointIdxKNN(K); // 存放查询点附近的点的索引
	std::vector<float> pointKNNSquareDistance(K); // 存放附件点对应距离的平方
	std::cerr << "K nearest neighbor at( " << beyond.x << " " << beyond.y << " " << beyond.z << " ) with K= " << K << std::endl;

	// 在cloud这个点云中找beyond这个点最接近的周围K个点的索引pointIdxKNN和距离距离平方和pointKNNSquareDistance
	if (kdtree.nearestKSearch(beyond, K, pointIdxKNN, pointKNNSquareDistance) > 0)
	{
		for (size_t i = 0; i < pointIdxKNN.size(); i++)
		{
			// 输出所有近邻点的坐标
			std::cerr << "  " << cloud->points[pointIdxKNN[i]].x
				<< "  " << cloud->points[pointIdxKNN[i]].y
				<< "  " << cloud->points[pointIdxKNN[i]].z
				<< " (squared distance : " << pointKNNSquareDistance[i] << " )"
				<< std::endl;
		}
	}

	return 0;
}

在这里插入图片描述

2,半径R内搜索

kdtree.setInputCloud(cloud);
kdtree.radiusSearch(beyond, radius, pointIdxRadiusKNN, pointRadiusKNNSquareDistance)

查找在cloud点云中,以beyond这个点为圆心,radius为半径找在这个范围内的所有点的坐标位置

#include <pcl/point_cloud.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <iostream>
#include <vector>
#include <ctime>

int main(int agrc,char* agrv[])
{
	srand(time(NULL)); // 使用系统时间初始化随机种子
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();

	// 随机生成点云
	cloud->width = 100;
	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.0f * rand() / (RAND_MAX)+(float)1.0f;
		cloud->points[i].y = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;
		cloud->points[i].z = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;
	}

	// 创建KdTreeFlann对象,并把创建的点云作为输入,创建一个searchPoint变量作为查询点
	pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
	// 要搜索的点云
	kdtree.setInputCloud(cloud);
	// 设置查询的点云并赋值
	pcl::PointXYZ beyond;
	beyond.x = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;
	beyond.y = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;
	beyond.z = 1024.0f * rand() / (RAND_MAX)+(float)1.0f;

	// 上述表示,在点云cloud中搜索beyond这个点云
	int K = 10; // 查找beyond这个点附近的K个点
	
	// 最小半径搜索
	std::vector<int> pointIdxRadiusKNN(K); // 存放查询点附近的点的索引
	std::vector<float> pointRadiusKNNSquareDistance(K); // 存放附件点对应距离的平方
	float radius = 256.0f * rand() / (RAND_MAX + 1.0f); // 随机生成的半径
	std::cerr << "K within radius neighbor at( " << beyond.x << " " << beyond.y << " " << beyond.z << "  ) with radius= " << radius << std::endl;

	// 在cloud这个点云中以beyond这个点为圆心半径为radius内的点的索引pointIdxRadiusKNN和距离距离平方和pointRadiusKNNSquareDistance
	if (kdtree.radiusSearch(beyond, radius, pointIdxRadiusKNN, pointRadiusKNNSquareDistance) > 0)
	{
		for (size_t i = 0; i < pointIdxRadiusKNN.size(); i++)
		{
			// 输出所有近邻点的坐标
			std::cerr << "  " << cloud->points[pointIdxRadiusKNN[i]].x
				      << "  " << cloud->points[pointIdxRadiusKNN[i]].y
				      << "  " << cloud->points[pointIdxRadiusKNN[i]].z
				      << " (squared distance : " << pointRadiusKNNSquareDistance[i] <<" )"
				      << std::endl;
		}
	}
	return 0;
}

因为点和半径都是随机的,不一定每次运行就能找到
有可能这个半径内没有点,所以有可能没有点的输出
多尝试几次
在这里插入图片描述

六、Octree八叉树搜索

数学原理有点多,后期再补充学习

七、Visualizer点云可视化

显示自己的点云数据

#include <pcl\visualization\cloud_viewer.h>
#include <iostream>
#include <pcl\io\io.h>
#include <pcl\io\pcd_io.h>

int main(int agrc,char*agrv[])
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::io::loadPCDFile("1_part.pcd",*cloud);

	pcl::visualization::PCLVisualizer visulaizer;
	visulaizer.setBackgroundColor(0, 0, 0); // RGB设置背景颜色
	visulaizer.addPointCloud(cloud);
	visulaizer.addCoordinateSystem(1.0);
	visulaizer.initCameraParameters(); // 显示坐标系 红x绿y蓝z
	// visulaizer.resetCamera(); // 不显示坐标系
	visulaizer.spin();

	return 0;
}

在这里插入图片描述

八、Filter点云滤波

1,直通滤波

说白了就是可以根据指定某个轴给定范围进行保留
pcl::PassThrough<pcl::PointXYZ> pass; // 定义直通滤波对象
pass.setInputCloud(cloud); // 对加载的原始点云进行处理
pass.setFilterFieldName("z"); // 直通滤波Z轴
pass.setFilterLimits(700, 920); // Z轴的范围为700-920
pass.filter(*result_z); // 滤波之后的结果为result_z点云

#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>
#include <pcl/io/pcd_io.h>
#include <pcl\visualization\pcl_visualizer.h>

int main(int agrc ,char* agrv[])
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::PointCloud<pcl::PointXYZ>::Ptr result_z = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::PointCloud<pcl::PointXYZ>::Ptr result_y = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::PointCloud<pcl::PointXYZ>::Ptr result_x = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::io::loadPCDFile("1_model_xyz.pcd", *cloud);

	pcl::PassThrough<pcl::PointXYZ> pass; // 定义直通滤波对象
	pass.setInputCloud(cloud); // 对加载的原始点云进行处理
	pass.setFilterFieldName("z"); // 直通滤波Z轴
	pass.setFilterLimits(700, 920); // Z轴的范围为700-920
	pass.filter(*result_z); // 滤波之后的结果为result_z点云
	
	// 对Y轴和X轴进行直通滤波的时候是基于得到的结果进行再次操作
	pass.setInputCloud(result_z);
	pass.setFilterFieldName("y");
	pass.setFilterLimits(-200, 100);
	pass.filter(*result_y);

	pass.setInputCloud(result_y);
	pass.setFilterFieldName("x");
	pass.setFilterLimits(-200, 200);
	pass.filter(*result_x);

/*
	std::cerr << "Cloud after filtering: " << std::endl;
	for (size_t i = 0; i < result_x->points.size(); ++i)
		std::cerr << "    " << result_x->points[i].x << " "
		<< result_x->points[i].y << " "
		<< result_x->points[i].z << std::endl;
*/


	pcl::visualization::PCLVisualizer visualizer;
	visualizer.addPointCloud(result_x);
	visualizer.initCameraParameters();
	visualizer.resetCamera();
	visualizer.spin();

	return 0;
}

原点云
在这里插入图片描述
通过直通滤波进行XYZ各个方向进行过滤,得到只包含红色目标的物体
先对Z轴进行直通滤波,然后依次对Y轴和X轴进行直通滤波操作
在这里插入图片描述

2,VoxelGrid滤波器

体素化网格方法实现下采样,减少点云数据
原理:创建一个三位体素栅格,每个体素内的所有点的重心来近似表示体素中的其他点,这个体素内的所有点都可以用重心点表示,可以减少数据量
在这里插入图片描述
使用VoxelGrid滤波器加载的数据必须是pcl::PCLPointCloud2格式

pcl::VoxelGrid<pcl::PCLPointCloud2> sor; // 定义VoxelGrid对象
sor.setInputCloud(cloud); //加载原始点云数据进行处理
sor.setLeafSize(1.0f, 1.0f, 1.0f); // 设置滤波时创建的体素体积为1m的立方体,这样相当于1立方米内的体素栅格内的点归一成重心点,可以下采样减少点云数据量
sor.filter(*cloud_filtered); // 输出结果,类型也必须是pcl::PCLPointCloud2

pcl::fromPCLPointCloud2(*cloud_filtered, *src);//可以将pcl::PCLPointCloud2格式转换为pcl::PointXYZ格式,通过可视化进行显示

#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/io/pcd_io.h>
#include <pcl\visualization\pcl_visualizer.h>

int main(int agrc, char* agrv[])
{
	pcl::PCLPointCloud2::Ptr cloud = std::make_shared<pcl::PCLPointCloud2>();;
	pcl::PCLPointCloud2::Ptr cloud_filtered = std::make_shared<pcl::PCLPointCloud2>();
	pcl::io::loadPCDFile("1_model_xyz.pcd", *cloud);

	pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
	sor.setInputCloud(cloud);
	sor.setLeafSize(1.0f, 1.0f, 1.0f); // 设置滤波时创建的体素体积为1m的立方体,这样相当于1立方米内的体素栅格内的点归一成重心点,可以下采样减少点云数据量
	sor.filter(*cloud_filtered);

	pcl::PointCloud<pcl::PointXYZ>::Ptr src = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::fromPCLPointCloud2(*cloud_filtered, *src);

	std::cerr << "voxelgrid filter is: "<< src->points.size() << std::endl; // 

	pcl::visualization::PCLVisualizer visualizer;
	visualizer.addPointCloud(src);
	visualizer.initCameraParameters();
	visualizer.resetCamera();
	visualizer.spin();

	return 0;
}

原始点云大小为:1063964
在这里插入图片描述
下采样之后的点云大小为:925246
在这里插入图片描述

3,statisticalOutlierRemoval滤波器

statisticalOutlierRemoval滤波器移除离群点,emmm说真的,没看懂,先放个案例在这吧

pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; // 定义滤波器对象
sor.setInputCloud(cloud); // 放入待处理的点云
sor.setMeanK(200); //设置考虑临界点点数
sor.setStddevMulThresh(1.0); // 考虑离群点的阈值
sor.filter(*cloud_result); // 得出结果点云

#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/io/pcd_io.h>
#include <pcl\visualization\pcl_visualizer.h>

int main(int agrc, char* agrv[])
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_result = std::make_shared<pcl::PointCloud<pcl::PointXYZ>>();
	pcl::io::loadPCDFile("1_model_xyz.pcd", *cloud);

	pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
	sor.setInputCloud(cloud);                           //设置待滤波的点云
	sor.setMeanK(200);                                  //设置在进行统计时考虑查询点临*点数
	sor.setStddevMulThresh(1.0);                        //设置判断是否为离群点的阀值
	sor.filter(*cloud_result);

	std::cerr << "StatisticalOutlierRemoval filter is: " << cloud_result->points.size() << std::endl; // 

	pcl::visualization::PCLVisualizer visualizer;
	visualizer.addPointCloud(cloud);
	visualizer.initCameraParameters();
	visualizer.resetCamera();
	visualizer.spin();

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/768927.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Halcon支持向量机

一 支持向量机 1 支持向量机介绍&#xff1a; 支持向量机(Support Vector Machine&#xff0c;SVM)是Corinna Cortes和Vapnik于1995年首先提出的&#xff0c;它在解决小样本、非线性及高维模式识别表现出许多特有的优势。 2 支持向量机原理: 在n维空间中找到一个分类超平面…

4.整合第三方技术【整合JUnit】

目录 1.创建项目&#xff1a; 2.导入测试对应的starter 3.添加测试对象 3.1 添加Prodcut接口文件 3.2 添加ProdcutImpl文件 3.3 测试类添加测试文件&#xff0c;并开始测试 4.测试类文件解析 4.1.测试类使用SpringBootTest修饰 4.2使用自动装配的形式添加要测试的对象 1.…

LeetCode 算法:路径总和 III c++

原题链接&#x1f517;&#xff1a;路径总和 III 难度&#xff1a;中等⭐️⭐️ 题目 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶…

大模型与机器人精彩碰撞-7月5日晚上八点不见不散!

在瞬息万变的科技时代&#xff0c;新兴人工智能和机器人技术的结合正在引领新一轮的创新浪潮。你是否想成为未来科技的领航者&#xff1f;你是否想了解最前沿的AI与机器人技术&#xff1f;行麦科技重磅推出的“AIGC时代的生存法则”AI系列课&#xff0c;将为你揭开大模型与机器…

数据库操作语言(DML)

数据库操作语言&#xff08;DML&#xff09; 文章目录 数据库操作语言&#xff08;DML&#xff09;一、四种操作二、数据的插入&#xff08;增&#xff09;三、数据的删除&#xff08;删&#xff09;四、数据的修改&#xff08;改&#xff09;五、数据的查询&#xff08;查&…

科研与英文学术论文写作指南——于静老师课程

看到了一个特别棒的科研与英文学术论文写作指南&#xff0c;理论框架实例。主讲人是中科院信息工程研究所的于静老师。推荐理由&#xff1a;写论文和读论文或者讲论文是完全不一样的&#xff0c;即使现在还没有发过论文&#xff0c;但是通过于老师的课程&#xff0c;会给后续再…

2024最新Stable Diffusion【插件篇】:SD提示词智能生成插件教程!

前言 今天我们介绍几款可以自动生成提示词的插件。所谓智能生成提示词&#xff0c;就是我们只需要输入非常少量的关键字&#xff0c;插件就会根据关键词提示信息帮助我们生成一系列关键字或者句子作为提示词。下面来和我一起看看吧。 一. SD智能提示词工具 之前的文章中和大…

Java学习 - Redis-Cluster

为什么需要集群 为了高的处理速度 单机redis&#xff0c;官网宣传处理速度为10万命令/秒如果业务需要更高的处理速度&#xff0c;则需要使用集群 为了存储大量数据 一般机器的内存为16-256G如果想要存储更大量的数据&#xff0c;则需要使用集群 分布式之数据分区 因为数据需…

KEYSIGHT是德科技 E5063A ENA 系列网络分析仪

E5063A ENA 矢量网络分析仪 18GHz 2端口 降低无源射频元器件的测试成本 Keysight E5063A ENA 是一款经济适用的台式矢量网络分析仪&#xff0c;可用于测试简单的无源元器件&#xff0c;例如频率最高达到 18 GHz 的天线、滤波器、电缆或连接器。 作为业界闻名的 ENA 系列…

工具:颜色查询 / CMYK颜色查询RGB、HSL、HSV、XYZ的颜色值

一、颜色查询-网址 RGB(90,223,9),#5ADF09 颜色查询,颜色梯度,色彩搭配,色盲模拟 - RGB颜色查询 - 在线工具 - Fontke.com 二、CMYK颜色查询RGB、HSL、HSV、XYZ的颜色值 三、颜色梯度 四、色彩搭配 五、色盲模拟 六、欢迎交流指正

程序员的加油站,各类技术文章,可视化技术,在线源码资源,在线实用工具,数据爬虫接口持续集成更新中

先挂网址&#xff1a;https://wheart.cn 可视化大屏模板与设计&#xff0c;在线预览 上百例可视化模板 技术文章、资源下载等各类资源导航页 echart在线实用demo 各种在线工具提升开发效率 echart在线代码模板

服务器之BIOS基础知识总结

1.BIOS是什么&#xff1f; BIOS全称Basic Input Output System&#xff0c;即基本输入输出系统&#xff0c;是固化在服务器主板的专用ROM上&#xff0c;加载在服务器硬件系统上最基本的运行程序&#xff0c;它位于服务器硬件和OS之间&#xff0c;在服务器启动过程中首先运行&am…

配置Uptime Kuma固定前缀

在做ICT集成项目时&#xff0c;遇到需要对现网接口进行拨测的需求。搜索后尝试使用开源的Uptime Kuma组件完成现网接口拨测。 但该项目有个问题就是默认不支持配置固定前缀&#xff0c;这对现网进行请求转发会造成较大的影响。通过查看该项目的github后找到了问题的解决方案。S…

助力游戏实现应用内运营闭环,融云游戏社交方案升级!

通信能力在所有应用场景都是必备组件&#xff0c;这源于社交属性带给应用的增长神话。 在游戏场景&#xff0c;玩家从少数核心向大众用户泛化扩展的过程&#xff0c;就是游戏深度融合社交能力的过程。 从单机到联机&#xff0c;游戏乐趣的升级 1996 年&#xff0c;游戏界顶流…

Laravel swagger接口文档生成和管理

Laravel swagger接口文档生成和管理 接口开发随着时间推移接口会越来越多&#xff0c;随着多部门之间的协作越来越频繁, 维护成本越来越高, 文档的可维护性越来越差, 需要一个工具来管理这些接口的文档, 并能够充当mock server给调用方使用 这里推荐swagger生成和管理接口文档&…

硅纪元视角 | 1 分钟搞定 3D 创作,Meta 推出革命性 3D Gen AI 模型

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

Arthas实战(2)- OOM问题排查

一、 准备测试应用 新建一个 SpringBoot应用&#xff0c;写一段有 OOM bug 的代码&#xff1a; RestController RequestMapping public class JvmThreadController {List<TestWrapper> memoryList new ArrayList<>();GetMapping("/test")public Strin…

Element 的 el-table 表格实现单元格合并

html 部分 <template><div class"index-wapper"><el-table :data"tableData" :span-method"objectSpanMethod" border><el-table-column v-for"(item, index) in tableHeader" :key"index" :prop&quo…

【C语言】auto 关键字

在C语言中&#xff0c;auto关键字用于声明局部变量&#xff0c;但它的使用已经变得很少见。事实上&#xff0c;从C99标准开始&#xff0c;auto关键字的默认行为就是隐含的&#xff0c;因此在大多数情况下无需显式使用它。 基本用法 在C语言中&#xff0c;auto关键字用于指定变…

五粮液:稳,还稳得住吗?

前有“酱香”茅台一骑绝尘&#xff0c;后有“清香”汾酒21%的增速虎视眈眈。 在新的股东大会上&#xff0c;管理层把“稳”字说了近30次。 就问白酒二哥——五粮液&#xff0c;你还稳得住吗&#xff1f; 近期&#xff0c;白酒大哥茅台因跌价吸引各方关注&#xff0c;但在这一…