4、对极几何与基础矩阵:对极约束、本质矩阵、基础矩阵、八点法求解
说到三维重建,有个绕不开的坎——对极几何。
我记得刚入行那会儿,第一次做双目视觉标定,看着两张图片里那些匹配点,心里就在想:这两张图到底有什么关系?怎么从一堆像素点里算出相机的运动?
后来我才明白,这一切的答案,都藏在对极几何里。
4.1 对极约束:两张图之间的“隐形锁链”
先看一个场景。你拿着相机,拍了一张照片。然后你移动了一下相机,又拍了一张。这两张图里,同一个三维点(比如墙角)会落在不同的像素位置。
问题是:这两个像素点之间,有没有什么固定的数学关系?
答案是:有。这就是对极约束。
说白了,对极约束描述的是:第一张图里的一个像素点,在第二张图里对应的匹配点,一定落在一条特定的直线上。这条线叫极线。
核心思想:匹配点不需要在整张图里瞎找,只需要沿着极线搜索就行。这大大降低了匹配的计算量。
我在项目中遇到过一个问题:用暴力匹配做特征点匹配,速度慢得离谱。后来改用极线约束做引导匹配,速度直接提升了10倍。嗯,这就是对极几何的实用价值。
4.2 本质矩阵:相机运动的内在密码
对极约束有了,但怎么用数学表达?
这里就要引入本质矩阵(Essential Matrix)了。它用符号 E 表示。
本质矩阵描述的是:两个相机坐标系之间的旋转和平移关系。它只跟相机的运动有关,跟相机内参无关。
数学上,本质矩阵满足一个关键方程:
p2^T * E * p1 = 0
其中 p1 和 p2 是归一化平面上的坐标(不是像素坐标)。
这个方程的意思就是:点 p1 在第二张图里的对应点 p2,一定满足这个约束。
我的习惯:在实际代码里,我会先把像素坐标转成归一化坐标,再计算本质矩阵。这样能避免内参带来的干扰,结果更稳定。
4.3 基础矩阵:像素层面的对极约束
本质矩阵只关心相机运动,但实际中我们拿到的是像素坐标。怎么办?
把相机内参加进去就行了。这就得到了基础矩阵(Fundamental Matrix),用 F 表示。
基础矩阵的方程是:
x2^T * F * x1 = 0
其中 x1 和 x2 是像素坐标。
本质矩阵和基础矩阵的关系很简单:
F = K^(-T) * E * K^(-1)
其中 K 是相机内参矩阵。
| 矩阵 | 输入坐标 | 依赖信息 | 自由度 |
|---|---|---|---|
| 本质矩阵 E | 归一化坐标 | 旋转 R、平移 t | 5 |
| 基础矩阵 F | 像素坐标 | 旋转 R、平移 t、内参 K | 7 |
你想想看,基础矩阵把内参和运动信息都打包在一起了。所以它可以直接从像素匹配点中求解出来。
4.4 八点法求解:最经典的线性方法
怎么从一堆匹配点里算出基础矩阵?
最经典的方法就是八点法。为什么叫八点法?因为基础矩阵有7个自由度,理论上7个点就够了。但8个点可以构成一个线性方程组,求解更稳定。
具体步骤是这样的:
- 构建矩阵 A:对每一对匹配点 (x1, y1) 和 (x2, y2),构建一行:
A_i = [x2*x1, x2*y1, x2, y2*x1, y2*y1, y2, x1, y1, 1]
- 求解线性方程组:解
A * f = 0,其中f是基础矩阵的9个元素。 - 奇异值约束:基础矩阵的秩必须是2。所以对求出的矩阵做SVD分解,把最小的奇异值置为0,再重构。
我曾经踩过的坑:直接用原始像素坐标做八点法,数值稳定性很差。后来我学会了先做归一化——把坐标缩放到均值为0、方差为1的范围。这一步能显著提升精度。
归一化后的八点法,代码实现大概是这样的:
def compute_fundamental_matrix(pts1, pts2):
# 1. 归一化
T1 = normalize_points(pts1)
T2 = normalize_points(pts2)
pts1_norm = apply_transform(T1, pts1)
pts2_norm = apply_transform(T2, pts2)
# 2. 构建矩阵 A
A = []
for p1, p2 in zip(pts1_norm, pts2_norm):
x1, y1 = p1
x2, y2 = p2
A.append([x2*x1, x2*y1, x2, y2*x1, y2*y1, y2, x1, y1, 1])
A = np.array(A)
# 3. 求解 Af = 0
U, S, Vt = np.linalg.svd(A)
f = Vt[-1, :]
F = f.reshape(3, 3)
# 4. 秩2约束
U, S, Vt = np.linalg.svd(F)
S[2] = 0
F = U @ np.diag(S) @ Vt
# 5. 反归一化
F = T2.T @ F @ T1
return F
4.5 从基础矩阵到相机运动
算出基础矩阵之后,怎么得到相机的旋转和平移?
流程是这样的:
- 从基础矩阵
F和相机内参K恢复本质矩阵E:E = K^T * F * K - 对
E做SVD分解,得到4组可能的 (R, t) 解。 - 用三角化验证,选出正确的那个。
我的经验:4组解里只有1组能让所有三维点都在相机前方。用这个条件筛选,基本不会出错。
4.6 本章知识体系
下面这张图,把对极几何的核心逻辑串起来了:
从这张图可以看得很清楚:整个流程就是从匹配点出发,一步步解出相机的运动参数。每一步都有明确的数学工具支撑。
好了,对极几何的核心内容就这些。说白了,它就是连接二维图像和三维空间的一座桥梁。掌握了它,你就能从两张图片里读出相机的运动轨迹。
下次做视觉里程计或者三维重建的时候,别忘了回头看看这个基础。很多看似复杂的问题,追根溯源,都落在这几个矩阵上。