davidcaron / pclpy

Python bindings for the Point Cloud Library (PCL)
MIT License
428 stars 59 forks source link

getRemovedIndices returns empty Int vector #15

Closed ruoyu0088 closed 6 years ago

ruoyu0088 commented 6 years ago

I want to call getRemovedIndices() to get the index of removed points:

from pclpy import pcl
import numpy as np
arr = np.random.randn(30, 3).astype(np.float32)
cloud = pcl.PointCloud.PointXYZ.from_array(arr)
cloud_filtered = pcl.PointCloud.PointXYZ()
pas = pcl.filters.PassThrough.PointXYZ()
pas.setInputCloud(cloud)
pas.setFilterFieldName("z")
pas.setFilterLimits(0, 1)
pas.filter(cloud_filtered)
print(pas.getRemovedIndices())

but the result is Int[].

davidcaron commented 6 years ago

It seems the problem is with the filter method when given a point cloud as parameter.

If you give an Int vector to the filter method, it works:

# this is the same as before
from pclpy import pcl
import numpy as np
arr = np.random.randn(30, 3).astype(np.float32)
cloud = pcl.PointCloud.PointXYZ.from_array(arr)
cloud_filtered = pcl.PointCloud.PointXYZ()
pas = pcl.filters.PassThrough.PointXYZ()
pas.setInputCloud(cloud)
pas.setFilterFieldName("z")
pas.setFilterLimits(0, 1)

# passing a pcl.vectors.Int() to filter() is a workaround...
indices = pcl.vectors.Int()
pas.filter(indices)
print(indices)

But the filter function should work with a point cloud, so this is a bug.

davidcaron commented 6 years ago

Ok, I figured it out. It's a simple PCL flag that wasn't set: extract_removed_indices=True

from pclpy import pcl
import numpy as np
arr = np.random.randn(30, 3).astype(np.float32)
cloud = pcl.PointCloud.PointXYZ.from_array(arr)
cloud_filtered = pcl.PointCloud.PointXYZ()
pas = pcl.filters.PassThrough.PointXYZ(extract_removed_indices=True)  # only this line changed
pas.setInputCloud(cloud)
pas.setFilterFieldName("z")
pas.setFilterLimits(0, 1)
pas.filter(cloud_filtered)
print(pas.getRemovedIndices())

Also, you could do the same thing using numpy logic, but keep in mind this should be slightly slower:

from pclpy import pcl
import numpy as np
arr = np.random.randn(30, 3).astype(np.float32)
cloud = pcl.PointCloud.PointXYZ(arr)
xyz = cloud.xyz

indices = np.where(np.logical_and(xyz[:, 2] > 0, xyz[:, 2] < 1))[0]
print(indices)

# and create a new cloud if necessary
cloud_filtered = pcl.PointCloud.PointXYZ(xyz[indices])