OpenCV 4.11.0
开源计算机视觉库
加载中…
搜索中…
无匹配项
基于立体图像的深度图

目标

在本教程中,

  • 我们将学习如何从立体图像创建深度图。

基础知识

在上一个教程中,我们学习了像极线约束等基本概念以及其他相关术语。我们还了解到,如果我们有两张同一场景的图像,我们可以通过直观的方式获得深度信息。下图是一个图像和一些简单的数学公式,证明了这种直觉。(图像来源

图像

上图包含等价三角形。写出它们的等价方程将得到以下结果:

\[视差 = x - x' = \frac{Bf}{Z}\]

\(x\) 和 \(x'\) 是图像平面上对应于场景点 3D 及其相机中心的点之间的距离。\(B\) 是两个相机之间的距离(已知),\(f\) 是相机的焦距(已知)。简而言之,上述等式表明,场景中一个点的深度与对应图像点与其相机中心距离差成反比。因此,利用此信息,我们可以推导出图像中所有像素的深度。

所以它会在两张图像之间找到对应的匹配项。我们已经看到极线约束如何使此操作更快更准确。一旦找到匹配项,它就会找到视差。让我们看看如何用OpenCV来实现。

代码

以下代码片段展示了一个创建视差图的简单过程。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
imgL = cv.imread('tsukuba_l.png', cv.IMREAD_GRAYSCALE)
imgR = cv.imread('tsukuba_r.png', cv.IMREAD_GRAYSCALE)
stereo = cv.StereoBM.create(numDisparities=16, blockSize=15)
disparity = stereo.compute(imgL,imgR)
plt.imshow(disparity,'gray')
plt.show()
static Ptr< StereoBM > create(int numDisparities=0, int blockSize=21)
创建 StereoBM 对象。
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
从文件中加载图像。

下图包含原始图像(左)及其视差图(右)。正如你所看到的,结果包含高度的噪声。通过调整 numDisparities 和 blockSize 的值,你可以得到更好的结果。

图像

当你熟悉 StereoBM 时,会有一些参数,你可能需要微调参数以获得更好更平滑的结果。参数

  • 纹理阈值:过滤掉缺乏足够纹理以进行可靠匹配的区域。
  • 斑点范围和大小:基于块的匹配器经常在物体边界附近产生“斑点”,在这些边界上,匹配窗口在一侧捕获前景,在另一侧捕获背景。在这个场景中,似乎匹配器还在桌子上投影的纹理中找到小的虚假匹配。为了去除这些伪影,我们使用斑点过滤器对视差图像进行后处理,该过滤器由 speckle_size 和 speckle_range 参数控制。speckle_size 是小于该值的像素数,低于该值的视差斑点将被视为“斑点”而被忽略。speckle_range 控制视差必须有多接近才能被认为是同一斑点的一部分。
  • 视差数量:窗口滑动多少像素。它越大,可见深度的范围越大,但需要更多的计算。
  • 最小视差:从左像素的 x 位置开始搜索的偏移量。
  • 唯一性比率:另一个后过滤步骤。如果最佳匹配视差不足以优于搜索范围内的其他每个视差,则会过滤掉该像素。如果纹理阈值和斑点过滤仍然允许虚假匹配通过,你可以尝试调整此参数。
  • 预滤波器大小和预滤波器上限:预滤波阶段,该阶段对图像亮度进行归一化并增强纹理,为块匹配做准备。通常情况下,你不应该需要调整这些。

这些参数在算法初始化后使用专用的设置器和获取器进行设置,例如 setTextureThresholdsetSpeckleRangesetUniquenessRatio 等。有关详细信息,请参阅 cv::StereoBM 文档。

额外资源

练习

  1. OpenCV 示例包含生成视差图及其 3D 重建的示例。检查 OpenCV-Python 示例中的 stereo_match.py。