OpenCV46:立体图像的深度图|Depth Map

本文介绍了如何利用OpenCV的StereoBM算法从立体图像对中创建深度图。通过匹配两个不同视角的图像像素,计算视差以确定场景的深度信息。文章详细解释了基础理论,包括对极约束,并展示了简单的代码示例,演示了如何处理图像以得到视差图。尽管结果可能受到噪声影响,但通过调整算法参数,可以提高深度图的质量。关键词涵盖立体视觉、深度图、OpenCV、StereoBM、图像处理和计算机视觉。

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

目标

在本节中,将学习

  • 根据立体图像创建深度图

基础

在上一节中,看到了对极约束和其他相关术语等基本概念。如果有两个场景相同的图像,则可以通过直观的方式从中获取深度信息。下面是一张图片和一些简单的数学公式证明了这种想法。

stereo_depth.jpg

上图包含等效三角形。编写它们的等式将产生以下结果:

d i s p a r i t y = x − x ′ = B f Z disparity = x - x' = \frac{Bf}{Z} disparity=xx=ZBf

x x x x ′ x' x是图像平面中与场景点3D相对应的点与其相机中心之间的距离。 B B B是两个摄像机之间的距离(已知), f f f是摄像机的焦距(已知)。简而言之,上述方程式表示场景中某个点的深度与相应图像点及其相机中心的距离差成反比。因此,利用此信息,可以得出图像中所有像素的深度。

因此,可以在两个图像之间先找到对应的匹配项。一旦找到匹配项,就能获得深度(disparity)。

代码

下面的代码片段显示创建视差图的简单过程。

import cv2
import numpy as np
from matplotlib import pyplot as plt

imgL = cv2.imread('tsukuba_l.png', 0)
imgR = cv2.imread('tsukuba_r.png', 0)

stereo = cv2.StereoBM_create(numDisparities=16, blockSize=15)
disparity = stereo.compute(imgL, imgR)
plt.subplot(131)
plt.imshow(imgL, 'gray')
plt.title('imgL')
plt.xticks([])
plt.yticks([])
plt.subplot(132)
plt.imshow(imgR, 'gray')
plt.title('imgR')
plt.xticks([])
plt.yticks([])
plt.subplot(133)
plt.imshow(disparity, 'gray')
plt.title('disparity')
plt.xticks([])
plt.yticks([])

plt.show()

下面的图像包含原始图像(左)及其视差图(右)。如图所见,结果受到高度噪声的污染。通过

调整numDisparitiesblockSize的值,可以获得更好的结果。

在这里插入图片描述

当熟悉StereoBM后,可以微调一些参数以获得更好、更平滑的结果。部分参数如下所示:

  • texture_threshold:过滤出没有足够纹理的区域以获得可靠匹配的区域

  • Speckle range 和 size:基于块的匹配器通常会在对象边界附近产生“斑点”,其中匹配窗口捕获一侧的前景和在另一场景中的背景,在此场景中,匹配器还在桌子上找到的小片虚假匹配。要摆脱这些问题,可以使用speckle_sizespeckle_range参数来控制后处理的深度图像。speckle_size是视差斑点下的像素数,speckle_range控制必须被视为相同斑点的一部分最近距离

  • Number of disparities:滑动窗口的像素数。越大表明可见深度的范围就越大,但是需要更多的计算代价,最大视差值与最小视差值之差, 窗口大小必须是16的整数倍,int 型

  • min_disparity:从开始搜索的左像素的x位置开始的偏移量

  • uniqueness_ratio:另一个后过滤步骤。如果最佳匹配视差不足够好于搜索范围中的所有其他视差,则将像素滤出。如果texture_threshold和斑点过滤仍在通过虚假匹配,则可以尝试进行调整

  • prefilter_size和prefilter_cap:预过滤阶段,可标准化图像亮度并增强纹理,以准备块匹配。通常,不需要调整这些参数

附加资源

### 实现双目视差深度图 要在 Jupyter Notebook 中使用 OpenCV 和 Python 生成双目视差深度图,可以按照以下方法操作: #### 准备工作 首先,在环境中安装必要的库 `opencv-python` 和 `opencv-contrib-python`。这可以通过以下命令完成: ```bash pip install opencv-python pip install opencv-contrib-python ``` 接着,启动 Jupyter Notebook 并新建一个 Python 文件。 #### 加载图像 为了计算双目视差图,需要加载两幅来自不同视角的图像(左相机和右相机)。以下是加载图像的代码示例[^3]: ```python import cv2 import numpy as np # 加载左右图像 left_image = cv2.imread('left.jpg', cv2.IMREAD_GRAYSCALE) right_image = cv2.imread('right.jpg', cv2.IMREAD_GRAYSCALE) if left_image is None or right_image is None: raise ValueError("无法加载图像,请检查路径") cv2.imshow("Left Image", left_image) cv2.imshow("Right Image", right_image) cv2.waitKey(0) cv2.destroyAllWindows() ``` #### 配置立体匹配参数 OpenCV 提供了多种算法来计算视差图,最常用的是 StereoBM 和 StereoSGBM。这里以 StereoBM 为例展示其配置过程[^4]: ```python # 设置立体匹配对象 stereo_bm = cv2.StereoBM_create(numDisparities=16*8, blockSize=15) # 计算视差图 disparity_map = stereo_bm.compute(left_image, right_image).astype(np.float32) / 16.0 # 显示视差图 cv2.imshow("Disparity Map", (disparity_map - disparity_map.min()) / (disparity_map.max() - disparity_map.min())) cv2.waitKey(0) cv2.destroyAllWindows() ``` #### 转换为深度图 一旦获得了视差图,可以根据三角测量原理将其转换为深度图。假设已知焦距 \(f\) 和基线距离 \(B\),则深度 \(Z\) 的计算公式为: \[ Z = \frac{f \cdot B}{d} \] 其中 \(d\) 是视差值。以下是实现该公式的代码片段: ```python # 已知参数 baseline = 0.1 # 基线距离(单位:米) focal_length = 249.82379 # 焦距(像素) # 将视差图转换为深度图 depth_map = focal_length * baseline / (disparity_map + 1e-7) # 添加一个小数防止除零错误 # 归一化并显示深度图 normalized_depth = cv2.normalize(depth_map, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F) cv2.imshow("Depth Map", normalized_depth) cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上步骤展示了如何在 Jupyter Notebook 中使用 OpenCV 和 Python 来生成双目视差深度图。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

uncle_ll

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值