双目立体视觉之深度估计

本文探讨了为何双目相机能获取深度信息而单目相机不能,指出人眼的先验知识和运动恢复结构在单目深度推断中的作用。通过理想双目相机成像模型,解释了深度值计算的几何原理,强调了相机焦距、基线长度和视差在深度估计中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 为什么非得用双目相机才能得到深度?

说到这里,有些读者会问啦:为什么非得用双目相机才能得到深度?我闭上一只眼只用一只眼来观察,也能知道哪个物体离我近哪个离我远啊!是不是说明单目相机也可以获得深度?

在此解答一下:首先,确实人通过一只眼也可以获得一定的深度信息,不过这背后其实有一些容易忽略的因素在起作用:一是因为人本身对所处的世界是非常了解的(先验知识),因而对日常物品的大小是有一个基本预判的(从小到大多年的视觉训练),根据近大远小的常识确实可以推断出图像中什么离我们远什么离我们近;二是人在单眼观察物体的时候其实人眼是晃动的,相当于一个移动的单目相机,这类似于运动恢复结构(Structure from Motion, SfM)的原理,移动的单目相机通过比较多帧差异确实可以得到深度信息。

但是实际上,相机毕竟不是人眼,它只会傻傻的按照人的操作拍照,不会学习和思考。下图从物理原理上展示了为什么单目相机不能测量深度值而双目可以的原因。我们看到红色线条上三个不同远近的黑色的点在下方相机上投影在同一个位置,因此单目相机无法分辨成的像到底是远的那个点还是近的那个点,但是它们在上方相机的投影却位于三个不同位置,因此通过两个相机的观察可以确定到底是哪一个点。
这里写图片描述
- 理想双目相机成像模型

首先我们从理想的情况开始分析:假设左右两个相机位于同一平面(光轴平行),且相机参数(如焦距f)一致。那么深度值的推导原理和公式如下。公式只涉及到初中学的三角形相似知识,不难看懂。
这里写图片描述

根据上述推导,空间点P离相机的距离(深度)z=f*b/d,可以发现如果要计算深度z,必须要知道:

1、相机焦距f,左右相机基线b。这

### 双目立体视觉深度估计算法实现原理 双目立体视觉的核心目标是从两幅或多幅图像中恢复场景的三维信息,其中深度估计是最基础也是最重要的部分之一。以下是关于双目立体视觉深度估计算法的具体实现原理及相关代码。 #### 1. 立体视觉的基础理论 立体视觉依赖于两个摄像头获取同一场景的不同视角图像,并通过比较这些图像中的像素位置差异(称为视差)来推断物体的距离。视差 \(d\) 和深度 \(Z\) 的关系可以通过以下公式描述[^2]: \[ Z = \frac{fB}{d} \] 其中: - \(f\) 是焦距, - \(B\) 是基线距离(即两个摄像头之间的水平间距), - \(d\) 是视差值。 该公式的前提是假设成像平面是平行的,这简化了许多实际操作中的复杂性[^4]。 #### 2. 深度估计的关键步骤 为了完成深度估计,通常需要以下几个关键步骤: ##### (1) 图像校正 由于实际拍摄过程中可能存在镜头畸变或其他误差,因此需先对输入的左、右图像进行校正。OpenCV 提供了 `stereoRectify` 函数用于生成矫正变换矩阵[^1]。 ```python import cv2 import numpy as np # 加载相机参数 cameraMatrixL, distCoeffsL, cameraMatrixR, distCoeffsR, R, T, E, F = load_camera_params() # 获取校正映射 RL, RR, PL, PR, Q, validPixROI1, validPixROI2 = \ cv2.stereoRectify(cameraMatrixL, distCoeffsL, cameraMatrixR, distCoeffsR, img_shape, R, T) mapL_x, mapL_y = cv2.initUndistortRectifyMap(cameraMatrixL, distCoeffsL, RL, PL, img_shape, cv2.CV_32FC1) mapR_x, mapR_y = cv2.initUndistortRectifyMap(cameraMatrixR, distCoeffsR, RR, PR, img_shape, cv2.CV_32FC1) # 应用校正 imgL_rectified = cv2.remap(imgL, mapL_x, mapL_y, cv2.INTER_LINEAR) imgR_rectified = cv2.remap(imgR, mapR_x, mapR_y, cv2.INTER_LINEAR) ``` ##### (2) 特征匹配与视差图生成 特征匹配的目标是在左右图像之间找到对应的点对。常用的方法有基于块匹配(Block Matching)和半全局匹配(Semi-Global Block Matching, SGBM)。下面是一个使用 OpenCV 中 SGBM 方法的例子: ```python def compute_disparity_map(imgL, imgR): window_size = 3 min_disp = 0 num_disp = 16 * 8 stereo = cv2.StereoSGBM_create( minDisparity=min_disp, numDisparities=num_disp, blockSize=window_size, uniquenessRatio=10, speckleWindowSize=100, speckleRange=32, disp12MaxDiff=1, P1=8 * 3 * window_size ** 2, P2=32 * 3 * window_size ** 2 ) disparity = stereo.compute(imgL, imgR).astype(np.float32) / 16.0 return disparity ``` ##### (3) 深度图转换 一旦获得了视差图,就可以利用前述公式将其转化为深度图。具体过程如下所示: ```python def convert_disparity_to_depth(disparity_map, focal_length, baseline): depth_map = (focal_length * baseline) / (disparity_map + 1e-7) # 防止除零错误 return depth_map ``` #### 3. 完整流程示例 综合上述各步,完整的双目深度估计算法可按以下方式实现: ```python if __name__ == "__main__": # 步骤 1: 载入并校正图像 imgL = cv2.imread('left_image.png', 0) imgR = cv2.imread('right_image.png', 0) imgL_rectified, imgR_rectified = rectify_images(imgL, imgR) # 步骤 2: 计算视差图 disparity_map = compute_disparity_map(imgL_rectified, imgR_rectified) # 步骤 3: 将视差图转为深度图 focal_length = 500 # 单位:像素 baseline = 0.1 # 单位:米 depth_map = convert_disparity_to_depth(disparity_map, focal_length, baseline) # 显示结果 plt.figure(figsize=(10, 5)) plt.subplot(1, 2, 1), plt.imshow(disparity_map, cmap='gray'), plt.title("Disparity Map") plt.subplot(1, 2, 2), plt.imshow(depth_map, cmap='jet'), plt.title("Depth Map") plt.show() ``` --- ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值