当前位置:   article > 正文

双目三维重建:双目摄像头实现双目测距(Python)_cv2.reprojectimageto3d

cv2.reprojectimageto3d

双目三维重建-双目摄像头实现双目测距(Python)

目录

双目三维重建-双目摄像头实现双目测距(Python)

1.双目测距原理

2.双目测距实现

3.3D点云显示

4.双目摄像头实现双目测距(Python)

5.双目摄像头实现双目测距(OpenCV C++) 

6.双目摄像头实现双目测距(Android版本)


双目立体视觉深度相机实现双目测距功能,主要分为4个步骤:相机标定+双目校正+双目匹配+计算深度信息:

(1)相机标定:需要对双目相机进行标定,得到两个相机的内外参数、单应矩阵。
(2)  双目校正:根据标定结果对原始图像进行校正,校正后的两张图像位于同一平面且互相平行。
(3)双目匹配:对校正后的两张图像进行像素点匹配。
(4)计算深度图:根据匹配结果计算每个像素的深度,从而获得深度图。

本篇将着重介绍双目测距的深度图计算原理和实现,关于相机标定+双目校正+双目匹配等内容,鄙人已经整理了一个完整的项目内容,详情请查看博客《双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python

双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python_AI吃大瓜的博客-CSDN博客_双目相机三维重建​本博客将实现Python版本的双目三维重建系统,项目代码实现包含:`双目标定`,`立体校正(含消除畸变)`,`立体匹配`,`视差计算`和`深度距离计算/3D坐标计算` 的知识点。限于篇幅,本博客不会过多赘述算法原理,而是手把手教你,如果搭建一套属于自己的双目三维重建的系统。该系统包含:支持双USB连接线的双目摄像头支持单USB连接线的双目摄像头(左右摄像头被拼接在同一个视频中显示)支持单目相机标定:mono_camera_calibration.py支持双目相机标定:stereo_camerahttps://blog.csdn.net/guyuealian/article/details/121301896


1.双目测距原理

原理很简单,利用了相似三角形计算距离,所以双目测距的主要任务在于前期摄像头的定标、双目图像点的特征匹配上。 


2.双目测距实现

实现双目测距最关键的步骤是获得视差图,视差图计算请查看博客《双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python

得到了视差图之后,就可以计算像素深度了,在opencv中使用StereoRectify()函数可以得到一个重投影矩阵Q,它是一个4*4的视差图到深度图的映射矩阵(disparity-to-depth mapping matrix ),使用Q矩阵和cv2.reprojectImageTo3D即可实现将像素坐标转换为三维坐标,该函数会返回一个3通道的矩阵,分别存储X、Y、Z坐标(左摄像机坐标系下)。

  1. def reprojectImageTo3D(disparity, Q, _3dImage=None, handleMissingValues=None, ddepth=None):
  2. """
  3. :param disparity: 输入视差图
  4. :param Q: 输入4*4的视差图到深度图的映射矩阵,即重投影矩阵 通过stereoRectify得到
  5. (disparity-to-depth mapping matrix)
  6. :param _3dImage: 映射后存储三维坐标的图像
  7. contains 3D coordinates of the point (x,y) computed from the disparity map
  8. :param handleMissingValues: 计算得到的非正常值是否给值,如果为true则给值10000
  9. :param ddepth: 输出类型 -1 即默认为CV_32FC3 还可以是 CV_16S, CV_32S, CV_32F
  10. :return:
  11. """

运算如下:


 [X,Y,Z,W] ^T=Q*[x,y,disparity(x,y),1]^ T

_3dImage(x,y)=(X/W,Y/W,Z/W)

