使用StereoBM获取绝对视差以测量绝对距离的技术咨询
如何从立体图像得到绝对视差并测量绝对距离
嘿,这个问题问到点子上了!你现在用StereoBM得到的视差图确实是相对尺度的灰度表示——白色只是当前计算范围内的最大视差像素值,和真实物理距离完全不挂钩。要拿到能测绝对距离的绝对视差,得走完「相机标定→立体校正→视差还原→深度计算」这一套流程,咱们一步步说:
为什么当前结果是相对的?
cv2.StereoBM.compute()返回的其实是16位有符号整数的视差数据,你把它直接当灰度图显示时,OpenCV会自动把数值归一化到0-255范围,所以白色只是相对最大值,丢失了真实的像素视差数值,更没法关联到物理尺度。
拿到绝对视差&测量距离的关键步骤
1. 先完成双目相机标定
这是核心前提——你必须知道左右相机的内参(焦距、主点坐标)、畸变系数,以及两相机之间的平移/旋转关系(基线距离就藏在平移矩阵里)。
- 用棋盘格标定板拍摄多组左右视角的图像,然后用
cv2.calibrateCamera()分别标定单目相机,再用cv2.stereoCalibrate()得到双目系统的外参(旋转矩阵R、平移矩阵T)。 - 标定后你能拿到焦距
f(像素单位,从内参矩阵的[0,0]或[1,1]位置取值),以及基线B(物理单位,比如米,一般是平移矩阵T的x分量绝对值,因为双目相机通常水平放置)。
2. 对图像做立体校正
标定后需要把左右图像校正到极线平行的状态,这样StereoBM的匹配精度会更高,也方便后续的视差转深度:
- 用
cv2.stereoRectify()计算校正映射,再用cv2.remap()分别对左右灰度图做校正。
3. 还原真实的绝对视差数值
StereoBM的视差结果是乘以16存储的(为了保留小数精度),所以要先还原成真实的像素视差:
# 从StereoBM得到原始视差(16位整数) disparity_raw = stereo.compute(l1_rectified, l2_rectified) # 转换为浮点型的真实视差(像素数) disparity = disparity_raw.astype(np.float32) / 16.0 # 过滤无效视差(比如小于等于0的区域,代表匹配失败) disparity[disparity <= 0] = np.inf
4. 用三角测量公式计算绝对距离
有了视差、焦距和基线,就能用经典的立体视觉公式计算深度(绝对距离):
depth = (f * B) / disparity
depth的单位和基线B一致(比如米),值越小代表物体越近。
完整示例代码
import cv2 import numpy as np # 替换成你自己标定得到的参数! fx = 600.0 # 相机焦距(像素单位) B = 0.12 # 双目基线(米,比如12厘米) # 读取图像 imgL = cv2.imread("left_img.jpg") imgR = cv2.imread("right_img.jpg") grayL = cv2.cvtColor(imgL, cv2.COLOR_BGR2GRAY) grayR = cv2.cvtColor(imgR, cv2.COLOR_BGR2GRAY) # 这里省略标定和校正步骤,假设你已经得到校正后的grayL_rectified和grayR_rectified # 如果没校正,也可以直接用原始图,但匹配精度会下降 # 立体匹配 stereo = cv2.StereoBM_create(numDisparities=128, blockSize=15) disparity_raw = stereo.compute(grayL, grayR) # 还原真实视差 disparity = disparity_raw.astype(np.float32) / 16.0 disparity[disparity <= 0] = np.inf # 计算深度图(米) depth_map = (fx * B) / disparity # 可视化深度图(归一化到0-255方便显示) depth_vis = cv2.normalize(depth_map, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U) cv2.imshow("Absolute Depth Map", depth_vis) cv2.waitKey(0) cv2.destroyAllWindows()
注意事项
- 标定的精度直接决定了深度测量的准确性,建议拍摄15-20组不同角度、不同距离的棋盘格图像来标定。
- 视差图里难免会有噪声或匹配错误的区域,可以用
cv2.filterSpeckles()、中值滤波或者双边滤波来优化。 - 如果你的相机是已经预校正好的双目模组(比如Intel RealSense),可以直接拿到官方提供的内参和基线,不用自己标定。
内容的提问来源于stack exchange,提问作者Bart Friederichs
相关产品推荐
相关产品推荐

