双目获取点云图过程和问题

参考:

https://blog.youkuaiyun.com/wangxiaokun671903/article/details/37935113

https://www.cnblogs.com/riddick/p/8486223.html

https://blog.youkuaiyun.com/FUZHENQI/article/details/80092605

 

结构框架

首先,将整个框架搭出来,我会按上面每一个过程进行问题提问与回答。

过程1——参数整定

双目矫正矫正的最终效果?

       双目校正就是通过一定的方法将两个摄像头拍摄同一个物体的图像进行处理,使得两幅图像最终达到下面的目标,同一个物体在两幅图像中的大小一样,且水平在一条直线上。

相机标定的内容?

1.内参标定:

      焦距fx,fy,图像物理坐标的扭曲因子gama,图像原点相对于光心成像点的的纵横偏移量cx和cy(像素为单位)

2.外参标定:

      世界坐标系转换到相机坐标系的旋转R和平移T矩阵。右相机相对于左相机的旋转矩阵R(通过一定的方法可将此矩阵分解成两个矩阵R1和R2,即左右相机各旋转一半达到水平)。

3.畸变系数:

      括相机的径向畸变系数k1,k2,k3,~,和相机的切向畸变系数p1,p2,~

针孔相机的模型?

 

世界坐标系:就是物体在真实世界中的坐标,比如黑白棋盘格的世界坐标系原点定在第一个棋盘格的顶点,XwYwZw互相垂直,Zw方向就是垂直于棋盘格面板的方向。可见世界坐标系是随着物体的大小和位置变化的,单位是长度单位。只要棋盘格的大小决定了,无论板子怎么动,棋盘格角点坐标一般就不再变动(因为是相对于世界坐标系原点的位置不变),且认为是Zw=0.

相机坐标系:以光心为相机坐标系的原点,以平行于图像的x和y方向为Xc轴和Yc轴,Zc轴和光轴平行,Xc,Yc,Zc互相垂直,单位是长度单位。

图像物理坐标系:以主光轴和图像平面交点为坐标原点,x和y方向如图所示,单位是长度单位。

图像像素坐标系:以图像的顶点为坐标原点,uv方向平行于xy方向,单位是以像素计。

 从世界坐标系到图像坐标系的转换过程如下:世界坐标系通过外参矩阵转换到相机坐标系,相机坐标系通过内参矩阵转换到图像像素坐标系(这一步是通过两步完成的,一,相机坐标系通过焦距对角矩阵和畸变系数转换到图像物理坐标系,二图像物理坐标系通过像素转换矩阵转换到像素坐标系中)。转换过程和公式如下:

过程2——极线矫正

极线矫正的过程是什么?

  双目平行校正,是针对图像对应的相机坐标系进行的,那么极线校正的时候应该注意就是在四中叙述的畸变校正过程中,在转换到相机坐标系后,左右图像对应的相机坐标系分别通过旋转矩阵R1R2进行平行极线校正。步骤如下:将源图像像素坐标系通过内参矩阵转化成相机坐标系(和图像物理坐标系比较多了缩放和Z轴),通过旋转矩阵R1R2进行平行极线校正,然后通过畸变系数校正图像的相机坐标,校正后通过内参矩阵将相机坐标系转换成图像像素坐标系,并根据源图像坐标的像素值赋值给新的图像坐标

极线矫正的目的?

       为了可以得出视差图。

过程3——畸变矫正

畸变矫正过程是什么?

   获取了内参矩阵和畸变系数对图像进行畸变校正时,就是解决图像的畸变问题(径向畸变是因为透镜本身工艺的问题,切向畸变是由于安装问题带来的)。畸变校正的过程是这样的,将源图像像素坐标系通过内参矩阵转化成相机坐标系(和图像物理坐标系比较多了缩放和Z轴),通过畸变系数校正图像的相机坐标,校正后通过内参矩阵将相机坐标系转换成图像像素坐标系,并根据源图像坐标的像素值赋值给新的图像坐标。

其中,k1,k2,k3径向畸变系数,p1,p2是切向畸变系数。畸变发生在相机坐标系转图像物理坐标系的过程中。操作的对象时相机坐标系。(Xc,Yc,Zc)为相机坐标系坐标。

过程4——视差图获取

视差图是什么?作用是什么?

立体校正后的左右两幅图像得到后,匹配点是在同一行上的,可以使用OpenCV中的BM算法或者SGBM算法计算视差图。由于SGBM算法的表现要远远优于BM算法,因此采用SGBM算法获取视差图。

P为空间中的点,P1和P2是点P在左右像平面上的成像点,f是焦距,OR和OT是左右相机的光心。由下图可见左右两个相机的光轴是平行的。XR和XT是两个成像点在左右两个像面上距离图像左边缘的距离。

(Xr-Xt)就可以得到P1点,在左视差图中的值,同理可以计算出整幅图像,最终获得左视差图。右视差图同理。

左边为左视差图,右边为右视差图。

 

过程5——空洞填补

为什么造成空洞?解决办法?

视差图中视差值不可靠的视差大多数是由于遮挡引起,或者光照不均匀引起。既然牛逼如SGBM也觉得不可靠,那与其留着做个空洞,倒不如用附近可靠的视差值填充一下。

  空洞填充也有很多方法,在这里我检测出空洞区域,然后用附近可靠视差值的均值进行填充。填充后的视差图如下:

填充后左视差图:

过程6——视差图计算深度图

深度图如何获取?

视差的单位是像素(pixel),深度的单位往往是毫米(mm)表示。而根据平行双目视觉的几何关系(此处不再画图推导,很简单),可以得到下面的视差与深度的转换公式:

 depth = ( f * baseline) / disp

   上式中,depth表示深度图;f表示归一化的焦距,也就是内参中的fx; baseline是两个相机光心之间的距离,称作基线距离;disp是视差值。等式后面的均已知,深度值即可算出。