重投影矩阵Q中c_x​和c_y​为左相机主点在图像中的坐标,f为焦距,T_x​为两台相机投影中心间的平移(负值),即基线baseline,相当于平移向量T[0], c_{x}^{`}  ​是右相机主点在图像中的坐标。

其中Z即是深度距离depth:

其中 f 为焦距长度(像素焦距),b为基线长度,d为视差,c_{xl}​与c_{xr}​为两个相机主点的列坐标。

这里有个地方需要注意,如果获得视差图像是CV_16S类型的,这样的视差图的每个像素值由一个16bit表示,其中低位的4位存储的是视差值得小数部分,所以真实视差值应该是该值除以16。在进行映射后应该乘以16,以获得毫米级真实位置。

  1. def get_depth(self, disparity, Q, scale=1.0, method=False):
  2. """
  3. reprojectImageTo3D(disparity, Q),输入的Q,单位必须是毫米(mm)
  4. :param disparity: 视差图
  5. :param Q: 重投影矩阵Q=[[1, 0, 0, -cx]
  6. [0, 1, 0, -cy]
  7. [0, 0, 0, f]
  8. [1, 0, -1/Tx, (cx-cx`)/Tx]]
  9. 其中f为焦距,Tx相当于平移向量T的第一个参数
  10. :param scale: 单位变换尺度,默认scale=1.0,单位为毫米
  11. :return depth:ndarray(np.uint16),depth返回深度图, 即距离
  12. """
  13. # 将图片扩展至3d空间中,其z方向的值则为当前的距离
  14. if method:
  15. points_3d = cv2.reprojectImageTo3D(disparity, Q) # 单位是毫米(mm)
  16. x, y, depth = cv2.split(points_3d)
  17. else:
  18. # baseline = abs(camera_config["T"][0])
  19. baseline = 1 / Q[3, 2] # 基线也可以由T[0]计算
  20. fx = abs(Q[2, 3])
  21. depth = (fx * baseline) / disparity
  22. depth = depth * scale
  23. # depth = np.asarray(depth, dtype=np.uint16)
  24. depth = np.asarray(depth, dtype=np.float32)
  25. return depth
  • 运行demo.py后,鼠标点击图像任意区域,终端会打印对应距离
  • 鼠标点击手部区域会打印距离摄像头的距离约633mm,即0.63米,还是比较准的
  1. (x,y)=(203,273),depth=633.881653mm
  2. (x,y)=(197,329),depth=640.386047mm
  3. (x,y)=(222,292),depth=631.549072mm
  4. (x,y)=(237,270),depth=630.389221mm
  5. (x,y)=(208,246),depth=652.560669mm

 双目测距的精度 说明:

根据上式可以看出,某点像素的深度精度取决于该点处估计的视差d的精度。假设视差d的误差恒定,当测量距离越远,得到的深度精度则越差,因此使用双目相机不适宜测量太远的目标。

如果想要对与较远的目标能够得到较为可靠的深度,一方面需要提高相机的基线距离,但是基线距离越大,左右视图的重叠区域就会变小,内容差异变大,从而提高立体匹配的难度,另一方面可以选择更大焦距的相机,然而焦距越大,相机的视域则越小,导致离相机较近的物体的距离难以估计。

理论上,深度方向的测量误差与测量距离的平方成正比,而X/Y方向的误差与距离成正比;而距离很近时,由于存在死角,会导致难以匹配的问题;想象一下,如果你眼前放置一块物体,那你左眼只能看到物体左侧表面,右眼同理只能看到物体右侧表面,这时由于配准失败,导致视差计算失败;这个问题在基线越长,问题就越严重


双目立体视觉系统精度分析_3D Vision-CSDN博客_双目视觉定位精度在一个三维测量项目中,如果采用立体视觉方案,首先,要根据测量需求(精度、测量范围、速度等),确定立体视觉的硬件方案。Thomas Luhmann在他的《Close-Range Photogrammetry and 3D Imaging》(2014)中,给出立体视觉系统的简化分析方法。这个方法假设两个相机的光轴平行,基线与光轴垂直,基线长度b和焦距值c不存在误差。分析了图像处理误差对立体定位https://blog.csdn.net/xuyuhua1985/article/details/50151269


3.3D点云显示

恢复三维坐标后,就可以使用python-pcl和Open3D库显示点云图

PCL Python版比较难安装,如果安装不了,那可以采用Open3D勉强凑合使用吧

如下图所示,你可以用鼠标旋转坐标轴,放大点云

2D-RGBOpen3D点云显示PCL点云显示

  1. def show_3dcloud_for_open3d(self, frameL, frameR, points_3d):
  2. """
  3. 使用open3d显示点云
  4. :param frameL:
  5. :param frameR:
  6. :param points_3d:
  7. :return:
  8. """
  9. if self.use_open3d:
  10. x, y, depth = cv2.split(points_3d) # depth = points_3d[:, :, 2]
  11. self.open3d_viewer.show(color_image=frameL, depth_image=depth)
  12. def show_3dcloud_for_pcl(self, frameL, frameR, points_3d):
  13. """
  14. 使用PCL显示点云
  15. :param frameL:
  16. :param frameR:
  17. :param points_3d:
  18. :return:
  19. """
  20. if self.use_pcl:
  21. self.pcl_viewer.add_3dpoints(points_3d, frameL)
  22. self.pcl_viewer.show()

4.双目摄像头实现双目测距(Python)

完整的项目代码双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python源码

双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python_AI吃大瓜的博客-CSDN博客_双目相机三维重建​本博客将实现Python版本的双目三维重建系统,项目代码实现包含:`双目标定`,`立体校正(含消除畸变)`,`立体匹配`,`视差计算`和`深度距离计算/3D坐标计算` 的知识点。限于篇幅,本博客不会过多赘述算法原理,而是手把手教你,如果搭建一套属于自己的双目三维重建的系统。该系统包含:支持双USB连接线的双目摄像头支持单USB连接线的双目摄像头(左右摄像头被拼接在同一个视频中显示)支持单目相机标定:mono_camera_calibration.py支持双目相机标定:stereo_camerahttps://blog.csdn.net/guyuealian/article/details/121301896


5.双目摄像头实现双目测距(OpenCV C++) 

目前已经实现了OpenCV C++版本的双目测距,与Python版本效果几乎一致,

详细请查看鄙人另一篇博客《双目摄像头实现双目测距(C++)OpenCV C++双目三维重建:双目摄像头实现双目测距

6.双目摄像头实现双目测距(Android版本)

如果你需要Android版本的双目测距, 请查看鄙人另一篇博客《Android OpenCV实现双目三维重建:双目摄像头实现双目测距

       

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/152879
推荐阅读
相关标签
  

闽ICP备14008679号