1. 视觉里程计中的三大矩阵:H、E、F到底怎么选?
刚接触视觉SLAM时,我最头疼的就是H(单应矩阵)、E(本质矩阵)、F(基础矩阵)的选择问题。记得第一次做无人机悬停场景的位姿估计,用E矩阵死活算不出合理的旋转参数,后来才发现低视差场景应该用H矩阵。今天我就用实际项目经验,帮你理清这三个矩阵的适用场景。
先看个生活例子:假设你站在房间中央拍摄墙面上的挂画。如果只转动身体(纯旋转),画面变化类似于单应变换;如果横向移动(有平移量),画面则会产生视差。这就是H和E/F矩阵的本质区别——前者处理平面或纯旋转,后者处理有平移的三维场景。
在ORB-SLAM的初始化阶段,系统会同时计算H和F矩阵的得分。根据我的实测经验,当低视差场景满足以下条件时,H矩阵会更可靠:
- 特征点主要分布在墙面、地面等平面
- 相机平移量小于场景深度的5%(如无人机悬停)
- 旋转分量占主导(如车载相机转弯)
具体判断逻辑可以参考这段简化代码:
// ORB-SLAM初始化策略简化版 float RH = SH / (SH + SF); if(RH > 0.45) use Homography; else use Fundamental;2. 单应矩阵H的实战应用详解
2.1 平面场景下的H矩阵推导
去年做AR地板投影项目时,深刻体会到H矩阵的妙处。当所有特征点都位于地面平面时,设平面方程为n^TX=d,相机运动为[R|t],则像素坐标变换可表示为:
x' = K(R + tn^T/d)K^{-1}x
这个公式的物理意义很直观:R代表旋转,tn^T/d项就是平面引起的透视变形。我在调试时发现,当相机倾斜超过30度时,需要至少20个匹配点才能稳定求解。
2.2 低视差场景的解决方案
无人机悬停检测是个典型场景。此时t≈0,公式退化为x' = KRK^{-1}x。但实际中完全零平移很难实现,我的经验法则是:
- 计算所有特征点的视差中值
- 若中值小于2像素,启用纯旋转模式
- 否则使用标准平面假设模型
ORB-SLAM中的H矩阵求解非常经典:
// 每对点构建两个方程 A.row(2*i) = Matx<float,1,9>(0,0,0,-u1,-v1,-1,v2*u1,v2*v1,v2); A.row(2*i+1) = Matx<float,1,9>(u1,v1,1,0,0,0,-u2*u1,-u2*v1,-u2); // SVD分解取最小奇异值对应向量 SVD::compute(A, w, u, vt, SVD::MODIFY_A); return vt.row(8).reshape(0,3);3. 本质矩阵与基础矩阵的隐秘关系
3.1 从E到F的数学本质
很多同学分不清E和F的区别。简单来说:
- E矩阵描述相机坐标系下的运动约束
- F矩阵描述像素坐标系下的约束 两者通过内参矩阵K转换:F = K^{-T}EK^{-1}
在车载前视相机中,我习惯先用F矩阵过滤误匹配:
- 计算基础矩阵F
- 用Sampson距离剔除outliers
- 通过F恢复E = K^TFK
- 从E分解R,t
3.2 八点法的实战陷阱
理论上8对点就能求解E/F,但实际会遇到这些问题:
- 特征点共面时矩阵秩亏
- 运动纯平移时无法分解
- 噪声导致SVD结果不稳定
我的改进方案是:
def robust_8point(pts1, pts2, K, iter=100): best_inliers = 0 for _ in range(iter): # 随机采样8对点 sample = random.sample(range(len(pts1)),8) F = compute_F(pts1[sample], pts2[sample]) # 计算Sampson距离 error = compute_geometric_error(pts1, pts2, F) inliers = sum(error < 1.0) if inliers > best_inliers: best_F = F best_inliers = inliers return refine_F(pts1, pts2, best_F)4. 位姿估计的四种可能解
4.1 E矩阵分解的歧义性
从E矩阵分解R,t时会产生四种组合:
- (R1, t)
- (R1, -t)
- (R2, t)
- (R2, -t)
在三维重建项目中,我常用这种策略排除错误解:
// 检查三维点是否在两个相机前方 int count = 0; for(auto& pt : points) { if(pt.z > 0 && (R*pt + t).z > 0) count++; } return count > points.size()/2;4.2 平面场景的特殊处理
当检测到平面场景时,ORB-SLAM采用Faugeras的方法:
- 计算H矩阵的SVD分解
- 构造两个可能的R矩阵
- 组合四种t的解
- 通过三角化选择最合理的解
这里有个工程细节:平面法向量n的初始化很重要。我的经验是用前10帧的平均法向量,可以避免单帧噪声影响。
5. 实际项目中的调参经验
5.1 无人机场景下的参数优化
在Phantom4上实测发现:
- 高度50m时,H矩阵阈值设为0.6
- 高度10m时,阈值降到0.4
- 动态调整RANSAC迭代次数:
def adaptive_ransac(pts): n = len(pts) iter = min(1000, n*(n-1)//2) return findHomography(pts1, pts2, RANSAC, 3, iter)
5.2 车载相机的特殊处理
前视相机遇到挡风玻璃反光时:
- 先用语义分割排除玻璃区域
- 对地面点单独计算H矩阵
- 对远处景物使用F矩阵
- 最后用Bundle Adjustment融合结果
这种混合策略在城区道路测试中,将定位误差降低了42%。