[PCL self-study: Filtering] Introduction and use of various filters in PCL (continuous update)

Posted by teebo on Mon, 14 Feb 2022 18:16:34 +0100

1. PassThrough filter: for threshold filtering

1. Introduction of Straight-pass Filter

PassThrough filters, as the name implies, use a threshold to directly filter out filters that do not meet the threshold. For example, if there are 100,000 numbers with values ranging from 1 to 100,000 and the pass filter has a threshold value of <50, then all numbers >=50 in the 100,000 numbers will be discarded after the pass filter has been filtered, leaving only those numbers that meet the threshold value.

2. Sample Code

First, create a file in the editor, such as pass. CPP and put the following into it, see the comments for code analysis.

#include <iostream>
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>

int main ()
 {
	// Original Point Cloud Pointer
   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
   // Filtered Point Cloud Pointer
   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);

  // Set point cloud as disordered point cloud with 5 points
  cloud->width  = 5;
  cloud->height = 1;
  cloud->points.resize (cloud->width * cloud->height);

  for (auto& point: *cloud) //Random generation of point coordinates
  {
    point.x = 1024 * rand () / (RAND_MAX + 1.0f);
    point.y = 1024 * rand () / (RAND_MAX + 1.0f);
    point.z = 1024 * rand () / (RAND_MAX + 1.0f);
  }
  // Output Created Points
  std::cerr << "Cloud before filtering: " << std::endl;
  for (const auto& point: *cloud)
    std::cerr << "    " << point.x << " "
                        << point.y << " "
                        << point.z << std::endl;
/*
* The following code creates a PassThrough filter object and sets its parameters.
* The filter field name is set to z-coordinate.
* Accepted interval value is set to (0.0; 1.0).
*/


  // Create Filter Object
   pcl::PassThrough<pcl::PointXYZ> pass;
   pass.setInputCloud (cloud);		// Fill in data
   pass.setFilterFieldName ("z");   // Set the dimension name to filter, where is the z-direction dimension
   pass.setFilterLimits (580.0, 900); // Setting filter threshold
  //pass.setFilterLimitsNegative (true);
  pass.filter (*cloud_filtered);    // Start Filtering
  
 // Points filtered by output
  std::cerr << "Cloud after filtering: " << std::endl;
  for (const auto& point: *cloud_filtered)
    std::cerr << "    " << point.x << " "
                        << point.y << " "
                        << point.z << std::endl;

  return (0);
}

Filter effect: Green is the point within the threshold (580,900), and red is the point being filtered. When the setFilterLimitsNegative parameter is set to True, point clouds within (Z<580 | Z > 900) are selected.

2. VoxelGrid filter: for downsampling

1. Introduction of voxel filters

VoxelGrid filters are often used to reduce the number of point clouds, i.e. point cloud subsampling. It can be analogous to image pyramid down sampling. As the name implies, point clouds are divided into voxels (spatial grids) in three dimensions, and the point clouds within each voxel are replaced by a point using a mathematical method to reduce the number of point clouds.
Official explanation:
_VoxelGrid method: The VoxelGrid class to be displayed creates a 3D voxel grid on the input point cloud data (think of the voxel grid as a set of miniature 3D boxes in space). Then, in each voxel (that is, the 3D frame), all the points that occur are approximated (that is, downsampled) to their centroids. This approach is slower than approaching them with voxel centers, but it represents the underlying surface more accurately.

2. Sample Code

First, download the dataset table_scene_lms400.pcd And save it somewhere on disk. I can't connect to github right now, so I'll use someone else's effect map instead.
Paste the following code into the editor and compile it.

 #include <iostream>
 #include <pcl/io/pcd_io.h>
 #include <pcl/point_types.h>
 #include <pcl/filters/voxel_grid.h>
 
 int
 main ()
 {
   pcl::PCLPointCloud2::Ptr cloud (new pcl::PCLPointCloud2 ());
  pcl::PCLPointCloud2::Ptr cloud_filtered (new pcl::PCLPointCloud2 ());

  // Create point cloud reader object
  pcl::PCDReader reader;
 // Replace the downloaded pcd file path with the following
  reader.read ("table_scene_lms400.pcd", *cloud); 

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

  // Create voxel filter object
  pcl::VoxelGrid<pcl::PCLPointCloud2> sor;
  sor.setInputCloud (cloud);
  //LeafSize is a voxel raster leaf size parameter, where each element represents the dimension of the voxel in the XYZ direction. The unit is m, where 0.01 represents one centimeter.
   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) << ")." << std::endl;
  //Create a point cloud writer to write filtered point clouds to a pcd file
  pcl::PCDWriter writer;
  writer.write ("table_scene_lms400_downsampled.pcd", *cloud_filtered, 
         Eigen::Vector4f::Zero (), Eigen::Quaternionf::Identity (), false);

  return (0);
}

