公司动态

第155篇 RGB-D数据处理——深度图空洞填充、对齐和坐标转换

📅 2026/8/19 22:03:32
第155篇 RGB-D数据处理——深度图空洞填充、对齐和坐标转换
上篇讲了三种主流深度获取方案——结构光、ToF、双目。不管你用哪种方案拿到深度数据之后都要做进一步处理才能用。今天就把RGB-D数据处理的核心环节讲清楚。面试时候被问你处理过RGB-D数据吗很多候选人只说用RealSense获取深度图然后转点云。但中间有很多细节深度图有空洞怎么办深度和RGB怎么对齐深度图怎么转成3D点云这些细节才是区分你到底是做过还是只跑过demo。深度图的数据格式深度图是一张特殊的图像每个像素的值不是颜色而是距离值。常见的格式有两种16位无整数uint16每个像素的值表示到相机的距离单位是毫米。比如像素值1500表示距离1.5米。有效范围通常是0-65535毫米约65米但实际相机的有效范围远小于此。RealSense D435的有效范围是0.2-10米对应像素值200-10000。32位浮点数float32每个像素的值表示距离单位是米。精度更高但占用空间是uint16的四倍。一些研究用的数据集如NYU Depth V2用这种格式。import numpy as np import cv2 # 读取uint16深度图 depth_raw cv2.imread(depth.png, cv2.IMREAD_UNCHANGED) # 转换为米 depth_meters depth_raw.astype(np.float32) / 1000.0 # 过滤无效值0表示无有效深度 valid_mask (depth_raw 0) (depth_raw 10000) # 0-10米有效 print(f有效像素比例: {np.sum(valid_mask) / valid_mask.size * 100:.1f}%)有个容易忽略的点深度值为0不代表距离是0而是表示这个位置没有有效的深度测量。可能是物体太远、太近、太黑或者太反光。处理深度图的第一步永远是检查无效值。深度图空洞填充空洞holes是深度图中值为0的区域。产生的原因很多黑色物体不反射红外光、透明物体玻璃让红外光穿透、高反射表面金属让红外光镜面反射、物体边缘的深度跳变处算法无法匹配。最简单的填充方法是最近邻插值对每个空洞像素找最近的有效深度值来填充。def fill_holes_nearest(depth): 最近邻空洞填充 mask depth 0 if not np.any(mask): return depth # 用OpenCV的inpaint depth_filled cv2.inpaint( depth.astype(np.float32), mask.astype(np.uint8), inpaintRadius5, flagscv2.INPAINT_NEAREST ) return depth_filled更好的方法是基于RGB引导的填充。思路是如果两个相邻像素的RGB颜色很接近它们大概率属于同一个物体表面深度应该是连续的。利用这个先验填充空洞时不仅考虑空间距离还考虑颜色相似度。Open3D提供了快速的深度图修复功能import open3d as o3d depth_o3d o3d.geometry.Image(depth_raw.astype(np.uint16)) depth_filled o3d.geometry.Image.fill_holes(depth_o3d)深度图与RGB对齐大多数RGB-D相机如RealSense的深度传感器和RGB传感器是物理上分开的两个镜头有不同的内参和相对位姿。这意味着同一个像素在深度图和RGB图上对应的是空间中不同的方向。对齐alignment就是把深度图重投影到RGB相机的坐标系下使得每个像素位置上的深度值和RGB值对应同一个空间点。# RealSense SDK中的对齐 pipeline rs.pipeline() config rs.config() config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30) config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30) pipeline.start(config) align rs.align(rs.stream.color) # 将深度对齐到RGB frames pipeline.wait_for_frames() aligned_frames align.process(frames) aligned_depth aligned_frames.get_depth_frame() color_frame aligned_frames.get_color_frame()对齐之后每个像素既有RGB颜色又有对应的深度值可以直接生成带颜色的点云。深度图转点云深度图转点云就是反投影back-projection利用相机内参把每个像素的深度值还原为3D坐标。def depth_to_pointcloud(depth, fx, fy, cx, cy, rgbNone): 深度图转点云 h, w depth.shape points [] colors [] for v in range(h): for u in range(w): z depth[v, u] if z 0: continue x (u - cx) * z / fx y (v - cy) * z / fy points.append([x, y, z]) if rgb is not None: colors.append(rgb[v, u] / 255.0) pcd o3d.geometry.PointCloud() pcd.points o3d.utility.Vector3dVector(np.array(points)) if colors: pcd.colors o3d.utility.Vector3dVector(np.array(colors)) return pcd实际项目中不需要自己写——Open3D和RealSense SDK都提供了封装好的函数。但面试时候理解这个原理很重要深度图本质上就是一张每个像素带深度值的图通过相机内参反投影就能得到3D点云。内参不准点云就会扭曲。面试中怎么聊面试官问RGB-D数据处理按这个顺序回答先说深度图格式uint16毫米、无效值处理再说空洞填充最近邻、RGB引导然后说对齐深度和RGB的坐标系统一最后说反投影深度图转点云。如果面试官追问空洞填充的效果怎么评估你可以说看填充后点云的完整性——物体表面是否连续、有没有明显的凹陷或突起。如果有ground truth深度数据可以计算填充区域的深度误差。如果面试官追问对齐精度怎么验证你可以说把对齐后的RGB-D数据投影到3D空间看物体的边缘是否清晰。如果对齐不准物体边缘会出现彩色光晕RGB和深度不重合。最后分享一个调试技巧在Rviz2中同时显示RGB图像、深度图和点云可以直观地看到对齐效果。如果点云表面不连续或者颜色错位说明对齐有问题需要检查相机内参和深度-RGB外参是否正确。再补充一个实际项目中的经验RealSense相机的深度和RGB对齐硬件对齐相机固件内置比软件对齐用realsense-ros的align节点效果好很多。如果你发现对齐后物体边缘有彩色光晕先检查一下是不是用了软件对齐试试开启相机的硬件对齐功能。另外深度图的空洞在近距离0.5米以内特别多这是因为结构光的基线限制导致近处盲区大用最近邻填充基本够用但如果要做精确的3D重建建议用RGB引导的填充方法。下一篇讲IMU工作原理——加速度计和陀螺仪的物理基础。从视觉传感器转到惯性传感器这是机器人感知系统的另一个重要组成部分。如果这篇文章对你有帮助欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。「机器人软件开发面试·从入门到精通」连载系列上一篇第154篇 深度相机原理对比——结构光/ToF/双目各自优劣下一篇预告第156篇 IMU工作原理——加速度计和陀螺仪的物理基础有任何问题欢迎评论区留言我会尽量回复。