Attention

You are viewing an older version of the documentation. The latest version is 2.2.

Estimating Surface Normals in a PointCloud

In this tutorial we will learn how to get the surface normals of each point in the cloud.

Note

This tutorial can be run both inside and outside a Docker* image. We assume that the pcl-oneapi-tutorial Deb package has been installed, and the user has copied the tutorial directory from /opt/intel/pcl/oneapi/tutorials/ to a user-writable directory.

  1. Prepare the environment:

    cd <path-to-oneapi-tutorials>/normal_estimation
    
    Copy to clipboard
  2. oneapi_normal_estimation.cpp should be in the directory with following content:

     1#include <pcl/io/pcd_io.h>
     2#include <pcl/oneapi/features/normal_3d.h>
     3#include <pcl/oneapi/kdtree/kdtree_flann.h>
     4#include <pcl/oneapi/point_cloud.h>
     5
     6int main (int argc, char** argv)
     7{
     8  int k = 10;
     9  float radius = 0.01;
    10
    11  std::cout << "Running on device: " << dpct::get_default_queue().get_device().get_info<sycl::info::device::name>() << "\n";
    12
    13  // load point cloud
    14  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr( new pcl::PointCloud<pcl::PointXYZ>() );
    15
    16  int result = pcl::io::loadPCDFile("bun0.pcd", *cloud_ptr);
    17  if (result != 0)
    18  {
    19    pcl::console::print_info ("Load pcd file failed.\n");
    20    return result;
    21  }
    22
    23  // estimate normals with knn search
    24  pcl::oneapi::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
    25  ne.setSearchMethod (pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>::Ptr (new pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>));
    26  ne.setInputCloud(cloud_ptr);
    27  ne.setKSearch(k);
    28
    29  // save normal estimation to CPU memory point cloud
    30  pcl::PointCloud<pcl::Normal>::Ptr normals_knn(new pcl::PointCloud<pcl::Normal>);
    31  ne.compute(*normals_knn);
    32
    33  std::cout << "normals_knn.size (): " << normals_knn->size () << std::endl;
    34
    35  // estimate normals with radius search
    36  ne.setSearchMethod (pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>::Ptr (new pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>));
    37  ne.setInputCloud(cloud_ptr);
    38  ne.setRadiusSearch(radius);
    39  ne.setKSearch(0);
    40
    41  // save normal estimation output to device shared memory point cloud
    42  pcl::oneapi::PointCloudDev<pcl::Normal>::Ptr normals_radius(new pcl::oneapi::PointCloudDev<pcl::Normal>) ;
    43  ne.compute(*normals_radius);
    44
    45  std::cout << "normals_radius.size (): " << normals_radius->size () << std::endl;
    46
    47  return 0;
    48}
    
    Copy to clipboard
  3. Source the Intel® oneAPI Base Toolkit environment:

    source /opt/intel/oneapi/setvars.sh
    
    Copy to clipboard
  4. (Optional) Setup proxy setting to download test data:

    export http_proxy="http://<http_proxy>:port"
    export https_proxy="http://<https_proxy>:port"
    
    Copy to clipboard
  5. Build the code:

    mkdir build && cd build
    cmake ../
    make -j
    
    Copy to clipboard
  6. Run the binary:

    ./oneapi_normal_estimation
    
    Copy to clipboard
  7. Expected results example:

    normals_knn.size (): 397
    normals_radius.size (): 397
    
    Copy to clipboard

Code Explanation

The example PCD is initially loaded into a PointCloud<PointXYZ>.

  // load point cloud
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr( new pcl::PointCloud<pcl::PointXYZ>() );

  int result = pcl::io::loadPCDFile("bun0.pcd", *cloud_ptr);
  if (result != 0)
  {
    pcl::console::print_info ("Load pcd file failed.\n");
    return result;
  }
Copy to clipboard

This tutorial includes two normal estimation processes: KNN search and radius search. The initial step involves adjusting the parameters for normal estimation in the KNN search.

  // estimate normals with knn search
  pcl::oneapi::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
  ne.setSearchMethod (pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>::Ptr (new pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>));
  ne.setInputCloud(cloud_ptr);
  ne.setKSearch(k);
Copy to clipboard

Normal estimation is then executed.

  pcl::PointCloud<pcl::Normal>::Ptr normals_knn(new pcl::PointCloud<pcl::Normal>);
  ne.compute(*normals_knn);
Copy to clipboard

The parameters for normal estimation are modified for the radius search.

  // estimate normals with radius search
  ne.setSearchMethod (pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>::Ptr (new pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>));
  ne.setInputCloud(cloud_ptr);
  ne.setRadiusSearch(radius);
  ne.setKSearch(0);
Copy to clipboard

Normal estimation is performed once more.

  // save normal estimation output to device shared memory point cloud
  pcl::oneapi::PointCloudDev<pcl::Normal>::Ptr normals_radius(new pcl::oneapi::PointCloudDev<pcl::Normal>) ;
  ne.compute(*normals_radius);
Copy to clipboard