04 April 2013

PCL - point cloud filtering

Filtering a point cloud using a Pass Through filter:
In PCL, there is a basic filter class for point cloud filtering along specified dimension. Here is a snippet of example code:
int main (int argc, char** argv)
{
 pcl::PointCloud::Ptr cloud (new pcl::PointCloud);
 pcl::PointCloud::Ptr cloud_filtered (new pcl::PointCloud);

 // Fill in the cloud data here


 // Create the filtering object
 pcl::PassThrough pass;
 pass.setInputCloud (cloud);
 pass.setFilterFieldName ("y");
 pass.setFilterLimits (0.0, 500.0);
 //pass.setFilterLimitsNegative (true);
 pass.filter (*cloud_filtered);

 return (0);
}
Above codes will filter the points whose y axis is outside boundary of 0.0 to 500.0.
From these two lines we can configure which axis and what limit for the filter.
 pass.setFilterFieldName ("z");
 pass.setFilterLimits (0.0, 100.0);
If we want to filter the points inside the interval (i.e. keep points outside the min & max limit), then just simply set the function "setFilterLimits" to true:
 pass.setFilterLimitsNegative (true);

---
Removing outliers using a StatisticalOutlierRemoval filter:
There are always noises in point cloud constructed from Kinect due to varying IR light received and measurement errors. The noises may complicate the estimation of local point cloud characteristics such as surface normals and curvature changes. This might lead to registration failure. We can apply statistical analysis on each point's neighborhood and filtering the points which do not meet a certain criteria. PCL provides filter to remove outliers whose mean distances to their own neighbors are outside an interval defined by global distances mean and standard deviation.
Here is the code:
int main (int argc, char** argv)
{
 pcl::PointCloud::Ptr cloud (new pcl::PointCloud);
 pcl::PointCloud::Ptr cloud_filtered (new pcl::PointCloud);

 // Fill in the cloud data
 pcl::PCDReader reader;
 // Read input point cloud
 reader.read ("table_scene_lms400.pcd", *cloud);

 std::cerr << "Cloud before filtering: " << std::endl;
 std::cerr << *cloud << std::endl;
 // Visualise input cloud
 pcl::visualization::CloudViewer viewer ("Input");
 viewer.showCloud(cloud);
 while (!viewer.wasStopped()){}

 // Create the filtering object
 pcl::StatisticalOutlierRemoval sor;
 sor.setInputCloud (cloud);
 sor.setMeanK (10);
 sor.setStddevMulThresh (1.0);
 sor.filter (*cloud_filtered);

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

 // Visualise output cloud
 pcl::visualization::CloudViewer viewer1 ("Output");
 viewer1.showCloud(cloud_filtered);
 while (!viewer1.wasStopped()){}

 return (0);
}
The function:
 sor.setMeanK (10);
set the number of points (k) to use for mean distance estimation. For larger k, the points lay within larger outlier area will be removed. If k is too big, the correct points with low density may be removed incorrectly. For small k, some outliers which are noises may not be removed.
Another function:
 sor.setStddevMulThresh (1.0);
means that all points who have a distance larger than 1 s.d. of the mean distance to the query point will be removed.
---
Downsampling a point cloud using a VoxelGrid filter:
Since the model extracted from Kinect still contains many redundant points which lead to unnecessary computation. For real-time shape model application, downsampling such dense point cloud while remain the vertices variation of the model shape is needed to be done very fast.
int main (int argc, char** argv)
{
 pcl::PointCloud::Ptr cloud (new pcl::PointCloud);
 pcl::PointCloud::Ptr cloud_filtered (new pcl::PointCloud);

 // Fill in the cloud data
 pcl::PLYReader reader;
 // Replace the path below with the path where you saved your file
 reader.read ("bodyModel.ply", *cloud); // Remember to download the file first!

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

 // Create the filtering object
 pcl::VoxelGrid sor;
 sor.setInputCloud (cloud);
 sor.setLeafSize (0.01f, 0.01f, 0.01f);
 sor.filter (*cloud_filtered);

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

 pcl::io::savePLYFileBinary("bodyModelfiltered.ply",*cloud_filtered);


 return (0);
}
The function setLeafSize can control the resolution of filtered cloud in xyz direction. For larger value the resolution will be worse.
Here is a figure shows the model before and after downsampling:
Figure 1 Result of downsampling, input model (left) and filtered model (middle & right). Middle one used leaf size of 0.01 while right one used leaf size of 0.005.
From the left to middle one, the number of point of the model is reduced from 123999 to 6120. The program can be finished almost immediately.

1 comment:

  1. Much appreciated for giving astonishing article. Digital pointcloud Vancouver, BC employments 3D laser checking innovation to donate you an exact show of existing resources through the total life cycle of your venture.

    ReplyDelete