pcl--第一节 Filters

news2024/11/26 12:00:42

官方例子在这里,本人使用的pcl1.12.1版本,win11,直接从github下载编译好的版本,使用vs打开cmake,之所以使用cmake,原因是环境配置方便,vs本身配置环境比较麻烦,所以为了方便使用cmake进行学习,这里参考了点云库pcl学习教程以及一些博客和官方例子进行学习,同时呢,笔者不会直接从背景、io、读取点云啥的介绍,这个东西,在实际使用时在查找或者学习也不晚,因此笔者会直接从涉及点云算法方面入手开始

背景介绍

下图给出了噪声消除的示例。由于测量误差,某些数据集会出现大量阴影点。这使得局部点云 3D 要素的估计变得复杂。其中一些异常值可以通过对每个点的邻域执行统计分析并修剪不符合特定条件的邻域来过滤。PCL 中的稀疏异常值去除实现基于对输入数据集中点到相邻距离分布的计算。对于每个点,将计算从该点到其所有相邻点的平均距离。通过假设生成的分布是具有平均值和标准差的高斯分布,则平均距离超出由全局距离平均值和标准差定义的区间之外的所有点都可以被视为异常值并从数据集中修剪。

PCL中总结了几种需要进行点云滤波处理的情况,这几种情况分别如下:

  1. 点云数据密度不规则需要平滑。
  2. 因为遮挡等问题造成离群点需要去除。
  3. 大量数据需要进行下采样(Downsample)
  4. 噪声数据需要去除

对应的方法如下

  1.  按具体给定的规则限制过滤去除点

  2.  通过常用滤波算法修改点的部分属性。

  3.    对数据进行下采样

 

直通滤波器PassThrough

官方介绍很简单,但是filters这节提供了很多东西,需要我们自己去学习,我这边先把官方代码奉上,还有一点就是官方代码不适合高版本,这里也进行了修改和测试

#include<iostream>
#include<pcl/point_types.h>
#include<pcl/filters/passthrough.h>

int main()
{
	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 (auto& point : *cloud)
	{
		point.x =  0.5+rand() / (RAND_MAX + 1.0f);
		point.y =  0.5+rand() / (RAND_MAX + 1.0f);
		point.z =  0.5+rand() / (RAND_MAX + 1.0f);
	}

	std::cerr << "Cloud before filtering: " << std::endl;
	for (const auto& point : *cloud)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;

	pcl::PassThrough<pcl::PointXYZ> pass;
	pass.setInputCloud(cloud);
	pass.setFilterFieldName("z");
	pass.setFilterLimits(0.0, 1.0);
	pass.setFilterLimitsNegative(true);
	pass.filter(*cloud_filtered);

	std::cerr << "Cloud after filtering: " << std::endl;
	for (const auto& point : *cloud_filtered)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;

	return (0);

}
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)

project(test)
SET(EXECUTABLE_OUTPUT_PATH "D:\\project_prj\\pcl\\run")
find_package(PCL 1.2 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (test  "passthrough.cpp")
target_link_libraries (test ${PCL_LIBRARIES})

把可执行文件都放到run里,需要把需要的dll都复制到这里才可以运行。

VoxelGrid滤波进行数据下采样

使用体素化网格方法实现下采样,即减少点的数量减少点云数据,并同时保持点云的形状特征,在提高配准、曲面重建、形状识别等算法速度中非常实用。PCL实现的VoxelGrid类通过输人的点云数据创建一个三维体素栅格(可把体素栅格想象为微小的空间三维立方体的集合),然后在每个体素(即,三维立方体)内用体素中所有点的重心来近似显示体素中其他点,这样该体素就内所有点就用一个重心点最终表示,对于所有体素处理后得到过滤后的点云。这种方法比用体素中心来逼近的方法更慢,但它对于采样点对应曲面的表示更为准确。

#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include<pcl/filters/passthrough.h>
#include<pcl/filters/voxel_grid.h>
#include <pcl/visualization/pcl_visualizer.h>
int main()
{
	// 体素滤波,降采样
	pcl::PCLPointCloud2::Ptr cloud(new pcl::PCLPointCloud2());
	pcl::PCLPointCloud2::Ptr cloud_filtered(new pcl::PCLPointCloud2());

	//创建pcd读取器
	pcl::PCDReader reader;
	reader.read("D:\\install\\pcl_1.13.1_data_pcd\\tutorials\\table_scene_lms400.pcd", *cloud);
	std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height
		<< " data points (" << pcl::getFieldsList(*cloud) << ")." << std::endl;
	// 创建滤波器对象
	pcl::VoxelGrid<pcl::PCLPointCloud2> 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) << ")." << std::endl;
	pcl::PCDWriter writer;
	writer.write("table_scene_lms400_downsampled.pcd", *cloud_filtered,
		Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), false
	);

	
	return (0);

}

