Filtering recording point clouds

The film blog filtering reference blogger content https://blog.csdn.net/qq_34719188/article/details/79179430 the URL.

1. I made the main pipe by SICK scanner docking object, for the pre-data is converted to a measurement acquisition txt for pcd file formats: code below

点云数据txt转pcd格式
#include "pch.h"
#include<iostream> 
#include<fstream>
#include<vector>
#include<string>
#include<pcl\io\pcd_io.h>
#include<pcl\point_types.h>
using namespace std;
int main()
{	//定义一种类型表示TXT中xyz	
	typedef struct TXT_Point_XYZ	
	{	
		double x;		
	    double y;		
	    double z;	
	}TOPOINT_XYZ; 	
	//读取txt文件	
	int num_txt;	
	FILE *fp_txt;	
	TXT_Point_XYZ txt_points;	
	vector<TXT_Point_XYZ> my_vTxtPoints;	
	fp_txt = fopen("C://Users//HEHE//Desktop//Chair.txt","r"); 	
	if (fp_txt)	
	{		
		while (fscanf(fp_txt, "%lf %lf %lf", &txt_points.x, &txt_points.y, &txt_points.z) != EOF)		
		{//将点存入容器尾部			
			my_vTxtPoints.push_back(txt_points);		
		}	
	}	
	else		
		cout << "读取txt文件失败"<<endl; 	
	num_txt = my_vTxtPoints.size(); 	
	//写入点云数据	
	pcl::PointCloud<pcl::PointXYZ> ::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);	
	cloud->width = num_txt;	
	cloud->height = 1;	
	cloud->is_dense = false;	
	cloud->points.resize(cloud->width*cloud->height);	
	for (int i = 0; i < cloud->points.size(); ++i)	
	{		
		cloud->points[i].x = my_vTxtPoints[i].x;		
		cloud->points[i].y = my_vTxtPoints[i].y;		
		cloud->points[i].z = my_vTxtPoints[i].z;	
	}	
	pcl::io::savePCDFileASCII("C://Users//HEHE//Desktop//Chair.pcd", *cloud);	
	cout<< "从 Chair.txt读取" << cloud->points.size() << "点写入Chair.pcd" << endl;		
	//打印出写入的点    cout << "_________________________________" << endl;	
	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;
}

Txt format data is left as the right to convert the pcd file format.

2. For pcd file format conversion and then to a filtering process, in the choice algorithm filtering, personally feel different in their own area of ​​data collection, the purpose is not to achieve the same filtering algorithm selected should be different, but in the filter selection algorithm was quite confused, and I hope God can guide us big (QQ: 1753939345)

       The first filtering algorithm:VoxelGrid the filter sampling point cloud, (using the voxel grid implemented method of downsampling, i.e., reducing the number of data points to reduce the cloud point, while preserving the shape and the feature point clouds, to improve registration, surface reconstruction, shape velocity recognition algorithm is very practical, PCL VoxelGrid class is implemented to create a 3D voxel lattice point cloud data by the input, the other points in the voxel receiving each voxel by voxel center of gravity of all the dots to display the approximate , so that all points within the voxel are represented with a final center of gravity, the point cloud for all voxels after treatment was filtered, this method than with the central voxel (note center and the center of gravity slower method) approximation, However, the sampling points corresponding to the surface for more accurate representation.)

#include "pch.h"
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>


int
main(int argc, char** argv)
{

	pcl::PCLPointCloud2::Ptr cloud(new pcl::PCLPointCloud2());
	pcl::PCLPointCloud2::Ptr cloud_filtered(new pcl::PCLPointCloud2());

	//点云对象的读取
	pcl::PCDReader reader;

	reader.read("C://Users//HEHE//Desktop//Chair.pcd", *cloud);    //读取点云到cloud中

	std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height
		<< " data points (" << pcl::getFieldsList(*cloud) << ").";

	/******************************************************************************
	创建一个叶大小为1cm的pcl::VoxelGrid滤波器,
  **********************************************************************************/
	pcl::VoxelGrid<pcl::PCLPointCloud2> sor;  //创建滤波对象
	sor.setInputCloud(cloud);            //设置需要过滤的点云给滤波对象
	//sor.setLeafSize(0.01f, 0.01f, 0.01f);  //设置滤波时创建的体素体积为1cm的立方体
	sor.setLeafSize(10.0f, 10.0f, 10.0f);//该部分如果选择的体素体积太小,就会造成索引溢
//出,所以本人改大点。
	sor.filter(*cloud_filtered);           //执行滤波处理,存储输出

	std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height
		<< " data points (" << pcl::getFieldsList(*cloud_filtered) << ").";

	pcl::PCDWriter writer;
	writer.write("C://Users//HEHE//Desktop//Chair_downsampled.pcd", *cloud_filtered,
		Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), false);

	return (0);
}

 

