Skip to content

三维点云精配准算法详解:从 Point-to-Point 到 Point-to-Plane ICP

迭代最近点(Iterative Closest Point, ICP)是计算机视觉、三维扫描、SLAM 与机器人定位中实现空间点云对齐的核心算法。ICP 算法的两个主流变体——点到点 (Point-to-Point)点到平面 (Point-to-Plane) 在几何假设、数学推导与收敛特性上存在深刻差异。本文系统剖析两种 ICP 算法的代价函数、闭式/数值解法推导、代码实现与工程选型对比。


1. 迭代最近点 (ICP) 算法的几何本质

ICP 算法解决的核心问题是:给定源点集 与目标点集 ,寻找最佳的刚体变换矩阵 ,使得变换后的源点云与目标点云重合度最高。

完整 ICP 迭代循环包含四个步骤:

  1. 匹配 (Matching):为源点云中每个点 寻找目标点云中欧氏距离最近的点 (依赖 KD-Tree 加速)。
  2. 拒绝 (Rejection):剔除距离超出阈值或处于边界上的误匹配点对。
  3. 求解 (Solving):构造代价函数并求解当前迭代下的最佳旋转矩阵 与平移向量
  4. 更新 (Updating):对源点云执行变换 ,检查残差收敛条件。

1.1 粗配准与精配准的底层联系与机制对比

粗配准与精配准在底层姿态解算算法上具有高度的统一性(数学核心均为求解去质心协方差矩阵 SVD 的 Kabsch 算法),但两者的匹配前提与迭代逻辑存在本质区别:

对比维度粗配准 (Coarse Registration)精配准 (ICP Fine Registration)
底层姿态解算Kabsch 算法 (基于 SVD)Kabsch 算法 (基于 SVD)(Point-to-Point 模式)
同名点对来源已知/显式绝对同名点
(人工 2D/3D 点击或 FPFH 特征匹配)
未知/隐式临近点
(在不知道对应点时,靠 KD-Tree 找最近邻)
算法执行机制单次闭式计算
(直接 1 次解出初始位姿)
不断寻找临近点并重复迭代 Kabsch
(数十次循环更新位姿)
算法终止条件1 次计算完成即结束直至重投影残差收敛 () 或达到最大迭代次数

2. Point-to-Point ICP 算法原理与 SVD 闭式解法

2.1 目标代价函数

Point-to-Point ICP 最小化匹配点对之间的全方向三维欧氏距离平方和:

其中 为正交旋转矩阵, 为平移向量。

2.2 去质心中心化 (Decentering)

分别计算源点集与目标点集的几何质心

定义去质心中心化坐标 ,代价函数展开为:

当平移向量设定为 时,后半项严格为 0。代价优化简化为仅求解旋转 的最大化问题:

其中 的互协方差矩阵(Cross-Covariance Matrix)。

2.3 SVD 奇异值分解求解

矩阵 进行奇异值分解:

使 最大的最佳旋转矩阵闭式解为:

  • 手性检视与镜像翻转修正:若 (代表包含镜像反射),需通过对角矩阵修正:

最后求得最佳平移向量:


3. Point-to-Plane ICP 算法原理与高斯-牛顿线性化解法

3.1 目标代价函数

在实际物理世界中,许多物体表面是平滑连续的。Point-to-Plane ICP 将源点 投影到目标点 处的局部切平面上,仅最小化沿目标点法线 方向的正交距离:

几何上看,该代价函数允许源点沿着目标的局部切平面方向自由滑动,不会因为切向方向的微小匹配偏差而产生不必要的惩罚惩戒。

3.2 小旋转量线性化与高斯-牛顿解法

该代价函数关于 是非线性的。考虑在单次迭代中旋转角度偏转很小,采用小角度近似 。 旋转矩阵 可以用三维旋转向量 线性化表示为:

其中 。将变换带入误差方程:

令待求未知增量向量为 。构建雅可比矩阵行向量:

残差标量为 。整个问题转化为标准高斯-牛顿线性方程组:

求解 正定方程组后,用求出的 构造增量变换矩阵并更新源点坐标。


4. 算法性能对比与选型指南