The filtering effect is as follows:
Before voxel filtering:

Effect after voxel filtering:

3. Statistical Outlier Removal filter: for outlier filtering

1. Introduction of Statistical Outlier Filter

Statistical Outlier Removal filter, which uses statistical analysis techniques to remove noise measurements, such as outliers, from point cloud datasets, is often used to remove outliers (noise and noise).
_1.1 Background:
_Laser scanning usually produces point cloud datasets of different point densities. In addition, measurement errors can lead to sparse outliers, further damaging the results. This complicates the estimation of local point cloud features, such as surface normals or curvature changes, resulting in incorrect values, which can lead to point cloud registration failures. Some of these irregularities can be solved by statistical analysis of the neighborhood of each point and pruning those points that do not meet certain criteria. The outlier removal method is based on the distribution of the calculated distance from the point to the neighbor in the input dataset. For each point, the average distance from it to all its neighbors is calculated. Assuming that the resulting distribution is a Gaussian distribution with mean and standard deviation, all points whose mean distance is outside the interval defined by the global distance mean and standard deviation can be considered outliers and trimmed from the dataset.
The image below shows the effect of outlier analysis and removal: the original dataset on the left and the generated dataset on the right. The graph shows the average k-neighbor distance around a point before and after filtering.

2. Sample Code

_Still download the following datasets from github first table_scene_lms400_inliers.pcd . Then paste the following code into the compiler.

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>

 int
 main ()
 {
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);

  // Point cloud data
  pcl::PCDReader reader;
  // Replace the downloaded pcd file path with the following
  reader.read<pcl::PointXYZ> ("table_scene_lms400.pcd", *cloud);

  std::cerr << "Cloud before filtering: " << std::endl;
  std::cerr << *cloud << std::endl;

  // Create filter object sor
    pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
/* Parameter settings:
* The number of neighbors to be analyzed for each point is set to 50 and the standard deviation multiplier is 1.
* This means that all points farther than one standard deviation from the query point will be marked as outliers and deleted.
* Output is calculated and stored in cloud_ In filtered.
*/
  sor.setInputCloud (cloud);// Fill in point clouds
  sor.setMeanK (50);        // Setting the mean parameter K
  sor.setStddevMulThresh (1.0);// Set up
  sor.filter (*cloud_filtered);

  std::cerr << "Cloud after filtering: " << std::endl;
  std::cerr << *cloud_filtered << std::endl;
  // Output filtered point clouds to pcd format file
  pcl::PCDWriter writer;
  writer.write<pcl::PointXYZ> ("table_scene_lms400_inliers.pcd", *cloud_filtered, false);

  sor.setNegative (true); // When set to true, the condition becomes that all points less than one standard deviation from the query point will be marked as outliers and deleted, leaving behind those previously filtered.
  sor.filter (*cloud_filtered);
  writer.write<pcl::PointXYZ> ("table_scene_lms400_outliers.pcd", *cloud_filtered, false);

  return (0);
}

Conditional or Radius Outlier: for outlier filtering

1. Conditions and Radius Filters

[1] Conditional filter, as its name implies, gives a filter some conditional values, which can be one or more. Conditional filter can be used to filter all points that do not meet the criteria, and is often used for outlier filtering.
_In the sample code, we use adding two comparisons to the condition: greater than (GT) 0.0 and less than (LT) 0.8. This condition is then used to construct the filter.
[2] radius filter, as the name implies, filters given a specified radius and the minimum number of points within the radius, such as within a radius of 0.8, where the number of points is at least 2, that is, counts the number of points within each point radius, and less than this number is filtered, often used for outlier filtering.
Let's look directly at the code:
_The following figure can help us understand the role of RadiusOutlierRemoval filter objects. The user specified some neighborhood points, and each index must be within the specified radius parameter. For example, if a neighbor is specified, only yellow points will be removed from PointCloud. If two neighbors are specified, the yellow and green points will be removed from the PointCloud.

