这篇文章整理了常用PCL函数(用途、参数的意义,必要时也会列出该函数所在的头文件)以及一些其它关于PCL库的知识。

Empirical Observation

sort by alphabet.

pcl::Octree

adoptBoundingBoxToPoint

This function can adjust bounding box even the box has been defined manually.

defineBoundingBox

pcl::Octree::OctreePointCloud::defineBoundingBox: input bounding box will be used as initial bounding box first. Then the box will be adjusted to a cube. The adjusted bounding box always is different with the initial bounding box.

getIntersectedVoxelKeys
  • PCL uses a 3D variant of the Bresenham’s line algorithm or Amanatides and Woo’s voxel traversal algorithm. These algorithms traverse the octree in an efficient, grid-aligned manner.
  • The worst-case time complexity can be estimated as 𝑂(𝑛). Average case is 𝑂(𝑘+log𝑛), where 𝑘 is the number of intersected voxels. Best case is 𝑂 (log𝑛)(traversing a few nodes if the ray is short or only passes through a few voxels).
  • The returned value of pcl::Octree::getIntersectedVoxels is not guaranteed to be sorted by default.
getIntersectedVoxelCenters
pcl::octree::OctreePointCloudSearch::getIntersectedVoxelCenters(Eigen::Vector3f origin,
                                                                Eigen::Vector3f direction,
                                                                AlignedPointTVector& voxel_center_list,
                                                                int max_voxel_count);

whether normalize direction can influence the result.

  1. Best Case: $𝑂(log⁡(𝑁))$ In the ideal case, the octree is well-balanced, and the ray intersects only a small number of voxels, minimizing traversal.
  2. Average Case: $𝑂(𝑘+log(𝑁))$ Where 𝑘 is the number of voxels intersected by the ray. Traversing the octree to find the ray’s starting position is $𝑂(log⁡(𝑁))$, and processing intersected voxels depends on 𝑘.
  3. Worst Case: $𝑂(𝑘)$ If the ray intersects a large number of voxels (e.g., when the ray passes through the entire octree), the complexity is proportional to the number of intersected voxels.
radiusSearch

The distances are not necessarily sorted. If known in advance that radius 0.5 m always yields ~10 points, then radius search may be faster.

Set the resolution to be between r/2 and r, where r is your search radius.

Resolution Description Use When
search_radius Coarser tree, faster to build For very large datasets or many queries
search_radius/2 Balanced, good performance Recommended default
nearestKSearch

The KNN results are sorted by increasing distance.

getBoundingBox
getBoundingBox(min_x, min_y, min_z, max_x, max_y, max_z);
key

The key of a voxel is represented by a triple of integer values (𝑘𝑒𝑦_𝑥,𝑘𝑒𝑦_𝑦,𝑘𝑒𝑦_𝑧), which are discretized coordinates at a given octree depth.

  1. Moving along the X-axis Positive direction (+X): key_x increases by 1. Negative direction (-X): key_x decreases by 1.
  2. Moving along the Y-axis Positive direction (+Y): key_y increases by 1. Negative direction (-Y): key_y decreases by 1.
  3. Moving along the Z-axis Positive direction (+Z): key_z increases by 1. Negative direction (-Z): key_z decreases by 1.
leaf traversal

leaf_begin(): breadth-first leaf_depth_begin(): depth-first manner

pcl::PointCloud

Time complexity of makeShared is O(n).

pcl::ConcaveHull

#include <pcl/surface/concave_hull.h>
int main (int argc, char** argv)
{
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>), cloud_hull(new pcl::PointCloud<pcl::PointXYZ>);
  // load file to cloud
  pcl::ConcaveHull<pcl::PointXYZ> concave_hull;
  concave_hull.setInputCloud (cloud);
  concave_hull.setAlpha (0.1); // 设置alpha值,根据需要调整。决定凹包计算的紧密程度:较小的值会生成更紧密、更详细的轮廓,但可能会导致更多的小洞和碎片;较大的值会生成更平滑的轮廓。
  concave_hull.reconstruct (*cloud_hull);
}

pcl::MovingLeastSquares

Areas with more original points get more upsample.

一、基础知识

1. data()

2

三、位姿变换

#include <pcl/common/transforms.h> //主要内容为:表示位姿的几种方法之间的转换
//cloud_in和cloud_out为::Ptr点云指针; Matrix4f=Affine3f
void pcl::transformPointCloud(const *cloud_in, *cloud_out, const Eigen::Matrix4f  & transform)
2. pcl/common/eigen.h

4×4变换矩阵 transformation Eigen::Affine3f 仿射矩阵 –> pos和rpy 位置和角度 6D位姿 ;输入和输出参数为float

#include <pcl/common/eigen.h>

// 精度可能存在问题
pcl::getTranslationAndEulerAngles(imuOdomAffineLast, x, y, z, roll, pitch, yaw);

// 输入和输出参数为float
Eigen::Affine3f lastPoseInMapAff = pcl::getTransformation(x, y, z, roll, pitch, yaw);

四、匹配和配准

1. ndt.h

setTransformationEpsilon(ndt_epsilon_); // the transformation epsilon in order for an optimization to be considered as having converged to the final solution.
setStepSize(ndt_step_size_); // Set the newton line search maximum step length.
setResolution(ndt_resolution_); // Set the voxel grid resolution.
getFitnessScore(double max_range = std::numeric_limits<double>::max()); // Obtain the Euclidean fitness score (e.g., mean of squared distances from the source to the target)

