PCL中实现点云法向量盘算

[复制链接]
发表于 2026-3-13 15:16:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
原理

法线的界说:法线是指垂直于一个平面的法向量。
对于点云(非固定平面)数据,怎样盘算法线?告急有两种方法:
外貌网格技能:从获取的数据中提取一个根本的外貌,然后从网格中盘算外貌的法线。
近似值推断法:直接从点数据会合推断外貌法线。其核心头脑是:为每个点盘算其外貌的切平面,这通常通过最小二乘平面拟合来估计。
那什么是最小二乘平面拟合呢?
给定一组三维数据点,找到最佳拟合平面 Z = AX + BY + C,使得全部数据点到该平面的垂直隔断(残差)的平方和最小。
在点云处置处罚中,通常利用主因素分析(PCA) 来实现平面拟合。PCA的核心目标是通过降维和去干系,找到数据变革的告急方向。
PCA的实现流程先对点云去中央化,然后再盘算斜方差矩阵,末了计盘算协方差矩阵的特性向量,此中最小特性值对应的特性向量就是法向量。
算法实现

协方差矩阵盘算:
  1. #include <pcl/common/centroid.h>   // 协方差矩阵计算的头文件
  2. Eigen::Vector4f centroid;          // 存储均值 (x, y, z, 1)
  3. Eigen::Matrix3f covariance;         // 3x3协方差矩阵
  4. // 核心一行:计算均值和协方差矩阵
  5. int points_used = pcl::computeMeanAndCovarianceMatrix(*cloud, covariance, centroid);
复制代码
特性向量求解:
  1. Eigen::Vector3f eigenvalues = solver.eigenvalues(); //特征值
  2. Eigen::Matrix3f eigenvectors = solver.eigenvectors();  // 列向量对应特征值
  3. Eigen::Vector3f normal = solver.eigenvectors().col(0); // 法向量赋值
复制代码
全部点盘算法向量:
  1. for each point p in cloud:
  2.     // 1. 找到 p 的邻域点集(半径内或 K 个最近邻)
  3.     neighbors = tree->radiusSearch(p, radius);
  4.     // 2. 如果邻域点数不足(如 < 3),法向量设为 NaN 或跳过
  5.     if (neighbors.size() < 3) continue;
  6.     // 3. 计算邻域重心
  7.     Eigen::Vector4f centroid;
  8.     computeCentroid(neighbors, centroid);
  9.     // 4. 构建协方差矩阵
  10.     Eigen::Matrix3f cov = Eigen::Matrix3f::Zero();
  11.     for each neighbor in neighbors:
  12.         Eigen::Vector3f centered = neighbor - centroid;
  13.         cov += centered * centered.transpose();
  14.     cov /= neighbors.size();   // 或除以 (n-1)
  15.     // 5. 特征分解
  16.     Eigen::SelfAdjointEigenSolver<Matrix3f> solver(cov);
  17.     Eigen::Vector3f normal = solver.eigenvectors().col(0);  // 最小特征值对应特征向量
  18.     // 6. 法向量定向(使指向传感器方向)
  19.     if (normal.dot(p - viewpoint) < 0) normal = -normal;
  20.     // 7. 存储法向量
  21.     cloud_normals[i] = normal;
复制代码
但在PCL中,有封装好了完备的实现函数pcl::NormalEstimation,因此只必要几行代码就能实现法向量盘算
  1. #include <pcl/features/normal_3d.h>    // 法向量估计头文件
  2. // 创建法向量估计对象
  3. pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
  4. ne.setInputCloud(cloud);   // 设置输入点云
  5. ne.setSearchMethod(tree);   // 设置邻域搜索方式
  6. //设置搜索半径(0.03 米)
  7. ne.setRadiusSearch(0.03);
  8. //创建存储法向量的点云对象,并执行计算
  9. pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);
  10. ne.compute(*cloud_normals);   // 核心计算:遍历每个点,估计法向量
复制代码
完备代码

[code]#include #include #include  #include int main() {    // 1. 加载点云    pcl:ointCloud:tr cloud(new pcl:ointCloud);    if (pcl::io::loadPCDFile("02.pcd", *cloud) == -1) {        std::cerr
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表