2. Sample Code

 #include <iostream>
 #include <pcl/point_types.h>
 #include <pcl/filters/radius_outlier_removal.h>
 #include <pcl/filters/conditional_removal.h>
 
 int
  main (int argc, char** argv)
 {
   if (argc != 2)
  {
    std::cerr << "please specify command line arg '-r' or '-c'" << std::endl;
    exit(0);
  }
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);

  // Randomly generate some point cloud data
  cloud->width  = 5;
  cloud->height = 1;
  cloud->resize (cloud->width * cloud->height);

  for (auto& point: *cloud)
  {
    point.x = 1024 * rand () / (RAND_MAX + 1.0f);
    point.y = 1024 * rand () / (RAND_MAX + 1.0f);
    point.z = 1024 * rand () / (RAND_MAX + 1.0f);
  }
// For user input-r, point clouds are filtered using a radius filter with a search radius of 0.8 and a minimum number of points of 2. After filtering, point clouds are kept organized (in order)
  if (strcmp(argv[1], "-r") == 0){
    pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
    // Setting filter parameters
    outrem.setInputCloud(cloud);
    outrem.setRadiusSearch(0.8);
    outrem.setMinNeighborsInRadius (2);
    outrem.setKeepOrganized(true);
    // Start filter
    outrem.filter (*cloud_filtered);
  }
  // If the user enters instruction-c, the conditional filter is enabled.
  else if (strcmp(argv[1], "-c") == 0){
  // Create the "condition" of a conditional filter and set the condition to two "comparison" filters. GT means greater than or equal to the point z>0 in this example. "LT" means less than, in this case, a point with z<0.8. Therefore, the filter retains points (0<z<0.8).
    pcl::ConditionAnd<pcl::PointXYZ>::Ptr range_cond (new
      pcl::ConditionAnd<pcl::PointXYZ> ());
    range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
      pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::GT, 0.0)));
    range_cond->addComparison (pcl::FieldComparison<pcl::PointXYZ>::ConstPtr (new
      pcl::FieldComparison<pcl::PointXYZ> ("z", pcl::ComparisonOps::LT, 0.8)));
    // Create a conditional filter to set the point cloud to remain organized (in order) after filtering
    pcl::ConditionalRemoval<pcl::PointXYZ> condrem;
    condrem.setCondition (range_cond);
    condrem.setInputCloud (cloud);
    condrem.setKeepOrganized(true);
    // Start Filtering
    condrem.filter (*cloud_filtered);
  }
  else{
    std::cerr << "please specify command line arg '-r' or '-c'" << std::endl;
    exit(0);
  }
  std::cerr << "Cloud before filtering: " << std::endl;
  for (const auto& point: *cloud)
    std::cerr << "    " << point.x << " "
                        << point.y << " "
                       << point.z << std::endl;
  // display pointcloud after filtering
  std::cerr << "Cloud after filtering: " << std::endl;
  for (const auto& point: *cloud_filtered)
    std::cerr << "    " << point.x << " "
                        << point.y << " "
                        << point.z << std::endl;
  return (0);
}

Summary:

This paper introduces the concepts and sample codes of pass filter, voxel filter, statistical outlier filter, radius filter and conditional filter. However, many filters are not introduced in PCL, such as CropHull filtering for arbitrary polygon interior point clouds (mostly used to write point cloud post-processing software for user interface interaction). The description here is simple, and the detailed description and experimental results can be used as reference. Senior Articles . After all the content learning is completed, prepare to write a point cloud post-processing software by yourself, use QT+PCL to achieve various point cloud post-processing functions, and then write a blog post about the writing process. Please look forward to it.

[Blogger Profile]
Stanford Rabbit, male, Master of Mechanical Engineering, Tianjin University. Since graduation, I have been engaged in optical three-dimensional imaging and point cloud processing. Since the three-dimensional processing library used in the work is an internal library of the company, which is not universally applicable, I learned the open source PCL library and its related mathematical knowledge for use. I would like to share the self-study process with you.
The blogger is ignorant and has no guidance yet. If you have any questions, please leave a message in the comments for your discussion.
If seniors have job opportunities to introduce you personally.

Topics: C++ PCL Algorithm Computer Vision Autonomous vehicles