2. pcl/kdtree/kdtree_flann.h

#include <pcl/kdtree/kdtree_flann.h>
// max_nn: num of returned points, if max_nn==0, return all.
kdtreeSurroundingKeyPoses->radiusSearch(point, radius, k_indices, k_sqr_distances, max_nn);
pcl::moveFromROSMsg(currentCloudMsg, *laserCloudIn);

3. pcl/registration/icp.h

#include <pcl/registration/icp.h>
pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
pcl::PointCloud<pcl::PointXYZ>::Ptr loopSourceCorner;
icp.setInputSource(loopSourceCorner); //注意输入的点云的数据类型为Ptr

五、文件处理

1. 加载文件
#include <pcl/io/pcd_io.h>
//temFilePath包含文件名和后缀;thisCornerCloud为::Ptr点云指针;
pcl::io::loadPCDFile(temFilePath, *thisCornerCloud);

other

1. fields of point type

You can use the following code to print out the fields of your registered point type and verify the order:

template <typename PointT>
void printPointTypeFields() {
    std::cout << "Fields in the point type:\n";
    for (const auto& field : pcl::traits::fieldList<PointT>::type::fields) {
        std::cout << "  " << field.name << "\n";
    }
}

末、Q&A

1. pcl_viewer segment fault

运行pcl_viewer时提示错误segment fault(core dump)。可能是因为驱动安装有问题,或者pcl的版本不适配。

2. register a point type

Code below is used to define and register a point type to PCL.

#include <pcl/point_types.h>

namespace custom_pcl
{
  struct MyCustomPoint
  {
    PCL_ADD_POINT4D;  // This macro adds padding for alignment and the XYZ fields
    int id;           // Add the custom field `id`
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW  // Ensure proper alignment
  };
}

POINT_CLOUD_REGISTER_POINT_STRUCT(
  custom_pcl::MyCustomPoint,  // Fully qualified name of the struct
  (float, x, x)               // Mapping: type, field name in struct, field name in PCL
  (float, y, y)
  (float, z, z)
  (int, id, id)               // Include the new `id` field
)

Note that the POINT_CLOUD_REGISTER_POINT_STRUCT macro must be placed in the global namespace. You cannot place it inside a namespace because the macro relies on global templates and compile-time mechanisms that PCL expects in the global scope. However, you can still define your custom point type within a namespace. Only the macro itself has to remain in the global scope.

3. Define a point type from existing point type in PCL
namespace custom_pcl
{
  struct EIGEN_ALIGN16 MyCustomPoint : public pcl::PointXYZINormal
  {
    int id;  // Additional field
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW  // Ensure proper memory alignment
  };
}

POINT_CLOUD_REGISTER_POINT_STRUCT(
  custom_pcl::MyCustomPoint,
  (float, x, x)
  (float, y, y)
  (float, z, z)
  (float, intensity, intensity)
  (float, normal_x, normal_x)
  (float, normal_y, normal_y)
  (float, normal_z, normal_z)
  (float, curvature, curvature)
  (int, id, id)
)

Then I got a warning.

warning: offsetof within non-standard-layout type 'MyCustomPoint' is conditionally-supported [-Winvalid-offsetof]

Standard Layout Requirements:

  1. A standard-layout type is one where all non-static data members are laid out in a well-defined order in memory, and there is no ambiguity due to inheritance.
  2. Adding new fields to a derived class makes the layout non-standard because the base class may already contain its own fields, making offsets potentially ambiguous.
4

code below

template <class PointT>
bool calculateNormal(const pcl::PointCloud<PointT>::Ptr &cloud, Eigen::Vector3f &normal) {}

I got an error during compilation:

error : need 'typename' before 'pcl::PointCloud<PointT>::Ptr' because 'pcl::PointCloud<PointT>' is a dependent bool calculateNormal(const pcl::PointCloud<PointT>::Ptr &cloud, Eigen::Vector3f &normal)

The error arises because in a templated function, PointT is a dependent type, and the compiler needs explicit help to identify pcl::PointCloud<PointT>::Ptr as a type. To fix this, you must use the typename keyword to specify that it is a type. Here’s the corrected code:

template <typename PointT>
bool calculateNormal(const typename pcl::PointCloud<PointT>::Ptr &cloud, Eigen::Vector3f &normal) {}

In fact, the corrected code can’t be compiled successfully. Because

5
octree_search.hpp : 396 : 46 : error : 'const struct custom::PointType' has no member named 'getVector3fMap' return (point_a.getVector3fMap() - point_b.getVector3fMap()).squaredNorm();

The error indicates that the structure custom::PointType does not have a member function or attribute named getVector3fMap. This function is a part of the PCL library for points that are derived from pcl::PointXYZ or similar types. Your custom PointType struct likely does not inherit from a pcl::PointXYZ-like structure or does not implement this function.

6

The macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW and EIGEN_ALIGN16 is not strictly necessary for C++17 in most cases, because C++17 introduced guarantees for aligned memory allocation through new alignment-aware operators like operator new(std::size_t, std::align_val_t). But if work with compiler and third-party library that don’t fully adopt C++17 alignment guarantees or do not respect the alignment requirements of Eigen types, the macro ensures compatibility.