C++ 平面拟合原理和最小法实现示例

平面拟合算法的核心目标是从三维空间中的一组离散点中找到最优拟合平面,使得这些点到该平面的垂直距离之和最小。以下是平面拟合的详细原理及实现方法:


1. 平面方程表示

三维平面的一般方程为:
[ A x + B y + C z + D = 0 ] [ Ax + By + Cz + D = 0 ] [Ax+By+Cz+D=0]

其中:

  • 法向量 : ( n = ( A , B , C ) ) ( \mathbf{n} = (A, B, C) ) (n=(A,B,C)),表示平面的朝向(通常归一化为单位向量)。
  • 截距 : ( D ) ( D ) (D) 为平面到原点的平移量。

为简化计算,常将方程标准化为:
[ A x + B y + C z = 1 或 n ⋅ p + D = 0 ] [ Ax + By + Cz = 1 \quad \text{或} \quad \mathbf{n} \cdot \mathbf{p} + D = 0 ] [Ax+By+Cz=1或n⋅p+D=0]

其中 ( p = ( x , y , z ) ) ( \mathbf{p} = (x, y, z) ) (p=(x,y,z)) 为点坐标。


2. 最小二乘法平面拟合

目标函数

最小二乘法通过最小化所有点到平面的 垂直距离平方和 来求解平面参数。点到平面的距离公式为:
[ d i = ∣ A x i + B y i + C z i + D ∣ A 2 + B 2 + C 2 ] [ d_i = \frac{|Ax_i + By_i + Cz_i + D|}{\sqrt{A^2 + B^2 + C^2}} ] [di=A2+B2+C2 ∣Axi+Byi+Czi+D∣]

为简化优化,忽略分母(即假设法向量归一化),目标函数简化为:
[ min ⁡ A , B , C , D ∑ i = 1 N ( A x i + B y i + C z i + D ) 2 ] [ \min_{A,B,C,D} \sum_{i=1}^N (Ax_i + By_i + Cz_i + D)^2 ] [A,B,C,Dmini=1∑N(Axi+Byi+Czi+D)2]

