4、系统标定联合优化:重投影误差最小化与光束法平差

好,咱们接着聊标定。前面几节我们把相机和投影仪各自的内参、外参都捋了一遍,但说实话,那只是「各自为战」。你想想看,相机标自己的,投影仪标自己的,最后拼在一起,误差能小吗?

我早年做第一个结构光项目时就吃过这个亏。相机重投影误差0.1像素,投影仪也标得挺漂亮,可一重建三维点,偏差直接飙到毫米级。后来我才明白——系统标定必须联合优化

4.1 为什么需要联合优化?

单独标定有个根本问题:相机和投影仪的误差会互相放大

举个例子。你标定相机时,用的是棋盘格角点。这些角点的三维坐标,是你假设的「理想值」。但投影仪标定时,它投射的编码条纹也会受相机畸变影响。两个误差源一叠加,最终重建精度就崩了。

说白了,相机-投影仪是一个双目系统。你不能把左眼和右眼分开训练,对吧?

核心思想:将相机和投影仪视为一个整体,构建联合代价函数,同时优化所有参数。让重投影误差在全局意义上最小化。

4.2 联合代价函数怎么构建?

这里我直接给出公式,别怕,其实逻辑很简单。

假设我们有N个标定点(比如棋盘格角点),每个点在世界坐标系下的坐标为 Xw。相机观测到的像素坐标为 uc,投影仪投射的编码对应像素坐标为 up

那么,联合代价函数就是:

E = Σ || u_c - π_c(K_c, R_c, t_c, X_w) ||² 
    + Σ || u_p - π_p(K_p, R_p, t_p, X_w) ||²

其中:

  • π_c 是相机的投影函数(含畸变)
  • π_p 是投影仪的投影函数(含畸变)
  • K_c, K_p 是内参矩阵
  • R_c, t_c, R_p, t_p 是外参(旋转和平移)

注意,这里的 X_w 也是优化变量!不是固定死的。这就是光束法平差(Bundle Adjustment)的精髓——同时优化三维点和相机/投影仪参数

我的经验:一开始别把所有参数都放开优化。先固定内参,只优化外参和三维点。迭代几轮后,再放开内参。这样收敛更快,不容易掉进局部最优。

4.3 Levenberg-Marquardt 算法怎么用?

LM算法,说白了就是梯度下降法 + 高斯牛顿法的混合体。它有个阻尼因子 λ,控制着算法在「信任区域」内搜索。

具体步骤我简化一下:

  1. 初始化:用单独标定的结果作为初值
  2. 计算雅可比矩阵:对每个参数求偏导
  3. 求解增量方程:(JTJ + λI) Δx = -JTe
  4. 更新参数:x = x + Δx
  5. 判断收敛:如果重投影误差下降小于阈值,停止

这里有个关键点——雅可比矩阵的稀疏性。因为每个三维点只出现在少数几个观测方程中,所以 JTJ 是高度稀疏的。利用稀疏求解器(比如 SuiteSparse),速度能快几十倍。

// 伪代码示例(C++风格)
void bundleAdjustment(
    vector<Point3d>& points,      // 三维点
    vector<Camera>& cameras,      // 相机+投影仪参数
    vector<Observation>& obs      // 观测数据
) {
    LevenbergMarquardt lm;
    lm.setMaxIterations(100);
    lm.setLambda(0.001);
    
    while (!lm.converged()) {
        // 构建稀疏矩阵
        SparseMatrix J = buildJacobian(points, cameras, obs);
        Vector e = computeResidual(points, cameras, obs);
        
        // 求解增量
        Vector dx = lm.solve(J, e);
        
        // 更新参数
        updateParameters(points, cameras, dx);
        
        // 调整阻尼因子
        lm.updateLambda(e, dx);
    }
}

注意:投影仪的畸变模型和相机略有不同。我建议投影仪用 多项式模型(径向畸变+切向畸变),而不要用除法模型。后者在投影仪上容易发散。

4.4 我曾经踩过的坑

讲几个真实案例,你遇到了能少走弯路。

坑1:初值太差,LM直接崩了

有一次我偷懒,直接用投影仪标定的初值,没做任何预处理。结果LM迭代到第3步,重投影误差从0.5像素直接跳到50像素。后来我加了两步法:先用线性方法求一个粗略解,再用LM精化。稳得很。

坑2:忽略了投影仪的「虚拟像素」

投影仪本质上是一个逆向相机。它的像素坐标是投射出去的编码值,不是直接拍摄的。所以计算重投影误差时,要把投影仪的观测值转换到「虚拟图像坐标系」下。我一开始没注意,误差算出来全是错的。

坑3:过度优化导致过拟合

标定点太少时,联合优化会把噪声也拟合进去。我建议每个标定板图像至少提取50个角点,总共20-30张图像。这样参数空间才够约束。

4.5 联合优化的效果有多明显?

直接上数据。这是我一个项目中的实测对比:

标定方法 相机重投影误差 (pixel) 投影仪重投影误差 (pixel) 三维重建误差 (mm)
单独标定 0.12 0.18 0.85
联合优化(仅外参) 0.10 0.15 0.52
联合优化(内外参+三维点) 0.08 0.11 0.31

看到了吧?联合优化能把三维重建误差降低60%以上。这可不是小数目。

4.6 核心逻辑流程图

下面这张图,我把整个联合优化的流程画出来了。你一看就明白。

系统标定联合优化流程图 步骤1:单独标定 相机内参 + 投影仪内参 步骤2:构建联合代价函数 相机残差 + 投影仪残差 步骤3:LM优化 迭代求解 步骤4:判断收敛 重投影误差 < 阈值? 不收敛 步骤5:输出优化结果 内外参 + 三维点 输入数据 标定板图像 + 编码条纹 注:虚线表示不收敛时的回退路径,实线表示正常流程 关键参数 • 阻尼因子 λ:0.001~10 • 最大迭代次数:100 • 收敛阈值:0.01 pixel

4.7 总结一下

联合优化不是什么高深莫测的技术,它就是把相机和投影仪当成一个整体来调优。核心就三点:

  • 构建联合代价函数——同时考虑相机和投影仪的残差
  • 使用LM算法——稳健的迭代优化方法
  • 注意初值和稀疏性——别让算法跑飞了

嗯,这一节内容不少,但你只要动手跑一遍代码,就会发现其实没那么复杂。下一节我们聊聊标定板的设计——别小看它,好的标定板能让你的精度再上一个台阶。


公众号:蓝海资料掘金营,微信deep3321