过程7——深度图转换点云图

转换过程是什么?

p.z = double(d) / camera_factor;
p.x = (n - camera_cx) * p.z / camera_fx;
p.y = (m - camera_cy) * p.z / camera_fy;

 

<think>好的,我需要帮助用户获取D435摄像头生成深度图点云图的方法或代码示例。首先,我应该回忆一下关于Intel RealSense D435的知识。D435是Intel的一款深度相机,常用于计算机视觉机器人领域。它能够生成深度图像RGB图像,进而转换为点云数据。 用户提到了参考引用中的内容,特别是引用[1][2]提到了使用Open3D库处理深度图像生成点云。所以可能需要结合RealSense的SDKOpen3D来实现这个目标。另外,引用[3]提到利用激光雷达点云数据,但这里用户使用的是D435,所以应该专注于RealSense的SDK。 首先,用户需要安装必要的库。Intel RealSense通常使用pyrealsense2库,而处理点云可能需要Open3D或OpenCV。因此,安装步骤应包括pyrealsense2open3d。代码示例部分需要展示如何初始化D435摄像头,获取深度帧,然后转换为点云。 接下来,代码结构应该包括:初始化管道,配置摄像头流(深度颜色),捕获帧,对齐深度到颜色帧(如果需要),然后处理深度图像。生成点云可能需要将深度数据转换为点云,这里可以用Open3D的PointCloud类。 需要注意的点:RealSense的深度图是16位的,可能需要转换为适合Open3D处理的格式。另外,相机的内参对于正确生成点云很重要,需要从摄像头获取内参矩阵,包括fx, fy, cx, cy等参数。 可能还需要考虑坐标系的转换,比如将深度图中的每个像素转换为3D点。这涉及到使用相机的内参进行反投影。Open3D可能有现成的函数,或者需要手动计算。 此外,用户可能需要保存深度图点云,或者实时显示。代码示例应包括这些步骤,比如使用Open3D可视化点云。 还需要检查是否有常见的错误,比如未正确对齐帧,深度图缩放问题,或者内参获取错误。因此,代码中应有错误处理,确保正确获取设备信息。 最后,根据用户提供的引用,需要正确引用相关文献,比如引用[1][2]中的Open3D处理流程,可能的话,整合RealSense的代码Open3D的点云生成。 总结步骤: 1. 安装pyrealsense2open3d。 2. 初始化RealSense管道,获取深度颜色帧。 3. 对齐深度到颜色帧(可选)。 4. 转换深度图为点云,使用相机内参。 5. 使用Open3D可视化点云。 6. 处理可能的错误,确保代码正确运行。 现在需要将这些步骤转化为具体的代码示例,解释每一步的作用,同时引用相关的文献。</think>以下是使用Intel RealSense D435摄像头获取深度图像点云数据的完整方法及代码示例: ### 1. 环境配置 首先安装依赖库: ```bash pip install pyrealsense2 open3d numpy ``` ### 2. 获取深度图像基础代码 ```python import pyrealsense2 as rs import numpy as np import cv2 # 配置深度/颜色流 pipeline = rs.pipeline() config = rs.config() config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30) config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30) # 启动流 profile = pipeline.start(config) try: # 对齐深度到颜色帧 align_to = rs.stream.color align = rs.align(align_to) for _ in range(30): # 等待自动曝光稳定 frames = pipeline.wait_for_frames() # 获取帧数据 frames = pipeline.wait_for_frames() aligned_frames = align.process(frames) # 获取对齐后的深度帧颜色帧 depth_frame = aligned_frames.get_depth_frame() color_frame = aligned_frames.get_color_frame() # 转换为numpy数组 depth_image = np.asanyarray(depth_frame.get_data()) color_image = np.asanyarray(color_frame.get_data()) # 保存深度图(注意:需先转换为8位) depth_colormap = cv2.applyColorMap( cv2.convertScaleAbs(depth_image, alpha=0.03), cv2.COLORMAP_JET ) cv2.imwrite("depth.png", depth_colormap) finally: pipeline.stop() ``` ### 3. 生成点云数据 ```python import open3d as o3d # 获取相机内参 depth_intrin = depth_frame.profile.as_video_stream_profile().intrinsics camera_matrix = o3d.camera.PinholeCameraIntrinsic( width=depth_intrin.width, height=depth_intrin.height, fx=depth_intrin.fx, fy=depth_intrin.fy, cx=depth_intrin.ppx, cy=depth_intrin.ppy ) # 创建点云对象 point_cloud = o3d.geometry.PointCloud() # 生成点云 depth_image_o3d = o3d.geometry.Image(depth_image) color_image_o3d = o3d.geometry.Image(color_image) rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth( color_image_o3d, depth_image_o3d, depth_scale=1000.0, # D435深度单位为毫米 convert_rgb_to_intensity=False ) pcd = o3d.geometry.PointCloud.create_from_rgbd_image( rgbd_image, camera_matrix ) # 坐标系调整(可选) pcd.transform([[1,0,0,0],[0,-1,0,0],[0,0,-1,0],[0,0,0,1]]) # 保存点云 o3d.io.write_point_cloud("pointcloud.ply", pcd) # 可视化 o3d.visualization.draw_geometries([pcd]) ``` ### 关键参数说明 1. `depth_scale`:D435默认深度单位为毫米,需设置为1000.0 2. `align.process()`:实现深度与彩色图像对齐[^1] 3. 坐标系变换矩阵:修正Open3D默认坐标系与RealSense的差异
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值