对比维度Point-to-Point ICPPoint-to-Plane ICP
代数几何约束全方向三维欧氏距离仅目标切平面法向投影距离
解算机制SVD 奇异值分解(闭式解,无须线性化)高斯-牛顿 / 增量方程求解 ( 矩阵)
收敛速度较慢(易在切向方向发生“震荡/锁死”)极快(相比 Point-to-Point 提升 3~5 倍)
依赖条件仅需要点云 3D 坐标 强依赖目标点云高品质法线
抗噪能力对高频坐标噪声容忍度相对较好若法线方向混乱,算法解算将严重发散
典型适用场景稀疏点云、无明显平面的复杂曲面具有连续光滑表面的 3D 扫描、CAD 模型

5. 基于 Eigen 的 C++ 通用代码实现

cpp
#include <iostream>
#include <vector>
#include <Eigen/Dense>

// Point-to-Point ICP 基于 SVD 求解单步 (R, T)
bool solve_icp_point_to_point(const std::vector<Eigen::Vector3d>& src,
                               const std::vector<Eigen::Vector3d>& dst,
                               Eigen::Matrix3d& R,
                               Eigen::Vector3d& T) {
    if (src.size() != dst.size() || src.empty()) return false;
    const size_t N = src.size();

    // 1. 计算质心
    Eigen::Vector3d src_centroid = Eigen::Vector3d::Zero();
    Eigen::Vector3d dst_centroid = Eigen::Vector3d::Zero();
    for (size_t i = 0; i < N; ++i) {
        src_centroid += src[i];
        dst_centroid += dst[i];
    }
    src_centroid /= static_cast<double>(N);
    dst_centroid /= static_cast<double>(N);

    // 2. 构建互协方差矩阵 H
    Eigen::Matrix3d H = Eigen::Matrix3d::Zero();
    for (size_t i = 0; i < N; ++i) {
        Eigen::Vector3d x = src[i] - src_centroid;
        Eigen::Vector3d y = dst[i] - dst_centroid;
        H += x * y.transpose();
    }

    // 3. SVD 分解
    Eigen::JacobiSVD<Eigen::Matrix3d> svd(H, Eigen::ComputeFullU | Eigen::ComputeFullV);
    Eigen::Matrix3d U = svd.matrixU();
    Eigen::Matrix3d V = svd.matrixV();

    R = V * U.transpose();

    // 手性翻转检查
    if (R.determinant() < 0) {
        Eigen::Matrix3d V_corrected = V;
        V_corrected.col(2) *= -1.0;
        R = V_corrected * U.transpose();
    }

    // 4. 计算平移向量
    T = dst_centroid - R * src_centroid;
    return true;
}

int main() {
    std::vector<Eigen::Vector3d> src = {{0,0,0}, {1,0,0}, {0,1,0}};
    // 构造旋转 90 度 (绕 Z 轴) 并平移 (2, 3, 0) 后的目标点
    std::vector<Eigen::Vector3d> dst = {{2,3,0}, {2,4,0}, {1,3,0}};

    Eigen::Matrix3d R;
    Eigen::Vector3d T;
    if (solve_icp_point_to_point(src, dst, R, T)) {
        std::cout << "Estimated Rotation Matrix R:\n" << R << "\n";
        std::cout << "Estimated Translation Vector T:\n" << T.transpose() << "\n";
    }
    return 0;
}

6. 核心原理与高频追问

FAQ 1:为什么 Point-to-Plane ICP 在光滑曲面上收敛速度远高于 Point-to-Point?

: Point-to-Point 强制要求源点在所有方向上都趋向目标点。在光滑平面或圆柱面上,点云在切向方向的极小局部滑动误匹配也会被计算为距离误差,引发优化算法在切向产生无意义的频繁震荡。 而 Point-to-Plane 解除了切向约束,只拉近源点到目标切平面的法向距离,允许算法在沿曲面滑动的过程中快速寻找全局全局最优姿态,因此通常只需 5~10 次迭代即可收敛。

FAQ 2:在 Point-to-Point ICP 算得的 中,为什么需要检查

: 互协方差矩阵 的 SVD 正交求解在纯代数上只约束了正交性 。然而, 正交群包含两类矩阵:

  • :属于特别正交群 ,代表物理上真实的旋转矩阵
  • :代表镜像反射矩阵(Reflection Matrix,如手性颠倒、左右翻转)。

在点云刚体变换中,物理世界不允许发生镜像翻转。当拟合点对共面或存在严重噪声导致 时,必须通过反转 的最后一列强制修正为真正的旋转矩阵。

基于 VitePress 强力驱动 | 记录技术与生活