使用下面的命令在cmd中执行可以看到滤波前和滤波后的可视化

pcl_viewer.exe -multiview 1 .\table_scene_lms400.pcd .\table_scene_lms400_downsampled.pcd

 

使用StatisticalOutlierRemoval滤波器移除离群点

学习如何使用统计分析技术,从一个点云数据集中移除测量噪声点(也就是离群点)。

背景知识:

激光扫描通常会产生密度不均匀的点云数据集。另外,测量中的误差会产生稀疏的离群点,使效果更糟。估计局部点云特征(例如采样点处法向量或曲率变化率)的运算很复杂,这会导致错误的数值,反过来有可能导致点云的配准等后期处理失败。以下方法可以解决其中部分问题:对每个点的邻域进行一个统计分析,并修剪掉那些不符合一定标准的点。我们的稀疏离群点移除方法基于在输入数据中对点到临近点的距离分布的计算。对每个点,我们计算它到它的所有临近点的平均距离。假设得到的结果是一个高斯分布,其形状由均值和标准差决定,平均距离在标准范围(由全局距离平均值和方差定义)之外的点,可被定义为离群点并可从数据集中去除掉。

 

#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include<pcl/filters/passthrough.h>
#include<pcl/filters/voxel_grid.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/visualization/pcl_visualizer.h>
int main()
{
	
	// 统计分析滤波
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);

	// Fill in the cloud data
	pcl::PCDReader reader;
	// Replace the path below with the path where you saved your file
	reader.read<pcl::PointXYZ>("table_scene_lms400.pcd", *cloud);

	std::cerr << "Cloud before filtering: " << std::endl;
	std::cerr << *cloud << std::endl;
	// 创建统计滤波
	pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
	sor.setInputCloud(cloud);
	sor.setMeanK(50);// 使用临近50个点做统计
	sor.setStddevMulThresh(1.0); // 设置标准差倍数为1,一个点的距离超出平均距离的一个标准差以上认为是离群点
	sor.filter(*cloud_filtered);

	std::cerr << "Cloud after filtering: " << std::endl;
	std::cerr << *cloud_filtered << std::endl;

	pcl::PCDWriter writer;
	writer.write<pcl::PointXYZ>("table_scene_lms400_inliers.pcd", *cloud_filtered, false);

	sor.setNegative(true);
	sor.filter(*cloud_filtered);
	writer.write<pcl::PointXYZ>("table_scene_lms400_outliers.pcd", *cloud_filtered, false);
return 0
}
pcl_viewer.exe -multiview 1 .\table_scene_lms400.pcd .\table_scene_lms400_inliers.pcd .\table_scene_lms400_outliers.pcd

使用参数化模型投影点云project_inliers

学习如何将点投影到一个参数化模型上(例如平面或球等)。参数化模型通过一组参数来设定,对于平面来说使用其等式形式a+by+cz+d=0,在PCL中有特意存储常见模型系数的数据结构。

