PCL 在没有云副本的八叉树上应用过滤器
Posted
技术标签:
【中文标题】PCL 在没有云副本的八叉树上应用过滤器【英文标题】:PCL apply filter on octree without cloud copy 【发布时间】:2018-11-12 16:02:27 【问题描述】:我有巨大的点云,我想在上面应用 voxelGrid。但由于点云太大,出现"[pcl::VoxelGrid::applyFilter] Leaf size is too small for the input dataset. Integer indices would overflow"
之类的错误。所以我想先从我的点云构建一个八叉树,然后在每个叶子上应用过滤器(即在具有良好索引的点云上应用过滤器)
问题出现在这里,当我应用过滤器时,PCL 要我选择一个将保存它的点云,并将原始点云替换为过滤器的结果。我想知道是否可以修改过滤器,使其不删除点,而只将必须删除的点云中索引处的点放入(0,0,0)?
我的代码:
void Octree::applyExample(float x, float y, float z)
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
// Fill in the cloud data
cloud->width = 100000;
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 + 1.0f);
cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
octree.setInputCloud(cloud);
octree.addPointsFromInputCloud();
pcl::octree::OctreePointCloud<pcl::PointXYZRGB>::LeafNodeIterator it;
pcl::octree::OctreePointCloud<pcl::PointXYZRGB>::LeafNodeIterator it_end = octree.leaf_end();
for (it = octree.leaf_begin(); it != it_end; ++it)
pcl::IndicesPtr indexVector(new vector<int>);
pcl::octree::OctreeContainerPointIndices& container = it.getLeafContainer();
container.getPointIndices(*indexVector);
FILTREexample(cloud, indexVector, x, y, z);
和过滤器:
void FILTREexample(pcl::PointCloud<pcl::PointXYZ>::Ptr pointcloud, pcl::IndicesPtr indices, float x, float y, float z)
pcl::VoxelGrid<pcl::PointXYZ> sor;
sor.setInputCloud(pointcloud);
sor.setIndices(indices);
sor.setLeafSize(x, y, z);
sor.filter(*pointcloud); //The problem occurs here
//Everytime, the pointcloud is substituted with the result of the filter, but I'd like to still have my "entire" pointcloud, but either with the filtered point deleted, or the filtered point put to 0,0,0.
这样的事情有可能吗?
【问题讨论】:
【参考方案1】:据我所知,没有“pcl”方法可以做到这一点。您应该自己进行一些编码以获得您期望的结果。想到的另一种选择是:您可以将来自体素过滤器的结果(过滤)点云添加到输入参数pointcloud
中,如下所示。这基本上会使您的原始点云膨胀并可能导致速度变慢,因为点云的点存储在std::vector<T>
中,并且调整此容器的大小很昂贵。
...
typedef pcl::PointCloud<pcl::PointXYZ> PC_t;
PC_t::Ptr temp_pc(new PC_t());
// Your voxel grid filter code ...
// ...
sor.filter(temp_pc);
for(auto& p : temp_pc->points)
pointcloud->push_back(p);
一旦applyExample(...)
函数中的循环完成,您将拥有所有初始点和体素过滤点。然后您可以使用pcl::ExtractIndices<T>
过滤器删除原始点云中的所有点(即cloud
)。请注意,您知道一开始有多少点,因此您知道将哪些索引传递给ExtractIndices
。您还应该注意,删除循环内中的点将使您的八叉树无效,这就是必须推迟删除点的原因。请查看 [1] 了解如何使用 pcl::ExtractIndices<T>
。
这只是一种方法,可能是获得您想要的结果的效率最低的方法之一。将另一个点云传递给您的 FILTREexample()
函数,您将在该函数上累积 temp_pc
中的点可能有助于加快速度。但是,这里的重点是 PCL 中没有像 filterAndAppend(...)
这样的方法。
[1]http://pointclouds.org/documentation/tutorials/extract_indices.php
【讨论】:
非常感谢您的回答。我现在明白了,不可能实现我想要的。我可能不得不找到另一种方法:(【参考方案2】:您的原始点云正在被替换,因为这正是您“告诉”PCL 要执行的操作:sor.filter(*pointcloud);
filter 方法的参数是“输出云”。您可以传递一个空云,过滤结果将保存到其中。 (输入已经通过setInputCloud
定义)
因此您可以将 FILTERExamples 重写为:
pcl::PointCloud<pcl::PointXYZ>::Ptr FILTREexample(pcl::PointCloud<pcl::PointXYZ>::Ptr pointcloud, pcl::IndicesPtr indices, float x, float y, float z)
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered_pointcloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::VoxelGrid<pcl::PointXYZ> sor;
sor.setInputCloud(pointcloud);
sor.setIndices(indices);
sor.setLeafSize(x, y, z);
sor.filter(*filtered_pointcloud); // No problem :)
return filtered_pointcloud;
而 applyExample 只会连接 clouds:
void Octree::applyExample(float x, float y, float z)
... // no change
pcl::PointCloud<pcl::PointXYZ>::Ptr filtered_cloud(new pcl::PointCloud<pcl::PointXYZ>);
for (it = octree.leaf_begin(); it != it_end; ++it)
pcl::IndicesPtr indexVector(new vector<int>);
pcl::octree::OctreeContainerPointIndices& container = it.getLeafContainer();
container.getPointIndices(*indexVector);
*filtered_cloud += *FILTREexample(cloud, indexVector, x,y,z);
【讨论】:
非常感谢!这证实了我必须在某处创建一个带有过滤点的副本。我得另寻出路。 只是一个小错误,是*filtered_cloud += *FILTREexample(cloud, indexVector, x,y,z)
:)以上是关于PCL 在没有云副本的八叉树上应用过滤器的主要内容,如果未能解决你的问题,请参考以下文章