数学基础(一):线性代数核心——向量、矩阵运算、特征值与特征向量在三维空间变换中的应用

说实话,做三维重建这些年,我见过太多人一上来就猛怼深度学习框架,结果连点云怎么旋转都搞不明白。嗯,线性代数这东西,就像你手里的螺丝刀——你不会用,再好的相机也拧不紧。今天咱们就把这螺丝刀磨锋利了。

1. 向量:三维空间的“坐标信使”

向量是什么?说白了就是带方向和大小的箭头。在三维重建里,每个三维点都是一个向量:p = (x, y, z)。我习惯把向量想象成“从原点出发的箭头”,指向空间中的某个位置。

核心操作:

  • 点积(内积):a · b = |a||b|cosθ。用来算夹角、投影长度。我在做点云配准时,经常用点积判断两个法向量是否朝向一致。
  • 叉积(外积):a × b = 垂直于a和b的向量。这个太重要了——求平面法向量、计算旋转轴,全靠它。

举个例子,你有一面墙的点云,想算它的法向量。随便选三个不共线的点,构造两个向量,叉积一算,法线就出来了。我当年第一次手动实现这个,兴奋得差点把咖啡洒键盘上。

// 伪代码:计算三角形法向量
vec3 a = p2 - p1;
vec3 b = p3 - p1;
vec3 normal = cross(a, b);  // 叉积
normal = normalize(normal); // 归一化

避坑指南:我曾经在项目里直接用未归一化的法向量去算光照,结果渲染出来一片漆黑。记住:叉积结果的长度是|a||b|sinθ,不归一化的话,长度会随三角形大小变化,导致后续计算全乱套。

2. 矩阵运算:空间变换的“翻译官”

矩阵就是把多个向量排成方阵。在三维重建里,矩阵干三件事:旋转、缩放、平移。你想想看,一个三维点从相机坐标系转到世界坐标系,背后就是矩阵乘法。

我习惯用4×4齐次矩阵,为什么?因为平移没法用3×3矩阵表示,加一个维度(齐次坐标)就能把旋转和平移统一成一次乘法。这招在OpenGL和点云库里随处可见。

变换类型 矩阵形式(4×4) 作用
平移 [1 0 0 tx; 0 1 0 ty; 0 0 1 tz; 0 0 0 1] 移动物体位置
旋转(绕Z轴) [cosθ -sinθ 0 0; sinθ cosθ 0 0; 0 0 1 0; 0 0 0 1] 绕Z轴转θ度
缩放 [sx 0 0 0; 0 sy 0 0; 0 0 sz 0; 0 0 0 1] 各方向缩放

矩阵乘法不满足交换律,这个坑我踩过。先旋转再平移,和先平移再旋转,结果完全不同。你想想看,一个物体先转90度再往右移,和先往右移再转90度,位置能一样吗?

注意:矩阵乘法顺序是从右往左读。比如 M = T × R,意思是先应用R(旋转),再应用T(平移)。我见过有人写反了,结果点云飞到天上去。

3. 特征值与特征向量:找到“不变的方向”

这个概念听起来玄乎,其实特简单。对于一个矩阵A,如果存在向量v和标量λ,使得 A·v = λ·v,那么v就是特征向量,λ就是特征值。说白了:矩阵A对v只做拉伸,不做旋转。

在三维重建里,特征值分解最经典的应用是主成分分析(PCA)。我做过一个项目,要自动识别点云中的平面。用PCA算协方差矩阵的特征值和特征向量:最小特征值对应的特征向量就是法向量,最大特征值对应的就是主方向。

// 伪代码:PCA求点云法向量
Matrix3x3 cov = computeCovariance(pointCloud);
EigenValues ev = solveEigen(cov);
// 最小特征值对应的特征向量 = 法向量
vec3 normal = ev.vectors[ev.minIndex];

为什么特征值大小有意义?

  • 三个特征值差不多大 → 点云分布均匀(球状)
  • 一个很大,两个很小 → 点云呈线状(比如墙角线)
  • 两个很大,一个很小 → 点云呈面状(比如墙面)

这个判断我在做点云分割时天天用,比肉眼判断准多了。

4. 知识体系总览

下面这张图是我自己总结的,把向量、矩阵、特征值在三维重建里的关系串起来了。你看一遍,心里就有谱了。

三维重建中的线性代数核心 向量 · 点积:夹角、投影 · 叉积:法向量、旋转轴 · 归一化:单位向量 矩阵 · 旋转矩阵 · 平移矩阵(齐次) · 缩放矩阵 特征值/特征向量 · PCA主成分分析 · 法向量估计 · 点云形状分析 应用:点云配准、相机位姿估计、三维重建 向量提供基础运算 → 矩阵封装变换 → 特征值提取几何本质 💡 核心思想:所有三维变换都可以用矩阵乘法表示 特征值分解帮我们找到数据中“最重要的方向”

5. 实战中的避坑经验

最后分享几个我踩过的坑,希望能帮你省点时间:

  • 矩阵求逆要小心:不是所有矩阵都可逆。旋转矩阵一定可逆(逆就是转置),但投影矩阵不可逆。我曾在代码里直接调用inverse(),结果程序崩了——矩阵是奇异的。
  • 特征值分解的数值稳定性:当两个特征值非常接近时,对应的特征向量可能不稳定。我建议用SVD(奇异值分解)代替,更鲁棒。
  • 坐标系习惯:OpenCV用右手系,Unity用左手系。矩阵运算结果不一样。我吃过这个亏,点云在OpenCV里看着正常,导入Unity就镜像了。

我的习惯:每次写矩阵运算前,先画个坐标系草图,标清楚x、y、z方向。别嫌麻烦,这能省下后面两小时的调试时间。

好了,线性代数这部分就聊到这儿。记住:向量是砖,矩阵是墙,特征值是墙里的钢筋。把这三样玩明白,三维重建的骨架你就搭起来了。

专注资料整理