#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include<pcl/filters/passthrough.h>
#include<pcl/filters/voxel_grid.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/project_inliers.h>
int main()
{
	// 使用参数化模型投影点云
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected(new pcl::PointCloud<pcl::PointXYZ>);

	// Fill in the cloud data
	cloud->width = 5;
	cloud->height = 1;
	cloud->points.resize(cloud->width * cloud->height);

	for (auto& point : *cloud)
	{
		point.x = 1024 * rand() / (RAND_MAX + 1.0f);
		point.y = 1024 * rand() / (RAND_MAX + 1.0f);
		point.z = 1024 * rand() / (RAND_MAX + 1.0f);
	}

	std::cerr << "Cloud before projection: " << std::endl;
	for (const auto& point : *cloud)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;
	/*
	* 填充ModelCoefficients 的值,本例中使用一个ax+by+cz+d=0的平面模型其中a=b=d=0,c=1,
	* 换句话说,也就是 X-Y平面,用户可以任意定义 PCL中支持的模型圆球、圆柱、锥形等进行投影滤波。
	*/
	pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
	coefficients->values.resize(4);
	coefficients->values[0] = coefficients->values[1] = 0;
	coefficients->values[2] = 1.0;
	coefficients->values[3] = 0;

	// 创建滤波对象
	pcl::ProjectInliers<pcl::PointXYZ> proj;
	proj.setModelType(pcl::SACMODEL_PLANE);
	proj.setInputCloud(cloud);
	proj.setModelCoefficients(coefficients);
	proj.filter(*cloud_projected);
	std::cerr << "Cloud after projection: " << std::endl;
	for (const auto& point : *cloud_projected)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;



	return (0);

}
Cloud before projection:
    1.28125 577.094 197.938
    828.125 599.031 491.375
    358.688 917.438 842.562
    764.5 178.281 879.531
    727.531 525.844 311.281
Cloud after projection:
    1.28125 577.094 0
    828.125 599.031 0
    358.688 917.438 0
    764.5 178.281 0
    727.531 525.844 0

从一个点云中提取索引extract_indices

这里就是简单的使用模型获取点云的平面,然后提取对应的索引,然后获取对应的点云数据

#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include<pcl/filters/passthrough.h>
#include<pcl/filters/voxel_grid.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/project_inliers.h>

#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/filters/extract_indices.h>

int main()
{
	// 从一个点云中提取索引
	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;

	// Create the filtering object: downsample the dataset using a leaf size of 1cm
	// 降采样,加速后续的计算速度
	pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
	sor.setInputCloud(cloud_blob);
	sor.setLeafSize(0.01f, 0.01f, 0.01f);
	sor.filter(*cloud_filtered_blob);

	// Convert to the templated PointCloud
	pcl::fromPCLPointCloud2(*cloud_filtered_blob, *cloud_filtered);

	std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height << " data points." << std::endl;

	// Write the downsampled version to disk
	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;
	// 设置参数
	seg.setOptimizeCoefficients(true);
	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;
	int nr_points = cloud_filtered->size();
	while (cloud_filtered->size()>0.3*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 << "table_scene_lms400_plane_" << i << ".pcd";
		writer.write<pcl::PointXYZ>(ss.str(), *cloud_p, false);

		// Create the filtering object
		extract.setNegative(true);
		extract.filter(*cloud_f);
		cloud_filtered.swap(cloud_f);
		i++;
	}
	return (0);

}
pcl_viewer.exe -multiview 1 .\table_scene_lms400_downsampled.pcd .\table_scene_lms400_plane_0.pcd .\table_scene_lms400_plane_1.pcd

使用ConditionalRemoval或 RadiusOutlierRemoval移除离群点 

ConditionalRemoval¶

条件滤波,设置不同维度滤波规则进行滤波,具体见下个与【半径离群值滤波】合并的案例。

RadiusOutlierRemoval¶

半径离群值滤波

下图有助于可视化RadiusOutlierRemoval过滤器对象的作用。用户指定邻居的个数,要每个点必须在指定半径内具有指定个邻居才能保留在PointCloud中。例如,如果指定了1个邻居,则只会从PointCloud中删除黄点。如果指定了2个邻居,则黄色和绿色的点都将从PointCloud中删除。

