Surface Reconstruction with Intel® oneAPI Base Toolkit's Moving Least Squares (MLS)#
MLS creates a 3D surface from a point cloud through either down-sampling or up-sampling. Intel® oneAPI Base Toolkit's MLS is based on the original MLS API. Differences between the two:
Intel® oneAPI Base Toolkit's MLS calculates with 32-bit float instead of 64-bit double.
Intel® oneAPI Base Toolkit's MLS’s surface is constructed as a set of indices grouped into multiple blocks. This consumes more system memory than the original version. Control the block size with
setSearchBlockSize
.Intel® oneAPI Base Toolkit's MLS improves the performance of all up-sampling methods.
The Intel® oneAPI Base Toolkit namespace must be appended to the original MovingLeastSquares class.
See resampling.rst for details.
This tutorial shows how to use these optimizations inside a Docker* image. For the same functionality outside of Docker* images, see PCL Optimizations Outside of Docker* Images.
Prepare the environment:
cd <edge_insights_for_amr_path>/Edge_Insights_for_Autonomous_Mobile_Robots_<version>/AMR_containers ./run_interactive_docker.sh eiforamr-full-flavour-sdk:2023.1 root -c full_flavor mkdir mls && cd mls
Create the file
oneapi_mls.cpp
:vim oneapi_mls.cpp
Place the following inside the file:
#include <pcl/oneapi/surface/mls.h> #include <pcl/oneapi/search/kdtree.h> #include <pcl/point_types.h> #include <pcl/io/pcd_io.h> using namespace pcl::oneapi; int main (int argc, char** argv) { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr( new pcl::PointCloud<pcl::PointXYZ>() ); // Load bun0.pcd -- should be available with the PCL archive in test pcl::io::loadPCDFile (argv[1], *cloud_ptr); pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>::Ptr tree (new pcl::oneapi::KdTreeFLANN<pcl::PointXYZ>); // Output has the PointNormal type in order to store the normals calculated by MLS pcl::PointCloud<pcl::PointNormal> mls_points; // Init object (second point type is for the normals, even if unused) pcl::oneapi::MovingLeastSquares<pcl::PointXYZ, pcl::PointNormal> mls; mls.setComputeNormals (true); // Set parameters mls.setInputCloud (cloud_ptr); mls.setPolynomialOrder (2); mls.setSearchMethod (tree); mls.setSearchRadius (0.03); // Reconstruct mls.process (mls_points); // Save output pcl::io::savePCDFile ("bun0-mls.pcd", mls_points); }
Create a CMakeLists.txt file:
vim CMakeLists.txt
Place the following inside the file:
cmake_minimum_required(VERSION 3.5 FATAL_ERROR) set(target oneapi_mls) set(CMAKE_CXX_COMPILER dpcpp) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_FLAGS "-Wall -Wpedantic -Wno-unknown-pragmas -Wno-pass-failed -Wno-unneeded-internal-declaration -Wno-unused-function -Wno-gnu-anonymous-struct -Wno-nested-anon-types -Wno-extra-semi -Wno-unused-local-typedef -fsycl -fsycl-unnamed-lambda -ferror-limit=1") project(${target}) find_package(PCL 1.12 REQUIRED) find_package(PCL-ONEAPI 1.12 REQUIRED) include_directories(${PCL_INCLUDE_DIRS} ${PCL-ONEAPI_INCLUDE_DIRS}) link_directories(${PCL_LIBRARY_DIRS} ${PCL-ONEAPI_LIBRARY_DIRS}) add_definitions(${PCL_DEFINITIONS} ${PCL-ONEAPI_DEFINITIONS}) add_executable (${target} oneapi_mls.cpp) target_link_libraries (${target} sycl pcl_oneapi_containers pcl_oneapi_surface pcl_oneapi_kdtree ${PCL_LIBRARIES})
Source the Intel® oneAPI Base Toolkit environment:
export PATH=/home/eiforamr/workspace/lib/pcl/share/pcl-1.12:/home/eiforamr/workspace/lib/pcl/share/pcl-oneapi-1.12:$PATH source /opt/intel/oneapi/setvars.sh
Build the code:
cd /home/eiforamr/workspace/mls/ mkdir build && cd build cmake ../ make -j
Download the test data from GitHub*:
wget https://raw.githubusercontent.com/PointCloudLibrary/pcl/master/test/bun0.pcd # if the binary is not downloaded try setting the proxies first and try again: export http_proxy="http://<http_proxy>:port" export https_proxy="http://<https_proxy>:port"
Run the binary:
./oneapi_mls ./bun0.pcd
To see the smoothed cloud (zoom out to see the reconstructed shape):
/home/eiforamr/workspace/lib/pcl/bin/pcl_viewer bun0-mls.pcd
Code Explanation#
Intel® oneAPI Base Toolkit's MLS requires this header.
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
Load the test data from GitHub* into a PointCloud<PointXYZ> (these fields are mandatory; other fields are allowed and preserved).
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr( new pcl::PointCloud<pcl::PointXYZ>() );
// Load bun0.pcd -- should be available with the PCL archive in test
pcl::io::loadPCDFile (argv[1], *cloud_ptr);
If normal estimation is required:
mls.setComputeNormals (true);
Append the Intel® oneAPI Base Toolkit namespace to the original MovingLeastSquares class. The first template type is for the input and output cloud. Only the XYZ dimensions of the input are smoothed in the output.
pcl::oneapi::MovingLeastSquares<pcl::PointXYZ, pcl::PointNormal> mls;
The maximum polynomial order is five. See the code API (pcl:MovingLeastSquares) for default values and additional parameters to control the smoothing process.
mls.setPolynomialOrder (2);
If the normal and original dimensions need to be in the same cloud, the fields have to be concatenated.
// Save output
pcl::io::savePCDFile ("bun0-mls.pcd", mls_points);