Reputation: 538
I have huge point cloud, and I want to apply voxelGrid on it. But since the point cloud is too big, I have error such as "[pcl::VoxelGrid::applyFilter] Leaf size is too small for the input dataset. Integer indices would overflow"
. So I wanted to build an octree first from my pointcloud, and then apply the filter on each leaf (i.e apply the filter on the pointcloud with the good index)
The problem occurs here, when I apply the filter, PCL wants me to chose a PointCloud in which it will be saved, and the original point cloud is substituted with the result of the filter. I would like to know if it is possible to modify the filter so that it doesn't remove the points, but only put to (0,0,0) the points at the index in the pointcloud that must be removed?
My code :
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);
}
}
and filter :
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.
}
Would it be possible to do such a thing?
Upvotes: 0
Views: 2817
Reputation: 2180
Your original point cloud is being substituted because it is exactly what you "told" PCL to do by writing: sor.filter(*pointcloud);
The argument to the filter method is the "output cloud". You can pass an empty cloud and the filter result will be saved into it. (the input was already defined via setInputCloud
)
So you can rewrite your FILTERExamples as:
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;
}
And applyExample will just concatenate the 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);
}
}
Upvotes: 2
Reputation: 144
To my knowledge, there is no "pcl" way of doing this. You should do some coding yourself to get the results you expect. One alternative that comes to mind is : You can add the resultant (filtered) point cloud from the voxel filter into the input argument pointcloud
as below. This will basically inflate your original point cloud and may cause slow down since points of a point cloud is stored in a std::vector<T>
and it is expensive to resize this container.
...
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);
Once the loop in your applyExample(...)
function completes, you will have all the initial points and voxel-filtered points. You can then use pcl::ExtractIndices<T>
filter to remove all the points in the original point cloud (i.e. cloud
). Please note that you know how many points you had at the very beginning hence you know which indices to pass to ExtractIndices
. You should also note that removing the points within the loop will invalidate your octree, which is why removal of points has to be deferred. Please check [1] to see how pcl::ExtractIndices<T>
is used.
This is just one way, and possibly one of the least efficient ways, of getting the result you want. Passing another point cloud to your FILTREexample()
function onto which you will accumulate the points in temp_pc
might help speeding-up a bit. However, the main point here is that there is no method in PCL like filterAndAppend(...)
.
[1] http://pointclouds.org/documentation/tutorials/extract_indices.php
Upvotes: 1