// 使用ConditionalRemoval或 RadiusOutlierRemoval移除离群点 
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);

	// Fill in the cloud data
	cloud->width = 15;
	cloud->height = 1;
	cloud->resize(cloud->width* cloud->height);

	for (auto& point : *cloud)
	{
		point.x =  rand() / (RAND_MAX + 1.0f);
		point.y =  rand() / (RAND_MAX + 1.0f);
		point.z =  rand() / (RAND_MAX + 1.0f);
	}

	if (true) {
		pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
		// build the filter
		outrem.setInputCloud(cloud);
		outrem.setRadiusSearch(0.5);
		outrem.setMinNeighborsInRadius(3);
		outrem.setKeepOrganized(true);
		// apply filter
		outrem.filter(*cloud_filtered);
	}
	else if (false) {
		// build the condition
		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.8)));
		// build the filter
		pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
		condrem.setCondition(range_cond);
		condrem.setInputCloud(cloud);
		condrem.setKeepOrganized(true);
		// apply filter
		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 (const auto& point : *cloud)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;
	// display pointcloud after filtering
	std::cerr << "Cloud after filtering: " << std::endl;
	for (const auto& point : *cloud_filtered)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;

 目前就这些例子,后续在其他应用中会大量的使用这边滤波方法

总体代码

 

#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
#include<pcl/filters/passthrough.h>
#include<pcl/filters/voxel_grid.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/project_inliers.h>

#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/filters/extract_indices.h>

#include <pcl/filters/radius_outlier_removal.h>
#include <pcl/filters/conditional_removal.h>


int main()
{
	// 直通滤波器
#if 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 (auto& point : *cloud)
	{
		point.x =  0.5+rand() / (RAND_MAX + 1.0f);
		point.y =  0.5+rand() / (RAND_MAX + 1.0f);
		point.z =  0.5+rand() / (RAND_MAX + 1.0f);
	}

	std::cerr << "Cloud before filtering: " << std::endl;
	for (const auto& point : *cloud)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;

	pcl::PassThrough<pcl::PointXYZ> pass;
	pass.setInputCloud(cloud);
	pass.setFilterFieldName("z");
	pass.setFilterLimits(0.0, 1.0);
	pass.setFilterLimitsNegative(true);
	pass.filter(*cloud_filtered);

	std::cerr << "Cloud after filtering: " << std::endl;
	for (const auto& point : *cloud_filtered)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;
	
#endif

	// 体素滤波,降采样
#if 0
	pcl::PCLPointCloud2::Ptr cloud(new pcl::PCLPointCloud2());
	pcl::PCLPointCloud2::Ptr cloud_filtered(new pcl::PCLPointCloud2());

	//创建pcd读取器
	pcl::PCDReader reader;
	reader.read("D:\\install\\pcl_1.13.1_data_pcd\\tutorials\\table_scene_lms400.pcd", *cloud);
	std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height
		<< " data points (" << pcl::getFieldsList(*cloud) << ")." << std::endl;
	// 创建滤波器对象
	pcl::VoxelGrid<pcl::PCLPointCloud2> 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) << ")." << std::endl;
	pcl::PCDWriter writer;
	writer.write("table_scene_lms400_downsampled.pcd", *cloud_filtered,
		Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), false
	);
#endif
	
	// 统计分析滤波
#if 0
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);

	// Fill in the cloud data
	pcl::PCDReader reader;
	// Replace the path below with the path where you saved your file
	reader.read<pcl::PointXYZ>("table_scene_lms400.pcd", *cloud);

	std::cerr << "Cloud before filtering: " << std::endl;
	std::cerr << *cloud << std::endl;
	// 创建统计滤波
	pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
	sor.setInputCloud(cloud);
	sor.setMeanK(50);// 使用临近50个点做统计
	sor.setStddevMulThresh(1.0); // 设置标准差倍数为1,一个点的距离超出平均距离的一个标准差以上认为是离群点
	sor.filter(*cloud_filtered);

	std::cerr << "Cloud after filtering: " << std::endl;
	std::cerr << *cloud_filtered << std::endl;

	pcl::PCDWriter writer;
	writer.write<pcl::PointXYZ>("table_scene_lms400_inliers.pcd", *cloud_filtered, false);

	sor.setNegative(true);
	sor.filter(*cloud_filtered);
	writer.write<pcl::PointXYZ>("table_scene_lms400_outliers.pcd", *cloud_filtered, false);

