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

目标

在本节中,将学习

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

基础

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

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:预过滤阶段,可标准化图像亮度并增强纹理,以准备块匹配。通常,不需要调整这些参数

附加资源

### 使用OpenCV实现图像中物体的距离测量 #### 单目相机下的距离测量方法 对于单目相机而言,要计算两个物体间的实际距离,需先校准相机并获取像素到毫米的比例因子。通过已知尺寸的对象作为参照物来确定比例因子是常见做法之一[^1]。 ```python import cv2 import numpy as np def find_marker(image): gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) edged = cv2.Canny(blurred, 35, 125) contours, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) c = max(contours, key=cv2.contourArea) return cv2.minAreaRect(c) def distance_to_camera(knownWidth, focalLength, perWidth): return (knownWidth * focalLength) / perWidth image = cv2.imread('path/to/image.jpg') marker = find_marker(image) focalLength = 810.0 # Example value; this should be calibrated. inches = distance_to_camera(2.0, focalLength, marker[1][0]) ``` 上述代码展示了如何利用一个具有固定宽度的目标对象来进行焦距估计,并据此推算其他目标的实际大小或位置关系。 #### 双目立体视觉中的距离测量 当采用双目摄像头系统时,则可以借助视差图(disparity map)完成更精确的空间定位任务。具体来说就是比较同一场景由两台不同视角拍摄所得图片间对应点的位置差异,进而解算出该处离摄像机有多远[^2]。 ```python stereo = cv2.StereoBM_create(numDisparities=16, blockSize=15) disparity = stereo.compute(imgL, imgR).astype(np.float32) / 16.0 depth_map = baseline * f_x / disparity ``` 这里`imgL`, `imgR`分别代表左眼和右眼所见景象;而`baseline`表示双眼间距,`f_x`则是镜头内参里的水平方向焦距参数。最终得到的是深度图(depth map),它反映了各像素点至观察者眼睛所在平面的真实径向长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

uncle_ll

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

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

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

打赏作者

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

抵扣说明:

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

余额充值