librealsense 入门实战:用 rs-hello-realsense 示例读取 RealSense 深度数据
【免费下载链接】librealsenseRealSense SDK项目地址: https://gitcode.com/GitHub_Trending/li/librealsense
导读
rs-hello-realsense是 librealsense(RealSense SDK)中最简单、最适合作为第一个上手的示例程序:它演示了连接 RealSense 设备、启动深度流并读取画面中心像素距离值的最小闭环。读完本文,你将掌握rs2::pipeline的核心用法、深度帧的获取与像素级距离查询 API,并理解这些高层接口在 SDK 源码中的底层实现路径,从而为后续开发点云、对齐、测量等应用打下基础。
本文基于仓库中的 examples/hello-realsense/readme.md 展开,并结合对应的 rs-hello-realsense.cpp、CMakeLists.txt 以及 include/librealsense2/hpp/rs_pipeline.hpp 等源码进行纵深讲解。
示例概述与预期输出
rs-hello-realsense是入门级的 C++ 示例(仓库中的 examples/readme.md 将其标记为最低难度的一星示例),核心目标只有三件事:
- 连接一台 RealSense 相机;
- 启动深度流;
- 持续打印相机视野中心点到前方物体的距离。
预期输出非常直观:在相机已连接且视野中心有物体的情况下,终端会不断刷新一行文本:
The camera is facing an object X meters away其中X是相机到视野中心物体的距离,单位为米。把相机对准不同远近的物体,数值会实时变化,这可以当作验证 SDK 安装与相机工作状态是否正常的"冒烟测试"。
该示例依赖 RealSense 的深度感知能力,关于深度传感技术(结构化光、双目立体视觉、L500 系列)的背景可参考 examples/depth.md;如果你更习惯 C 语言,仓库还提供了功能等价的 C 版本 examples/C/distance/rs-distance.c。
完整代码与构建方式
示例完整源码
readme 中为了讲解循序渐进地分段展示代码,而仓库中的 rs-hello-realsense.cpp 是可直接编译运行的完整版本,包含 readme 未展示的命令行参数解析与异常处理部分:
#include <librealsense2/rs.hpp> // RealSense Cross Platform API #include <iostream> #include <common/cli.h> int main(int argc, char * argv[]) try { auto settings = rs2::cli( "hello-realsense example" ) .process( argc, argv ); // Create a Pipeline - this serves as a top-level API for streaming and processing frames rs2::pipeline p( settings.dump() ); // Configure and start the pipeline p.start(); while (true) { // Block program until frames arrive rs2::frameset frames = p.wait_for_frames(); // Try to get a frame of a depth image rs2::depth_frame depth = frames.get_depth_frame(); // Get the depth frame's dimensions auto width = depth.get_width(); auto height = depth.get_height(); // Query the distance from the camera to the object in the center of the image float dist_to_center = depth.get_distance(width / 2, height / 2); // Print the distance std::cout << "The camera is facing an object " << dist_to_center << " meters away \r"; } return EXIT_SUCCESS; } catch (const rs2::error & e) { std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << std::endl; return EXIT_FAILURE; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; }相比 readme 中的教学片段,完整版多了两点值得注意:
- 命令行参数处理:通过
rs2::cli(...).process(argc, argv)解析参数。rs2::cli定义在 common/cli.h,基于 TCLAP 实现,支持--debug(开启 librealsense 调试日志)、--eth/--eth-only/--no-eth(控制是否检测 DDS 网络设备)以及--domain-id <0-232>(DDS 域 ID)等参数,process返回的 JSON 设置会通过rs2::pipeline p( settings.dump() )传给 pipeline 构造器。 - 异常处理:整个
main函数体包在try块中,专门捕获rs2::error(可打印出错的 API 函数名、参数与错误信息)和std::exception,便于在设备缺失或流启动失败时给出清晰的诊断输出。
CMake 构建配置
该示例的构建由 examples/hello-realsense/CMakeLists.txt 定义:
cmake_minimum_required(VERSION 3.10) project( rs-hello-realsense ) add_executable( ${PROJECT_NAME} rs-hello-realsense.cpp ) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11) target_link_libraries( ${PROJECT_NAME} ${DEPENDENCIES} ) set_target_properties( ${PROJECT_NAME} PROPERTIES FOLDER "Examples" ) using_easyloggingpp( ${PROJECT_NAME} SHARED ) install( TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )要点说明:
- 使用C++11标准即可编译,SDK 的 C++ API 对标准要求不高;
- 链接目标是
examples/CMakeLists.txt中统一收集的${DEPENDENCIES}(包括realsense2库及其传递依赖); using_easyloggingpp(...)接入 easyloggingpp 日志框架,这也是rs2::cli中--debug参数能够生效的前提;- 生成的
rs-hello-realsense可执行文件会随 SDK 一并安装到${CMAKE_INSTALL_BINDIR}。
按仓库根目录 readme.md 的安装指引完成 SDK 构建(或通过apt安装预编译包)后,即可运行该可执行文件进行验证。
逐步拆解:从包含头文件到打印距离
1. 引入跨平台 API 头文件
#include <librealsense2/rs.hpp> // Include RealSense Cross Platform APIreadme 特别强调:除高级功能外,整个 SDK 的全部能力都通过这一个头文件提供。rs.hpp会串联起 C++ 封装层(如rs_pipeline.hpp、rs_frame.hpp)与底层 C API(include/librealsense2/rs.h),因此你的项目只需要引入它,就能访问 pipeline、frame、sensor、processing block 等全部常用对象,无需按模块逐个 include。
2. 创建并启动 pipeline
// Create a Pipeline - this serves as a top-level API for streaming and processing frames rs2::pipeline p; // Configure and start the pipeline p.start();pipeline 是 SDK 面向应用层提供的最高层抽象,用于简化与设备及视觉处理模块的交互。从 include/librealsense2/hpp/rs_pipeline.hpp 中pipeline类的文档可以看到它的定位:
- 抽象了相机的配置与流启动过程——调用无参的
start()时,pipeline 使用默认配置自动解析并启动设备的深度流,不需要手动枚举设备、查询 profile 或逐流配置; - 抽象了视觉模块的触发与线程模型——流循环在后台运行,应用只需通过
wait_for_frames()或poll_for_frames()取帧; start()只能调用一次,重复启动会抛出异常;它返回的pipeline_profile描述了实际生效的设备与流的 profile。
如果你需要精确控制(例如指定分辨率、帧率或特定设备),可以在start()前通过rs2::config配置;本例为了展示最简用法,直接使用默认配置。
3. 阻塞等待帧集合
// Block program until frames arrive rs2::frameset frames = p.wait_for_frames();RealSense 相机通常同时提供多路视频流、运动(IMU)流或位姿(Pose)流。wait_for_frames()会阻塞当前线程,直到 pipeline 从已配置的各路流中取回一组时间上对齐(coherent)的帧,并以frameset(复合帧集合)的形式返回。这样你拿到的每一帧都属于同一时刻,便于后续做跨流处理。如果你不希望阻塞,可以使用非阻塞的poll_for_frames()轮询。
4. 取出深度帧
// Try to get a frame of a depth image rs2::depth_frame depth = frames.get_depth_frame();get_depth_frame()是frameset提供的辅助方法,负责从帧集合中提取第一个深度数据帧并返回rs2::depth_frame对象。rs2::depth_frame封装了深度图及其元数据,是后续所有距离/深度查询操作的入口。
5. 查询深度帧尺寸
// Get the depth frame's dimensions float width = depth.get_width(); float height = depth.get_height();get_width()/get_height()返回深度图像的像素宽高。readme 特别提示:默认深度帧的尺寸可能因传感器型号而异(例如 D415 与 D435 的分辨率配置就不同),因此不要硬编码像素坐标,而是动态读取尺寸后计算中心点。
6. 查询中心像素的距离
// Query the distance from the camera to the object in the center of the image float dist_to_center = depth.get_distance(width / 2, height / 2);get_distance(int x, int y)是rs2::depth_frame的核心方法,返回指定像素处物体到相机平面的距离,单位为米。它定义在 include/librealsense2/hpp/rs_frame.hpp 中,底层调用 C APIrs2_depth_frame_get_distance。用(width / 2, height / 2)即取图像正中心的像素。
7. 打印结果
// Print the distance std::cout << "The camera is facing an object " << dist_to_center << " meters away \r";\r(回车符)让输出在同一行不断刷新,形成实时测距效果。
源码级原理:get_distance 的底层实现与边界校验
教学示例到此为止,但如果你想深入理解get_distance究竟做了什么,可以顺着 C++ 封装向下追两层:
第一层:C++ 封装(include/librealsense2/hpp/rs_frame.hpp)中,get_distance的文档明确写道:"Provide the depth in meters at the given pixel",其实现直接委托给 C API:
float get_distance(int x, int y) const { rs2_error * e = nullptr; auto r = rs2_depth_frame_get_distance(get(), x, y, &e); error::handle(e); return r; }第二层:C API 实现(src/rs.cpp)中,rs2_depth_frame_get_distance做了两件事——接口类型校验与像素坐标范围校验,然后调用内部实现:
float rs2_depth_frame_get_distance(const rs2_frame* frame_ref, int x, int y, rs2_error** error) BEGIN_API_CALL { VALIDATE_NOT_NULL(frame_ref); auto df = VALIDATE_INTERFACE(((frame_interface*)frame_ref), librealsense::depth_frame); VALIDATE_RANGE(x, 0, df->get_width() - 1); VALIDATE_RANGE(y, 0, df->get_height() - 1); return df->get_distance(x, y); }这段实现透露了几个关键事实:
- 坐标系约定:像素坐标以图像左上角为原点(C API 文档注释为 "Left-Upper corner origin"),这与很多图像处理库的约定一致;
- 越界保护:
VALIDATE_RANGE会把超出[0, width-1]/[0, height-1]的像素坐标当作错误处理并抛出异常,因此示例中动态读取width/height再取中心点的写法既正确又安全; - 深度单位:返回值为米(metric units),配合
get_units()(返回原始深度值到米的换算系数)可以验证这一结论。
值得一提的是,同一份 C API 还被各语言封装复用:例如 Android 的 JNI 层 src/android/jni/frame.cpp 中DepthFrame.nGetDistance也直接调用rs2_depth_frame_get_distance,说明这条距离查询链路是 SDK 全平台共享的核心能力。
与 C 语言版本对照:更贴近底层的手动流程
如果你在 readme 之外还想看看"不用高层 pipeline"的写法,仓库提供了同主题的 C 版示例 examples/C/distance/rs-distance.c。它把 pipeline 内部帮你做的事一步步手动展开,非常适合理解高层 API 的封装意义:
- 用
rs2_create_context创建 context,rs2_query_devices枚举设备; - 用
rs2_create_config+rs2_config_enable_stream(config, RS2_STREAM_DEPTH, STREAM_INDEX, WIDTH, HEIGHT, RS2_FORMAT_Z16, FPS, &e)显式指定深度流参数(其中RS2_FORMAT_Z16表示 16 位深度格式,WIDTH为 640、HEIGHT为 0 表示自动解析); - 用
rs2_pipeline_start_with_config按配置启动; - 循环中
rs2_pipeline_wait_for_frames取帧,用rs2_is_frame_extendable_to(frame, RS2_EXTENSION_DEPTH_FRAME, &e)判断帧是否为深度帧后,再调用rs2_depth_frame_get_distance(frame, width / 2, height / 2, &e)获取中心距离。
对比可见:C++ 示例中一行p.start()背后,实际上封装了 C 版里 context 创建、设备查询、config 配置、pipeline 启动的全套流程;而frames.get_depth_frame()也等价于 C 版的"遍历复合帧、逐个判断扩展类型、提取深度帧"逻辑。理解这一对照关系,有助于你在需要精细控制(如多设备选型、自定义流参数)时切换到更底层的 API。
常见问题与排查方向
- 设备未连接/驱动未就绪:程序在
p.start()阶段会抛出异常,完整版示例会打印"RealSense error calling ..."及具体失败的 API 与参数。请确认相机已插入、udev 规则已按 scripts/setup_udev_rules.sh 安装(Linux),并参考 doc/troubleshooting.md 排查。 - 视野中心无有效深度:当中心像素处物体过近(低于传感器最小感知距离)或材质无反射时,
get_distance可能返回 0 或不稳定数值,可尝试对准 0.5~3 米内的物体验证。 - 输出不刷新:
\r在部分终端(如某些 IDE 内嵌终端)可能显示异常,改用\n或std::flush即可观察输出。 - 想自定义分辨率/帧率:改用
rs2::config的enable_stream显式指定流参数,写法可参考上文 C 版示例中的参数枚举(WIDTH、HEIGHT、FPS、RS2_FORMAT_Z16)。
总结:从"Hello World"到下一步
rs-hello-realsense用约 30 行核心代码完成了"连接设备 → 启动深度流 → 取帧 → 查像素距离 → 打印"的完整闭环,是理解 librealsense C++ API 设计哲学的最佳起点。它揭示的pipeline → frameset → depth_frame → get_distance这条调用链,正是后续几乎所有深度应用(点云、空间对齐、测量 等)的公共骨架。建议你在运行通过后,动手把get_distance的查询坐标从中心点改成任意像素、或把距离输出改为逐行打印整幅深度图,以加深对深度帧数据结构与坐标体系的理解。
【免费下载链接】librealsenseRealSense SDK项目地址: https://gitcode.com/GitHub_Trending/li/librealsense
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考