#endif
	// 使用参数化模型投影点云
#if 0
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected(new pcl::PointCloud<pcl::PointXYZ>);

	// Fill in the cloud data
	cloud->width = 5;
	cloud->height = 1;
	cloud->points.resize(cloud->width * cloud->height);

	for (auto& point : *cloud)
	{
		point.x = 1024 * rand() / (RAND_MAX + 1.0f);
		point.y = 1024 * rand() / (RAND_MAX + 1.0f);
		point.z = 1024 * rand() / (RAND_MAX + 1.0f);
	}

	std::cerr << "Cloud before projection: " << std::endl;
	for (const auto& point : *cloud)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;
	/*
	* 填充ModelCoefficients 的值,本例中使用一个ax+by+cz+d=0的平面模型其中a=b=d=0,c=1,
	* 换句话说,也就是 X-Y平面,用户可以任意定义 PCL中支持的模型圆球、圆柱、锥形等进行投影滤波。
	*/
	pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
	coefficients->values.resize(4);
	coefficients->values[0] = coefficients->values[1] = 0;
	coefficients->values[2] = 1.0;
	coefficients->values[3] = 0;

	// 创建滤波对象
	pcl::ProjectInliers<pcl::PointXYZ> proj;
	proj.setModelType(pcl::SACMODEL_PLANE);
	proj.setInputCloud(cloud);
	proj.setModelCoefficients(coefficients);
	proj.filter(*cloud_projected);
	std::cerr << "Cloud after projection: " << std::endl;
	for (const auto& point : *cloud_projected)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;
#endif
	// 从一个点云中提取索引
#if 0
	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;

	// Create the filtering object: downsample the dataset using a leaf size of 1cm
	// 降采样,加速后续的计算速度
	pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
	sor.setInputCloud(cloud_blob);
	sor.setLeafSize(0.01f, 0.01f, 0.01f);
	sor.filter(*cloud_filtered_blob);

	// Convert to the templated PointCloud
	pcl::fromPCLPointCloud2(*cloud_filtered_blob, *cloud_filtered);

	std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height << " data points." << std::endl;

	// Write the downsampled version to disk
	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;
	// 设置参数
	seg.setOptimizeCoefficients(true);
	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;
	int nr_points = cloud_filtered->size();
	while (cloud_filtered->size()>0.3*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 << "table_scene_lms400_plane_" << i << ".pcd";
		writer.write<pcl::PointXYZ>(ss.str(), *cloud_p, false);

		// Create the filtering object
		extract.setNegative(true);
		extract.filter(*cloud_f);
		cloud_filtered.swap(cloud_f);
		i++;
	}
#endif

	// 使用ConditionalRemoval或 RadiusOutlierRemoval移除离群点 
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);

	// Fill in the cloud data
	cloud->width = 15;
	cloud->height = 1;
	cloud->resize(cloud->width* cloud->height);

	for (auto& point : *cloud)
	{
		point.x =  rand() / (RAND_MAX + 1.0f);
		point.y =  rand() / (RAND_MAX + 1.0f);
		point.z =  rand() / (RAND_MAX + 1.0f);
	}

	if (true) {
		pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
		// build the filter
		outrem.setInputCloud(cloud);
		outrem.setRadiusSearch(0.5);
		outrem.setMinNeighborsInRadius(3);
		outrem.setKeepOrganized(true);
		// apply filter
		outrem.filter(*cloud_filtered);
	}
	else if (false) {
		// build the condition
		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.8)));
		// build the filter
		pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
		condrem.setCondition(range_cond);
		condrem.setInputCloud(cloud);
		condrem.setKeepOrganized(true);
		// apply filter
		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 (const auto& point : *cloud)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;
	// display pointcloud after filtering
	std::cerr << "Cloud after filtering: " << std::endl;
	for (const auto& point : *cloud_filtered)
		std::cerr << "    " << point.x << " "
		<< point.y << " "
		<< point.z << std::endl;


	return (0);

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FPGA----VCU128的SCUI(上位机软件)无法使用问题

