目标
在本节中,
基础知识
在上一节中,我们看到了诸如极线约束和其他相关术语等基本概念。我们还看到,如果我们有同一场景的两幅图像,我们可以从中直观地获得深度信息。下面是一张图片和一些简单的数学公式,证明了这种直觉。(图片来自
image
上图包含等效三角形。写出它们的等效方程将得到以下结果
\[disparity = 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)
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 的值,你可以获得更好的结果。
image
当你熟悉 StereoBM 时,有一些参数,你可能需要微调这些参数以获得更好和更平滑的结果。参数
- texture_threshold:过滤掉纹理不足以进行可靠匹配的区域
- Speckle range 和 size:基于块的匹配器通常在对象的边界附近产生“斑点”,匹配窗口在一侧捕获前景,另一侧捕获背景。在此场景中,匹配器似乎也在桌子上找到投影纹理中的小杂散匹配。为了消除这些伪影,我们使用由 speckle_size 和 speckle_range 参数控制的斑点滤波器对视差图像进行后处理。 speckle_size 是将视差斑点视为“斑点”而忽略的像素数。 speckle_range 控制视差值必须有多接近才能被视为同一斑点的一部分。
- Number of disparities:窗口滑过的像素数。它越大,可见深度的范围越大,但需要更多的计算。
- min_disparity:从左侧像素的 x 位置开始搜索的偏移量。
- uniqueness_ratio:另一个后过滤步骤。如果最佳匹配视差没有明显优于搜索范围内的每个其他视差,则会滤除该像素。如果 texture_threshold 和斑点过滤仍然允许通过杂散匹配,你可以尝试调整此值。
- prefilter_size 和 prefilter_cap:预过滤阶段,它标准化图像亮度并增强纹理,为块匹配做准备。通常你不需要调整这些。
这些参数在使用算法初始化后通过专用的 setter 和 getter 设置,例如 setTextureThreshold、setSpeckleRange、setUniquenessRatio 等。有关详细信息,请参见 cv::StereoBM 文档。
附加资源
练习
- OpenCV 示例包含生成视差图及其 3D 重建的示例。查看 OpenCV-Python 示例中的 stereo_match.py。