第一次接触双目立体视觉时,我被它模拟人眼的工作原理深深吸引。想象一下,当你闭上一只眼睛时,判断物体的距离会变得困难;而睁开双眼后,大脑通过比较两幅图像的差异就能轻松感知深度。这就是双目视觉的核心思想——通过两个摄像头模拟人眼,计算视差来重建三维世界。
在实际项目中,我常用一对经过严格校准的工业相机搭建系统。两个相机之间的水平距离(基线距离T)是关键参数,就像人的瞳距一样直接影响测量范围。基线越大,远距离测量越准,但会牺牲近距离的视野重叠区域。经过多次实验,我发现对于室内机器人导航,6-12cm的基线距离是最佳选择。
这里有个生活化的类比:假设你伸直手臂竖起大拇指,分别用左右眼观察。当拇指离眼睛很近时,左右眼看到的拇指位置差异很大(大视差);当拇指逐渐远离,这个差异会变小(小视差)。双目系统就是用数学公式量化这个过程:
python复制depth = (focal_length * baseline) / disparity
其中focal_length是相机焦距,baseline是两相机间距,disparity是同一物体在两幅图像中的像素坐标差。这个简单的三角测量公式,却是整个深度重建的基石。
很多教程只给出理论公式,却忽略了实际工程中的关键点。根据我的踩坑经验,三角测量要获得准确结果,必须处理好三个环节:
首先是相机标定。有次项目 deadline 前夜,我们的深度图总是扭曲,后来发现是标定板拍摄时存在反光。现在我的标准流程是:
其次是视差计算精度。早期我们直接用整数像素坐标做减法,结果深度图出现明显分层。后来改用亚像素级角点检测,精度提升显著:
python复制# 亚像素级角点优化
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corners = cv2.cornerSubPix(gray_image, corners, (11,11), (-1,-1), criteria)
最后是误差管理。三角测量有个反比例特性:当物体距离较近时,视差大但深度误差小;距离远时,视差小却会导致深度误差急剧增大。这解释了为什么双目相机在5米外的测距精度会明显下降。实测数据如下表:
| 距离(m) | 视差(pixel) | 深度误差(cm) |
|---|---|---|
| 1.0 | 120 | ±0.3 |
| 3.0 | 40 | ±2.1 |
| 5.0 | 24 | ±8.7 |
极线校正就像给两个相机戴上一副"数学眼镜",让它们的图像行严格对齐。有次客户要求实时处理4K视频,未经校正的原始匹配需要10秒/帧,校正后仅需0.3秒——这就是将二维搜索降为一维的威力。
校正的核心是构造旋转矩阵,这里分享我的实现技巧。首先计算基线方向单位向量:
python复制# 假设T是右相机在左相机坐标系中的平移向量
e1 = T / np.linalg.norm(T)
接着确定新坐标系的Y轴。我常用光轴方向与基线的叉积,比直接使用默认轴更稳定:
python复制left_optical_axis = R_left @ np.array([0,0,1]) # 左相机原光轴
e2 = np.cross(e1, left_optical_axis)
e3 = np.cross(e1, e2) # 确保右手坐标系
R_new = np.vstack([e1, e2, e3]).T
校正后还有个隐藏坑点:图像有效区域会缩小。我的解决方案是:
在机器人导航项目中,我几乎试遍了所有主流匹配算法。这里分享真实场景的对比数据:
全局算法(如Graph Cut):
局部算法(如SAD):
半全局算法(SGM):
python复制stereo = cv2.StereoSGBM_create(
minDisparity=0,
numDisparities=64, # 每增加16级显存占用翻倍
blockSize=5, # 奇数且不宜超过11
P1=8*3*5**2, # 平滑度约束参数
P2=32*3*5**2,
disp12MaxDiff=1 # 左右一致性检查阈值
)
最近在嵌入式设备上的优化让我发现:采用金字塔分层处理,先用低分辨率快速估计视差范围,再在高分辨率层细化,能节省40%计算量。