如何对RealSense D435i已保存的RGB与深度图像进行对齐?
RealSense D435i 离线深度图对齐RGB图实现方案
核心说明
离线对齐不需要依赖实时拍摄流,只需要获取拍摄设备的深度、彩色相机内参,以及深度到彩色相机的外参,即可完成重投影对齐,以下优先提供Python实现方案。
方案1:pyrealsense2原生对齐(最推荐,精度最高)
直接调用RealSense官方SDK的对齐接口,和实时对齐的计算逻辑完全一致,不需要自己实现重投影逻辑。
前置步骤:获取相机校准参数
如果是你自己的拍摄设备,直接运行以下代码读取设备出厂校准参数即可,D435i的出厂校准参数稳定性很高,只要没有拆解过设备就可以直接复用:
import pyrealsense2 as rs # 初始化流读取参数 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) # 读取深度、彩色流配置 depth_profile = rs.video_stream_profile(profile.get_stream(rs.stream.depth)) color_profile = rs.video_stream_profile(profile.get_stream(rs.stream.color)) # 读取内参与外参,可将这些参数序列化保存到本地json文件后续离线使用 depth_intrinsics = depth_profile.get_intrinsics() color_intrinsics = color_profile.get_intrinsics() depth_to_color_extrinsics = depth_profile.get_extrinsics_to(color_profile) pipeline.stop()
离线对齐代码
import cv2 import numpy as np import pyrealsense2 as rs # 初始化对齐对象,目标对齐到彩色流 align = rs.align(rs.stream.color) # 读取本地存储的原始图像,*深度图必须读取16位原始数据,禁止提前转8位灰度图* raw_depth = cv2.imread("你的深度图路径.png", cv2.IMREAD_UNCHANGED) raw_color = cv2.imread("你的RGB图路径.png") # 构造SDK可识别的帧对象 depth_frame = rs.video_frame(rs.frame(), raw_depth.tobytes(), depth_profile, 0, 0) color_frame = rs.video_frame(rs.frame(), raw_color.tobytes(), color_profile, 0, 0) # 执行对齐 aligned_frames = align.process(rs.frameset([depth_frame, color_frame])) aligned_depth_frame = aligned_frames.get_depth_frame() # 转换为numpy数组,和RGB图尺寸完全对应 aligned_depth = np.asanyarray(aligned_depth_frame.get_data())
方案2:纯OpenCV手动实现(无SDK依赖)
如果不想安装pyrealsense2环境,可以手动实现3D重投影逻辑完成对齐,代码如下:
import cv2 import numpy as np # 替换为你自己的相机参数,从之前读取的内参外参转换即可 # 深度相机内参3x3矩阵 depth_intr = np.array([ [depth_intrinsics.fx, 0, depth_intrinsics.ppx], [0, depth_intrinsics.fy, depth_intrinsics.ppy], [0, 0, 1] ]) # 彩色相机内参3x3矩阵 color_intr = np.array([ [color_intrinsics.fx, 0, color_intrinsics.ppx], [0, color_intrinsics.fy, color_intrinsics.ppy], [0, 0, 1] ]) # 深度到彩色的旋转矩阵3x3、平移向量3x1 R = np.array(depth_to_color_extrinsics.rotation).reshape(3,3) T = np.array(depth_to_color_extrinsics.translation).reshape(3,1) # RealSense默认深度值单位为毫米,转米用 depth_scale = 0.001 # 读取图像 raw_depth = cv2.imread("你的深度图路径.png", cv2.IMREAD_UNCHANGED) raw_color = cv2.imread("你的RGB图路径.png") color_h, color_w = raw_color.shape[:2] # 生成深度图像素坐标网格 u_d, v_d = np.meshgrid(np.arange(raw_depth.shape[1]), np.arange(raw_depth.shape[0])) z_d = raw_depth * depth_scale # 转换为深度相机坐标系下的3D点 x_d = (u_d - depth_intr[0,2]) * z_d / depth_intr[0,0] y_d = (v_d - depth_intr[1,2]) * z_d / depth_intr[1,1] points_3d_depth = np.stack([x_d, y_d, z_d], axis=-1).reshape(-1, 3) # 转换为彩色相机坐标系下的3D点 points_3d_color = (R @ points_3d_depth.T + T).T # 投影为彩色图像素坐标 z_c = points_3d_color[:, 2] u_c = (points_3d_color[:, 0] * color_intr[0,0] / z_c + color_intr[0,2]).astype(np.int32) v_c = (points_3d_color[:, 1] * color_intr[1,1] / z_c + color_intr[1,2]).astype(np.int32) # 过滤有效坐标范围,生成对齐后的深度图 valid_mask = (u_c >=0) & (u_c < color_w) & (v_c >=0) & (v_c < color_h) & (z_c > 0) aligned_depth = np.zeros((color_h, color_w), dtype=raw_depth.dtype) aligned_depth[v_c[valid_mask], u_c[valid_mask]] = raw_depth[v_d.reshape(-1)[valid_mask], u_d.reshape(-1)[valid_mask]] # 可选:对齐后的深度图可能存在孔洞,可用cv2.inpaint填充 # hole_mask = (aligned_depth == 0).astype(np.uint8) # aligned_depth = cv2.inpaint(aligned_depth, hole_mask, 5, cv2.INPAINT_TELEA)
内容的提问来源于stack exchange,提问作者Yarden Akaby
相关产品推荐
相关产品推荐

