4. 单应性矩阵求解:DLT算法、RANSAC鲁棒估计、重投影误差最小化
好,咱们进入正题。单应性矩阵这东西,说白了就是描述两个平面之间的一一映射关系。在标定场景里,它连接了棋盘格平面和图像平面。你想想看,我们拍一张棋盘格照片,角点的世界坐标是已知的,像素坐标也能检测出来——那中间的桥梁,就是单应性矩阵。
我个人习惯把单应性矩阵求解拆成三步走:先用DLT算个初始值,再用RANSAC剔除野点,最后用非线性优化把精度磨到极致。这三板斧下来,基本不会出大问题。
4.1 DLT算法:从线性代数到几何映射
DLT,全称Direct Linear Transform,直接线性变换。名字听着唬人,其实原理很简单——把问题转化成解线性方程组。
单应性矩阵H是一个3x3的矩阵,有8个自由度(去掉一个尺度因子)。一对匹配点可以提供两个方程,所以理论上4对点就能解。但实际中我们会用更多的点,用最小二乘来抵抗噪声。
具体推导我就不啰嗦了,直接说核心:
- 每对匹配点 (x, y) -> (u, v) 可以构造两个方程
- 把所有方程堆起来,得到 Ah = 0 的形式
- 对A做SVD分解,最小奇异值对应的右奇异向量就是H
这里有个坑,我踩过。如果点的坐标数值差异很大(比如世界坐标是毫米级,像素坐标是千像素级),A矩阵的条件数会很大,解出来的H精度堪忧。我的做法是:先做归一化,把坐标缩放到[-1, 1]区间,解完再反归一化回去。这一步叫"归一化DLT",效果立竿见影。
4.2 RANSAC鲁棒估计:把野点揪出来
实际项目中,角点检测不可能100%准确。光照不好、棋盘格反光、运动模糊——这些都会带来野点。如果直接用DLT硬算,一个野点就能把结果带偏。
RANSAC的思路很暴力:随机采样、验证、迭代。具体流程:
- 从所有匹配点中随机选4对,用DLT算一个H
- 用这个H去投影所有点,算重投影误差
- 误差小于阈值的点算内点,记录内点数量
- 重复N次,保留内点最多的那组H
- 用所有内点重新算一次H(精化)
我曾经在一个项目中,因为标定板贴歪了,导致20%的角点都有系统偏差。第一次跑DLT出来的结果惨不忍睹,重投影误差直接飙到5个像素。后来加上RANSAC,内点率降到95%以上,误差直接回到0.3像素以内。
4.3 重投影误差最小化:把精度磨到极致
DLT+RANSAC得到的H,精度已经不错了。但如果你追求亚像素级别的标定精度,那就得走最后一步——非线性优化。
优化的目标函数很直观:
minimize Σ || p_i - project(H, P_i) ||²
其中p_i是检测到的像素坐标,P_i是世界坐标,project是投影函数。说白了,就是让所有点的投影误差平方和最小。
我一般用Levenberg-Marquardt算法来解这个优化问题。相比高斯-牛顿,LM在迭代初期更稳定,不容易发散。初始值就用RANSAC精化后的H,通常迭代10~20次就能收敛。
这里有个细节:优化时H的9个参数不是独立的,因为有尺度模糊。我习惯把H的最后一个元素固定为1,或者用单位向量约束。两种做法都可以,看个人喜好。
4.4 知识体系总览
下面这张图,是我自己梳理的单应性矩阵求解流程。你可以把它当作一个检查清单:
嗯,到这里单应性矩阵求解的核心内容就讲完了。DLT给个起点,RANSAC清理数据,优化收尾——这套组合拳打下来,标定精度基本稳了。下次你遇到标定不准的问题,不妨按这个流程排查一遍,大概率能找到症结所在。