基于 PCL 体素滤波的改进滤波算法

144 阅读1分钟

改进介绍

PCL 中的体素滤波通过将点云数据划分为体素网格,用每个体素网格中所有点的重心近似表示体素中的其他点,从而减少点云的密度。所以体素滤波后的点并非原始点云中的点,可能导致点云特征丢失。这里的改进是指用原始点云中距离体素重心点最近的点作为体素网格中所有点的代表, 以此确保采样点在原始点云中的代表性。

代码实现

首先对点云进行体素滤波,对于滤波后的每一个点,利用 KD 树找到距其最近的原始点云中的点。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <sstream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/kdtree/kdtree_flann.h>


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

	pcl::io::loadPCDFile("C:\\Users\\10704\\Desktop\\dezhou1\\原始数据\\dezhou1_1-3_z_passThrough.pcd", *cloud);

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

	// -------------体素滤波-------------
	pcl::VoxelGrid<pcl::PointXYZ> sor;
	sor.setInputCloud(cloud);
	sor.setLeafSize(0.05f, 0.05f, 0.05f);	// 设置栅格体素的大小  
	pcl::PointCloud<pcl::PointXYZ> ::Ptr voxel_filtered(new pcl::PointCloud<pcl::PointXYZ>);
	sor.filter(*voxel_filtered);

	// -----------K最近邻搜索------------
	// 根据下采样的结果,选择距离采样点最近的点作为最终的下采样点
	pcl::KdTreeFLANN<pcl::PointXYZ> kdtree;
	kdtree.setInputCloud(cloud);
	// 采样后根据最邻近点提取的样本点下标索引
	pcl::PointIndicesPtr inds = std::shared_ptr<pcl::PointIndices>(new pcl::PointIndices());
	for (size_t i = 0; i < voxel_filtered->points.size(); i++) 
	{
		pcl::PointXYZ searchPoint;
		searchPoint.x = voxel_filtered->points[i].x;
		searchPoint.y = voxel_filtered->points[i].y;
		searchPoint.z = voxel_filtered->points[i].z;

		int K = 1;	// 最近邻搜索
		std::vector<int> pointIdxNKNSearch(K);
		std::vector<float> pointNKNSquaredDistance(K);
		if (kdtree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0) 
		{
			inds->indices.push_back(pointIdxNKNSearch[0]);
		}

	}
	pcl::PointCloud<pcl::PointXYZ>::Ptr final_filtered(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::copyPointCloud(*cloud, inds->indices, *final_filtered);
	std::cout << "the number of final downsampling cloud " << final_filtered->points.size() << std::endl;

	
	pcl::io::savePCDFile("C:\\Users\\10704\\Desktop\\dezhou1\\原始数据\\dezhou1_1-3_z_passThrough_downsample.pcd", *final_filtered);

	system("pause");
	return (0);
}