1、第一次使用VCU128&#xff0c;发现很坑&#xff0c;记录一下使用方法。 ①首先需要在购买的包装盒子中找到密匙去官网下载个license ②在Vivado 2019.1版本中将2019.2的板卡数据导入&#xff0c;很奇怪把哈哈哈哈。下面是下载链接 https://github.com/Xilinx/XilinxBoard…

C++中extern的使用

目录 什么是extern&#xff1f;如何使用extern&#xff1f;声明一个全局变量或函数在当前文件中引用其他文件中定义的全局变量或函数 应用场景拓展结论 在C中&#xff0c;extern是一个非常重要的关键字&#xff0c;它用于声明一个变量或函数是在其他文件中定义的。在本文中&…

电子企业MES管理系统有哪些特征

随着科技的飞速发展和全球化的推进&#xff0c;电子行业已成为当今社会至关重要的产业之一。在这个高度竞争的市场环境中&#xff0c;实施一套有效的生产执行管理系统是电子企业提高效率、降低成本、提升品质的重要手段。本文将详细介绍电子企业MES管理系统的特征。 一、定义和…

使用mybatis批量插入数据

最近在做项目的时候&#xff0c;有些明细数据&#xff0c;一条一条的插入太费资源和时间&#xff0c;所以得需要批量插入&#xff0c;今晚闲来无事写个小demo。 新建工程 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis…

歌曲推荐《最佳损友》

最佳损友 陈奕迅演唱歌曲 《最佳损友》是陈奕迅演唱的一首粤语歌曲&#xff0c;由黄伟文作词&#xff0c;Eric Kwok&#xff08;郭伟亮&#xff09;作曲。收录于专辑《Life Continues》中&#xff0c;发行于2006年6月15日。 2006年12月26日&#xff0c;该曲获得2006香港新城…

可视化工具之pyecharts

一、pyecharts基础 1、概述 Pyecharts是一款将python与echarts结合的强大的数据可视化工具。使用 pyecharts 可以生成独立的网页&#xff0c;也可以在 flask , Django 中集成使用。 echarts 是百度开源的一个数据可视化 JS 库&#xff0c;主要用于数据可视化。pyecharts 是一…

PyCharm控制台中英文显示切换

一开始全英环境下不适应安装了汉化包插件&#xff0c;使用后发现还是英文显示好使&#xff0c;现在切换回来。 要在 PyCharm 中将界面语言设置为英文&#xff0c;可以按照以下步骤操作&#xff1a; 打开 PyCharm&#xff0c;在主菜单中依次选择「File」、「Settings」。在「S…

App Inventor 2 列表选择框(ListPicker)用法示例

设置固定的列表项&#xff0c;设置“元素字串”属性&#xff0c;多个列表项使用英文逗号分隔&#xff1a; 点击效果如下&#xff1a; 选择完成后的事件处理&#xff0c;最终选中的数据通过“选中项”属性获取&#xff1a; 通过代码块动态设置列表选择框的列表项&#x…

【服务器 | 测试】如何在centos 7上面安装jmeter

安装之前需要几个环境&#xff0c;以下是列出的几个环境 CentOS 7.7 64位JDK 1.8JMeter 5.2 1. 下载jmeter安装包 JMeter是开源的工具&#xff0c;安装 JMeter 要先安装好 JDK 的环境&#xff0c;安装JDK在前面的文章已经讲到 JMeter最新版下载地址&#xff1a;Apache JMeter…

c#动态保留小数位数的数值格式化方法实例----从小数点后非零数字保留两位进行四舍五入

c#动态保留小数位数的数值格式化方法实例----从小数点后非零数字保留两位进行四舍五入 功能介绍代码案例输出结果封装扩展方法控制台调用 其他方法地址 功能介绍 1. 输入的数字是整数&#xff0c;则直接返回整数部分的字符串表示。 2. 如果输入的数字是小数&#xff0c;则执行…

