使用普通摄像头进行深度估计
本文根据《OpenCV3计算机视觉Python语言实现第二版》,进行代码编写,感谢本书作者的辛勤付出!
视差图-原理说明
深度摄像头:将传统摄像头和一个红外传感器相结合来帮助摄像头区别相似物体并计算他们与摄像头之间的距离。
普通摄像头:使用几何学中的极几何(Epipolar Geometry),从同一物体的两张不同图像提取三维信息。它跟踪从摄像头到图像上每一个物体的虚线,然后在第二张图像做同样的操作,并根据同一物体的对应的线交叉来计算距离。下图为概念示意图:
视差图-代码
import numpy as np
import cv2
#使用普通摄像头进行深度估计
def update(val=0):
#为“alone”图像对调整视差范围
stereo.setBlockSize(cv2.getTrackbarPos('window_size','disparity'))
stereo.setUniquenessRatio(cv2.getTrackbarPos('uniquenessRatio','disparity'))
stereo.setSpeckleWindowSize(cv2.getTrackbarPos('speckleWindowSize','disparity'))
stereo.setSpeckleRange(cv2.getTrackbarPos('speckleRange','disparity'))
stereo.setDisp12MaxDiff(cv2.getTrackbarPos('disp12MaxDiff','disparity'))
print('computing disparity')
disp = stereo.compute(imgL,imgR).astype(np.float32)/16.0
cv2.imshow('left',imgL)
cv2.imshow('disparity',(disp-min_disp)/num_disp)
if __name__ == "__main__":
window_size =5
min_disp =16
num_disp =192-min_disp
blockSize = window_size
uniquenessRatio = 1
speckleRange = 3
speckleWindowSize =3
disp12MaxDiff =200
P1 = 600
P2 = 2400
imgL = cv2.imread('../image/test3.JPG') #加载图像 1 C:/Users/Administrator/Desktop/test3
imgR = cv2.imread('../image/test4.JPG')
cv2.namedWindow('disparity')
cv2.createTrackbar('speckleRange','disparity',speckleRange,50,update)
cv2.createTrackbar('window_size','disparity',window_size,21,update)
cv2.createTrackbar('speckleWindowSize','disparity',speckleWindowSize,200,update)
cv2.createTrackbar('uniquenessRatio','disparity',uniquenessRatio,50,update)
cv2.createTrackbar('disp12MaxDiff','disparity',disp12MaxDiff,250,update)
stereo =cv2.StereoSGBM_create(
minDisparity = min_disp,
numDisparities=num_disp,
blockSize = window_size,
uniquenessRatio = uniquenessRatio,
speckleRange = speckleRange,
speckleWindowSize = speckleWindowSize,
disp12MaxDiff = disp12MaxDiff,
P1 = P1,
P2 = P2
)
update()
cv2.waitKey()
使用函数介绍
cv2.StereoSGBM_create
cv2.StereoSGBM_create(
[,minDisparity
[,numDisparities
[,blockSize
[,P1
[,P2
[,disp12MaxDiff
[,preFilterCap
[,uniquenessRatio
[,speckleWindowSize
[,speckleRange
[,mode]]]]]]]]]]]])
参数 | 介绍 |
---|---|
minDisparity | 最小可能的差异值。通常情况下,它是零,但有时整流算法可能会改变图像,所以这个参数需要作相应的调整。 |
numDisparities | 最大差异减去最小差异。该值总是大于零。在当前的实现中,该参数必须可以被16整除。 |
blockSize | 匹配的块大小。它必须是> = 1的奇数。通常情况下,它应该在3…11的范围内。 |
P1 | 控制视差平滑度的第一个参数。见下文。 |
P2 | 第二个参数控制视差平滑度。值越大,差异越平滑。P1是相邻像素之间的视差变化加或减1的惩罚。P2是相邻像素之间的视差变化超过1的惩罚。该算法需要P2> P1。请参见stereo_match.cpp示例,其中显示了一些相当好的P1和P2值(分别为8 * number_of_image_channels * SADWindowSize * SADWindowSize和32 * number_of_image_channels * SADWindowSize * SADWindowSize)。 |
disp12MaxDiff | 左右视差检查中允许的最大偏差(整数像素为单位)。设为非正值将不做检查。 |
preFilterCap | 预滤波图像像素的截断值。该算法首先计算每个像素的x导数,并通过[-preFilterCap,preFilterCap]间隔剪切其值。结果值传递给Birchfield-Tomasi像素成本函数。 |
uniquenessRatio | 最佳(最小)计算成本函数值应该“赢”第二个最佳值以考虑找到的匹配正确的百分比保证金。通常,5-15范围内的值就足够了。 |
speckleWindowSize | 平滑视差区域的最大尺寸,以考虑其噪声斑点和无效。将其设置为0可禁用斑点过滤。否则,将其设置在50-200的范围内。 |
speckleRange | 每个连接组件内的最大视差变化。如果你做斑点过滤,将参数设置为正值,它将被隐式乘以16.通常,1或2就足够好了。 |
mode | 将其设置为StereoSGBM :: MODE_HH以运行全尺寸双通道动态编程算法。它将消耗O(W * H * numDisparities)字节,这对640x480立体声很大,对于HD尺寸的图片很大。默认情况下,它被设置为false。 |
运行结果
视差图和景深的关系推导
原理说明
经过双目相机标定和校准后,双目相机的主光轴到达平行,如图所示是双目相机模型,世界坐标系中的任意一点都满足,该点与它在左右相机的成像点在同一个极平面上。OL和OR是左右相机的的光心,长为L的两条线段(端点为蓝色星星的线段)表示的是左右相机的像面。则光心到像面的最短距离就是焦距长度f。若P是世界坐标系中的一点,它在左右像面上的成像点是PL和PR。PL和PR距各自像面的左边缘的距离是XL和XR。视差就是XR-XL或者是XL-XR。标定和匹配后f,b,XR,XL都能够得到,那么物体的景深Z是多少呢?它和物体的视差有什么关系呢?
方法:相似三角形
三角形1:PL-PR-P
三角形2:OL-OR-P
焦距长度: f
景深: Z
两个三角形相似:
这样只要求得XR-XL就可以知道Z了