求解步骤
  1. 中心化数据

    计算点云质心 ( p ˉ = ( x ˉ , y ˉ , z ˉ ) ) ( \bar{\mathbf{p}} = (\bar{x}, \bar{y}, \bar{z}) ) (pˉ=(xˉ,yˉ,zˉ)),并将所有点平移至质心坐标系:
    [ x i ′ = x i − x ˉ , y i ′ = y i − y ˉ , z i ′ = z i − z ˉ ] [ x_i' = x_i - \bar{x}, \quad y_i' = y_i - \bar{y}, \quad z_i' = z_i - \bar{z} ] [xi′=xi−xˉ,yi′=yi−yˉ,zi′=zi−zˉ]

    此时平面方程变为 ( A x ′ + B y ′ + C z ′ = 0 ) ( A x' + B y' + C z' = 0 ) (Ax′+By′+Cz′=0),消去截距 ( D )。

  2. 构建矩阵方程

    将每个点的坐标代入平面方程,形成超定方程组:
    [ [ x 1 ′ y 1 ′ z 1 ′ x 2 ′ y 2 ′ z 2 ′ ⋮ ⋮ ⋮ x N ′ y N ′ z N ′ ] [ A B C ] = 0 ] [ \begin{bmatrix} x_1' & y_1' & z_1' \\ x_2' & y_2' & z_2' \\ \vdots & \vdots & \vdots \\ x_N' & y_N' & z_N' \end{bmatrix} \begin{bmatrix} A \\ B \\ C \end{bmatrix} = \mathbf{0} ] [ x1′x2′⋮xN′y1′y2′⋮yN′z1′z2′⋮zN′ ABC =0]

    记为 ( M v = 0 ) ( \mathbf{M} \mathbf{v} = \mathbf{0} ) (Mv=0),其中 ( v = ( A , B , C ) T ) ( \mathbf{v} = (A, B, C)^T ) (v=(A,B,C)T)。

  3. 奇异值分解(SVD)求解

    对矩阵 ( M ) ( \mathbf{M} ) (M) 进行奇异值分解:
    [ M = U Σ V T ] [ \mathbf{M} = \mathbf{U} \mathbf{\Sigma} \mathbf{V}^T ] [M=UΣVT]

    最小奇异值对应的右奇异向量即为法向量 ( \mathbf{v} )。

  4. 恢复截距

    根据质心坐标计算 ( D ) ( D ) (D):
    [ D = − ( A x ˉ + B y ˉ + C z ˉ ) ] [ D = - (A \bar{x} + B \bar{y} + C \bar{z}) ] [D=−(Axˉ+Byˉ+Czˉ)]


3. 主成分分析(PCA)法

PCA方法通过分析点云的协方差矩阵,找到方差最小的方向(即法向量方向)。

步骤
  1. 计算协方差矩阵
    [ C = 1 N ∑ i = 1 N ( p i − p ˉ ) ( p i − p ˉ ) T ] [ \mathbf{C} = \frac{1}{N} \sum_{i=1}^N (\mathbf{p}_i - \bar{\mathbf{p}})(\mathbf{p}_i - \bar{\mathbf{p}})^T ] [C=N1i=1∑N(pi−pˉ)(pi−pˉ)T]

  2. 特征值分解

    对 ( C ) ( \mathbf{C} ) (C) 进行特征分解,得到特征值 ( λ 1 ≥ λ 2 ≥ λ 3 ) ( \lambda_1 \geq \lambda_2 \geq \lambda_3 ) (λ1≥λ2≥λ3) 和对应的特征向量 ( v 1 , v 2 , v 3 ) ( \mathbf{v}_1, \mathbf{v}_2, \mathbf{v}_3 ) (v1,v2,v3)。

  3. 确定法向量

    最小特征值 ( λ 3 ) ( \lambda_3 ) (λ3) 对应的特征向量 ( v 3 ) ( \mathbf{v}_3 ) (v3) 即为平面法向量 ( n ) ( \mathbf{n} ) (n)。

  4. 计算截距

    利用质心坐标计算 ( D ) ( D ) (D):
    [ D = − n ⋅ p ˉ ] [ D = -\mathbf{n} \cdot \bar{\mathbf{p}} ] [D=−n⋅pˉ]


4. 鲁棒平面拟合(RANSAC)

当数据中存在噪声或离群点时,RANSAC(随机采样一致性)算法可提高拟合鲁棒性。

步骤
  1. 随机采样
    随机选择3个点计算初始平面参数。
  2. 内点检测
    计算所有点到该平面的距离,设定阈值 ( ϵ ) ( \epsilon ) (ϵ),统计距离小于 ( ϵ ) ( \epsilon ) (ϵ) 的内点数量。
  3. 迭代优化
    重复上述过程,保留内点最多的平面模型。
  4. 精确拟合
    使用所有内点通过最小二乘法重新拟合最终平面。

5. 算法对比

方法 优点 缺点 适用场景
最小二乘法 计算简单,闭式解 对噪声敏感,离群点影响大 数据干净,无显著离群点
PCA法 无需迭代,计算高效 假设数据服从高斯分布,对噪声敏感 点云分布均匀,主方向明显
RANSAC 鲁棒性强,抗离群点 计算开销大,依赖随机采样次数 数据含噪声或大量离群点

6. 代码实现示例(最小二乘法)

cpp 复制代码
#include <Eigen/Dense>
using namespace Eigen;

void fitPlane(const std::vector<Vector3d>& points, Vector3d& normal, double& d) {
    // 计算质心
    Vector3d centroid(0, 0, 0);
    for (const auto& p : points) centroid += p;
    centroid /= points.size();

    // 构建矩阵 M
    MatrixXd M(points.size(), 3);
    for (size_t i = 0; i < points.size(); ++i) {
        M.row(i) = points[i] - centroid;
    }

    // SVD分解
    JacobiSVD<MatrixXd> svd(M, ComputeThinV);
    normal = svd.matrixV().col(2); // 最小奇异值对应的列
    d = -normal.dot(centroid);
}

7. 应用场景

  • 三维重建:从点云中提取平面结构(如墙面、地面)。
  • 机器人导航:识别地面平面用于定位。
  • 工业检测:检测工件表面的平整度。

通过上述方法,可根据数据特性选择合适算法,平衡精度、速度和鲁棒性。

相关推荐
夏天的阳光吖22 分钟前
C++蓝桥杯基础篇(十一)
开发语言·c++·蓝桥杯
Alaso_shuang22 分钟前
C++多态
c++
郭涤生25 分钟前
并发操作的同步_第四章_《C++并发编程实战》笔记
开发语言·c++·算法
梦醒沉醉29 分钟前
C++和标准库速成(一)——HelloWorld和名称空间
开发语言·c++
BIT_Legend1 小时前
Torch 模型 model => .onnx => .trt 及利用 TensorTR 在 C++ 下的模型部署教程
c++·人工智能·python·深度学习
.ccl2 小时前
蓝桥杯省赛真题C++B组2024-握手问题
c++·算法·蓝桥杯
神里流~霜灭3 小时前
下降路径最⼩和(medium)
数据结构·c++·算法·链表·贪心算法·动态规划
tan180°3 小时前
版本控制器Git(1)
c++·git·后端
JANGHIGH3 小时前
c++ constraints与concepts使用笔记
c++·笔记
恋恋风辰4 小时前
QT系列教程(13) 事件系统
c++·qt·事件系统