百家宴焕新上市,持续深耕100-300元价位段

执笔 | 尼 奥 编辑 | 古利特 4月8日&#xff0c;长江酒道曾在《百家宴谋划“晋级”之路&#xff0c;多措并举切分宴席市场“蛋糕”》一文中提到&#xff1a;“百家宴主力新品即将登场&#xff0c;市场政策灵活焕新。” 如今&#xff0c;百家宴新品及市场新政&#xff0c;正…

计算机二级公共基础知识-2023

计算机基础知识&#xff1a; 计算机的发展&#xff1a; 第一台电子计算机eniac 埃尼阿克 1946 第一台存储程序计算机 edvac 艾迪瓦克 根据电子元器件的发展分类 1.电子管 2.晶体管 3.集成电路 4.超大规模继承电路 按照电脑的用途可以分为 专用计算机 专门用于处理…

vcomp100.dll丢失怎样修复?5个靠谱的修复方法分享

VCOMP100.DLL 是由微软打造的动态链接库&#xff0c;它对于一些图形密集型应用&#xff0c;例如Photoshop&#xff0c;以及多款知名游戏如巫师3的运行至关重要。 如果操作系统在启动应用程序时无法找到此vcomp100.dll&#xff0c;则会出现vcomp100.dll丢失或未找到错误。 如果D…

Google 基于 GNN 开发气味识别 AI,工作量相当于人类评价员连续工作 70 年

内容一览&#xff1a;气味总是萦绕我们身边。然而&#xff0c;我们却很难对气味准确描述。最近&#xff0c;Google Research 的子公司 Osom 基于图神经网络&#xff0c;开发了气味分析 AI。它可以根据化学分子的结构&#xff0c;对分子的气味进行预测。基于这一 AI&#xff0c;…

2023年法国CAC40指数研究报告

第一章 指数概况 1.1 指数基本情况 CAC 40指数&#xff0c;全名 Cotation Assiste en Continu (意为“连续辅助报价”)&#xff0c;是法国巴黎股票交易所的标志性股票指数&#xff0c;与德国DAX指数及英国富时100指数并列为欧洲三大指数。自1987年12月31日成立以来&#xff0…

【Linux学习笔记】基础命令1

1. 什么是操作系统2. Linux基本指令2.1. ls指令2.2. pwd命令2.3. cd命令2.4. touch命令2.5. mkdir命令 1. 什么是操作系统 这里简单的讲述一下操作系统的概念&#xff0c;来看下图示&#xff1a; **操作系统是计算机系统中的一种软件&#xff0c;它负责管理计算机硬件资源和提…

CentOS 安装HTTP代理服务器 Tinyproxy

Tinyproxy是一个小型的基于GPL的HTTP/SSL代理程序&#xff0c;非常适合小型网络而且便于快速部署。这个代理程序最大的优点就是占用系统资源比较少。这里使用的系统为CentOS7.6&#xff0c;可以直接 yum 方式安装。 yum install tinyproxy -y 如果提示找不到安装包&#xff0…

中国各省市相关图标

中国各省市相关图标

buuctf crypto 【[GUET-CTF2019]BabyRSA】解题记录

1.打开文件 2.给出了pq以及&#xff08;p1&#xff09;*(q1),e&#xff0c;d&#xff0c;c&#xff0c;就可以得出结果了 import gmpy2 from Crypto.Util.number import long_to_bytes #pq用x表示 #(p1)(q1)用y表示 x 0x1232fecb92adead91613e7d9ae5e36fe6bb765317d6ed3…

Python爬虫基础(二):使用xpath与jsonpath解析爬取的数据

文章目录 系列文章索引一、使用xpath解析html文件1、浏览器安装xpath-healper&#xff08;1&#xff09;谷歌浏览器安装&#xff08;需要科学上网&#xff09;&#xff08;2&#xff09;验证&#xff08;3&#xff09;使用文件安装&#xff08;不需科学上网&#xff09; 2、安装…