首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OpenCV 深度估计

OpenCV 深度估计

作者头像
用户6021899
发布2019-09-12 12:52:42
2.2K0
发布2019-09-12 12:52:42
举报

先来介绍两个基本概念:

  • 深度图:它是灰度图像,该图像的每个像素值都是摄像头到物体表面之间的距离的估计值。
  • 视差图:它也是灰度图,该图像的每个像素值代表物体表面的立体视差。立体视差是指:假如将从不同视角观察同一场景得到的两张图像叠加到一起,针对两张图像中两个孪生的物体之间任意一对相互对应的像素点,我们可以估算这些像素点之间的距离。这个距离就是立体视差。近距离的物体会产生更大的角度偏移从而会导致更大的立体视差,远距离的就小一些。因此近距离的物体在视差图中会更明亮一些。对于视差的理解自己可以体验一下:将手指头放在离眼睛不同距离的位置,并轮换睁、闭左右眼,可以发现手指在不同距离的位置,视觉差也不同,且距离越近,视差越大。

深度摄像头(比如微软的Kinect)将传统摄像头和一个红外传感器相结合来帮助摄像头区别相似物体并计算它们与摄像头之间的距离。

深度摄像头虽好但却比较昂贵。我们还可以根据同一物体在不同视角下拍摄的两幅图像计算视差图来进行深度估计。但是要注意这两幅图像需是距物体相同距离拍摄的,否则计算将会失败。其中的原理涉及到几何学中的极几何(Epipolar Geomerty)。

可参考网上的这篇博文:http://www.elecfans.com/d/863829.html

下面的代码我们对左右两张图片使用OpenCV中的StereoSGBM算法来计算视差。

左图:

右图:

代码如下:

import numpy as npimport cv2

def update():    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    result =  (disp /disp.max()*255).astype(np.uint8)    print(imgL.shape)    print(disp)    print(result.shape)    print(result)    cv2.imshow('imgL',imgL )    cv2.imshow('disparity',result)   
window_size =5min_disp = 16num_disp = 64 #与视差图左边黑色区域的大小 正相关blockSize =window_sizeuniquenessRatio = 16speckleRange =3speckleWindowSize = 50disp12MaxDiff = 200P1= 600P2 =2400imgL=cv2.imread("L0.jpg")imgR=cv2.imread("R0.jpg")#imgL= cv2.cvtColor(cv2.imread("L0.jpg"), cv2.COLOR_BGR2GRAY) #不必要,输入可以是彩图#imgR= cv2.cvtColor(cv2.imread("R0.jpg"), cv2.COLOR_BGR2GRAY)
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()

上述代码在OpenCV图形界面绘制了若干滑动条,用以动态调整函数参数。视差图的计算结果如下:

视差图中明亮的部分更靠近摄像头(是前景),阴暗的部分远离摄像头(是背景)。

所获取的视差图总是在左侧和右侧有明显的黑色区域,这些区域没有有效的视差数据。视差图有效像素区域与视差窗口(ndisp,一般取正值且能被16整除)和最小视差值(mindisp,一般取0或负值)相关,视差窗口越大,视差图左侧的黑色区域越大,最小视差值越小,视差图右侧的黑色区域越大。其原因是为了保证参考图像(一般是左视图)的像素点能在目标图像(右视图)中按照设定的视差匹配窗口匹配对应点,OpenCV 只从参考图像的第 (ndisp - 1 + mindisp) 列开始向右计算视差,第 0 列到第 (ndisp - 1 + mindisp) 列的区域视差统一设置为 (mindisp - 1) *16;视差计算到第 width + mindisp 列时停止,余下的右侧区域视差值也统一设置为 (mindisp - 1) *16。

简单介绍一下StereoSGBM()中的几个参数的意义:

  • minDisparity 最小的是视差,一般设置为0
  • numDisparities 最大的视差,这个需要自己去定,这个数值比0大,而且要被16整除, 比如32, 64
  • windowSize 滑动窗口的大小,必须要大于1,一般取在3-11之间
  • P1 惩罚系数,用于控制图像的平滑,具体需要看这个函数的算法,很多博客有介绍P1和P2的惩罚系数
  • P2 惩罚系数
  • disp12MaxDiff 视图检查中允许的最大偏差。
  • preFilterCap 表示预过滤图像像素的截断值
  • uniquenessRatio 最好的代价方程值“赢了”第二好的代价方程值的概率,通常设置为5-15之间效果达到最佳
  • speckleWindowSize 针对散斑滤波的窗口大小,如果设置为0则不允许散斑滤波,否则设置为50-200之间
  • speckleRange- 相邻像素点的视差值浮动范围,通常设置为1-2就好了,这个系数会被乘以16输入到程序中
  • fullDP 如果是尺寸比较大的图片,这里设置为true,否则设置为false
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档