Left original pattern data collection Chair right is sampled after filtering via the data drop is to save data I are introduced into CouldCompare of view:

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

//statisticalOutlierRemoval滤波器移除离群点
#include "pch.h"
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>

int
main(int argc, char** argv)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);

	// 定义读取对象
	pcl::PCDReader reader;
	// 读取点云文件
	reader.read<pcl::PointXYZ>("C://Users//HEHE//Desktop//Chair.pcd", *cloud);

	std::cerr << "Cloud before filtering: " << std::endl;
	std::cerr << *cloud << std::endl;

	// 创建滤波器,对每个点分析的临近点的个数设置为50 ,并将标准差的倍数设置为1  这意味着如果一
	 //个点的距离超出了平均距离一个标准差以上,则该点被标记为离群点,并将它移除,存储起来
	pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;   //创建滤波器对象
	sor.setInputCloud(cloud);                           //设置待滤波的点云
	sor.setMeanK(50);                               //设置在进行统计时考虑查询点临近点数
	sor.setStddevMulThresh(1.0);                      //设置判断是否为离群点的阀值
	sor.filter(*cloud_filtered);                    //存储

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

	pcl::PCDWriter writer;
	writer.write<pcl::PointXYZ>("C://Users//HEHE//Desktop//Chair_inliers.pcd", *cloud_filtered, false);

	sor.setNegative(true);
	sor.filter(*cloud_filtered);
	writer.write<pcl::PointXYZ>("C://Users//HEHE//Desktop//Chair_outliers.pcd", *cloud_filtered, false);

	return (0);
}

在运行该代码时可能会出现一个错误:

解决方案如下:https://github.com/mariusmuja/flann/issues/386

找到你自己的dist.h文件,修改方案为:将该条语句放置在#if之前即可。

In order to fix the issues and get my program and the PCL libraries working correctly I had to move the "typedef unsigned long long pop_t;" outside the #if and #else so that either one will use the parameter to do the math. I don't know if this was the intent of this code but in order to progress in my software application I needed this error fixed. Please fix this as soon as possible and let me know so I can just update the flann and not worry about it.

上述代码运行结果:

    第3:从一个点云中提取索引,基于某一分割算法提取点云中的一个子集:

//基于某一分割算法提取点云中的一个子集
#include "pch.h"
#include <iostream>
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/extract_indices.h>

int
main(int argc, char** argv)
{

	/**********************************************************************************************************
	 从输入的.PCD 文件载入数据后,创建一个VOxelGrid滤波器对数据进行下采样,在这里进行下才样是为了加速处理过程,
	 越少的点意味着分割循环中处理起来越快
	 **********************************************************************************************************/

	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>);

	// 读取PCD文件
	pcl::PCDReader reader;
	reader.read("C://Users//HEHE//Desktop//Chair.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.setLeafSize(8.0f, 8.0f, 8.0f);    // 设置采样体素大小
	sor.filter(*cloud_filtered_blob);        //保存

	// 转换为模板点云
	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<pcl::PointXYZ>("C://Users//HEHE//Desktop//CCChair_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);                      //判断是否为模型内点的距离阀值

	// 设置ExtractIndices的实际参数
	pcl::ExtractIndices<pcl::PointXYZ> extract;        //创建点云提取对象

	int i = 0, nr_points = (int)cloud_filtered->points.size();
	// While 30% of the original cloud is still there
	while (cloud_filtered->points.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 the inliers
		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);
}

 

程序运行截图:

左边对应原始图,右边对应提取图。

 

 

发布了28 篇原创文章 · 获赞 4 · 访问量 1万+

Guess you like

Origin blog.csdn.net/m0_37957160/article/details/98587673