2、深度数据获取:使用OpenCV和librealsense读取Intel RealSense深度流

好,咱们正式开始动手了。

上一章我们聊了深度相机的基本原理,这一章直接进入实操——怎么把RealSense的深度数据真正拿到手里。说白了,就是让你的电脑和相机“对上话”,然后把深度图、点云这些宝贝数据存下来。

2.1 环境准备:装好librealsense和OpenCV

我习惯先把环境搭利索了再写代码。不然调试到一半发现缺库,那感觉,嗯,你懂的。

第一步:安装librealsense SDK

Intel官方提供了很完善的SDK,叫librealsense。我个人建议直接从GitHub clone源码编译,这样能保证拿到最新的特性。当然,如果你图省事,用包管理器也行。

# Ubuntu / Debian 系
sudo apt-get install librealsense2-dev librealsense2-dkms

# macOS (Homebrew)
brew install librealsense

# Windows
# 直接下载 Intel.RealSense.SDK.exe 安装包

第二步:安装OpenCV

OpenCV负责图像处理和可视化。我一般用4.5以上的版本,对深度数据支持更好。

pip install opencv-python opencv-contrib-python
小提示: 如果你在Linux上遇到权限问题,记得把当前用户加到 realsense 组里。我曾经在这卡了半小时,后来发现就是少了个 sudo usermod -aG realsense $USER

2.2 初始化相机:配置分辨率与帧率

相机连上之后,第一件事就是配置参数。分辨率、帧率、深度范围,这些都得提前想好。

为什么会这样?因为不同的应用场景对参数要求完全不同。比如做手势识别,VGA分辨率(640×480)就够用,帧率可以跑到60fps;但如果你要做三维重建,那最好上1280×720,帧率降到30fps,保证点云密度。

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)

这里有个细节:rs.format.z16 表示深度数据以16位无符号整数存储,每个像素的值代表毫米单位的距离。说白了,值越大,离相机越远。

重点: 深度流和彩色流的分辨率、帧率最好保持一致。不然对齐的时候会出问题,我踩过这个坑——彩色图是30fps,深度图是60fps,结果时间戳对不上,画面一直闪。

2.3 获取帧数据:深度图与彩色图

配置好了,接下来就是循环读取数据。RealSense的API设计得很直观:每次调用 wait_for_frames() 就会返回一帧数据。

try:
    while True:
        # 等待一帧数据
        frames = pipeline.wait_for_frames()
        
        # 获取深度帧和彩色帧
        depth_frame = frames.get_depth_frame()
        color_frame = frames.get_color_frame()
        
        if not depth_frame or not color_frame:
            continue
        
        # 转为numpy数组
        depth_image = np.asanyarray(depth_frame.get_data())
        color_image = np.asanyarray(color_frame.get_data())
        
        # 显示
        cv2.imshow('Depth', depth_image)
        cv2.imshow('Color', color_image)
        
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
finally:
    pipeline.stop()
    cv2.destroyAllWindows()

你想想看,就这么几行代码,深度数据就源源不断地流进来了。是不是挺爽的?

注意: wait_for_frames() 是阻塞的。如果你的主循环里还有其他任务(比如UI更新),建议用多线程或者异步方式处理。我曾经在实时交互项目里忘了这茬,结果界面卡得跟幻灯片似的。

2.4 深度图可视化与保存

原始深度图看起来是灰蒙蒙的,因为它是16位单通道数据。直接显示的话,近处亮、远处暗,但细节不明显。我习惯做一下归一化,让视觉效果更舒服。

# 深度图归一化到0-255
depth_colormap = cv2.applyColorMap(
    cv2.convertScaleAbs(depth_image, alpha=0.03), 
    cv2.COLORMAP_JET
)

# 保存深度图
cv2.imwrite('depth_raw.png', depth_image)          # 原始16位
cv2.imwrite('depth_colormap.png', depth_colormap)  # 伪彩色
cv2.imwrite('color.png', color_image)              # 彩色图

这里 alpha=0.03 是个经验值。它把深度值从毫米范围映射到0-255。如果你的场景距离范围不同,可以调整这个系数。比如近距离扫描,alpha可以设大一点。

2.5 点云生成与保存

深度图是二维的,点云才是三维的。RealSense SDK内置了点云生成功能,非常方便。

# 创建点云对象
pc = rs.pointcloud()

# 将深度帧转换为点云
points = pc.calculate(depth_frame)

# 获取顶点和纹理坐标
vertices = np.asanyarray(points.get_vertices()).view(np.float32).reshape(-1, 3)
tex_coords = np.asanyarray(points.get_texture_coordinates()).view(np.float32).reshape(-1, 2)

# 保存为PLY格式
points.export_to_ply('output.ply', color_frame)

保存成PLY格式后,你可以用MeshLab、CloudCompare或者Blender打开查看。我个人习惯用PLY,因为它同时支持顶点颜色,彩色点云看起来更直观。

避坑指南: 我曾经在保存点云时发现文件特别大,一查才知道忘了设置 texture_coordinates 的精度。默认是float32,如果你对精度要求不高,可以转成float16,文件大小直接减半。

2.6 知识体系总览

下面这张图概括了本章的核心流程。从硬件初始化到数据获取,再到保存,每一步都有对应的API和注意事项。

深度数据获取流程 1. 初始化管道 pipeline.start(config) 2. 配置参数 分辨率 / 帧率 3. 获取帧数据 wait_for_frames() 4. 保存 深度图/点云 关键输出 📷 深度图 (Depth Image) → 16位单通道,单位毫米 → 可保存为PNG或NPZ 🌐 点云 (Point Cloud) → 三维坐标 (x, y, z) → 可保存为PLY或PCD

2.7 常见问题与调试技巧

最后分享几个我实际项目中遇到的坑,希望能帮你省点时间。

问题 现象 解决方案
相机无法启动 pipeline.start() 抛出异常 检查USB接口是否为3.0,RealSense需要高带宽
深度图全黑 所有像素值为0 可能是距离太近(<0.3m)或太远(>10m),调整深度范围
点云文件巨大 一个PLY文件几百MB 降低分辨率,或者用体素滤波下采样
彩色和深度不对齐 边缘出现重影 使用 rs.align 进行对齐处理

嗯,这一章的内容就到这里。代码不多,但每一步都是实打实的操作。你把这些跑通了,后面做手势识别、三维重建就有了坚实的基础。

专注资料整理