librealsense rs-pointcloud 示例深度解析:使用 RealSense SDK 生成并可视化带纹理 3D 点云
2026/9/16 13:38:40 网站建设 项目流程

librealsense rs-pointcloud 示例深度解析:使用 RealSense SDK 生成并可视化带纹理 3D 点云

【免费下载链接】librealsenseRealSense SDK项目地址: https://gitcode.com/GitHub_Trending/li/librealsense

导读

本文基于 Intel RealSense SDK(librealsense)官方示例 rs-pointcloud 展开,完整讲解如何用 C++ 从深度流生成三维点云、把彩色帧映射为点云纹理,并通过 OpenGL 实时渲染与交互查看。读完本文,你将掌握rs2::pointcloudrs2::pointsrs2::pipeline的核心用法,理解深度反投影与纹理坐标映射的底层原理,并能独立运行、改造该示例,将其中的点云生成流程移植到自己的项目中。

示例概览:它能做什么

rs-pointcloud是 librealsense 仓库中负责点云生成与可视化的图形示例,位于 examples/pointcloud/。它的核心能力包括:

  • 从 RealSense 深度相机实时取流,把每一帧深度图转换为 3D 点云;
  • 把同一时刻的彩色帧作为纹理映射到点云表面,生成"彩色点云";
  • 通过 OpenGL 窗口实时渲染,并支持鼠标拖拽旋转(yaw/pitch)、滚轮缩放(offset)交互查看。

其编译入口是 examples/pointcloud/CMakeLists.txt:目标rs-pointcloud由 rs-pointcloud.cpp 与共享的 example.hpp 及 ImGui 源码共同构建,仅在开启BUILD_GRAPHICAL_EXAMPLES选项时才会编译,最终安装到${CMAKE_INSTALL_BINDIR}。因此,若你使用 CMake 配置项目,需要显式启用图形示例选项并链接依赖(如 GLFW/OpenGL)。

运行后,程序会打开一个1280x720的窗口,窗口内显示带真实色彩纹理的三维点云;按住鼠标左键拖拽可以旋转视角,滚动滚轮可以缩放,按空格键可将视角复位为初始状态。

程序骨架:窗口、状态与回调

示例开头引入两个关键头文件,这与首个教程的写法一脉相承:

#include <librealsense2/rs.hpp> // Include RealSense Cross Platform API #include "example.hpp" // Include short list of convenience functions for rendering
  • librealsense2/rs.hpp是 SDK 的跨平台 C++ API 入口(对应 C API 为 include/librealsense2/rs.h);
  • example.hpp是示例共享的轻量辅助库,封装了 OpenGL 窗口管理、纹理上传与基础渲染(其实现位于 examples/example.hpp)。

随后代码定义了一个用于管理点云视角旋转的状态结构体,并声明两个辅助函数:

// Struct for managing rotation of pointcloud view struct state { double yaw, pitch, last_x, last_y; bool ml; float offset_x, offset_y; texture tex; }; // Helper functions void register_glfw_callbacks(window& app, state& app_state); void draw_pointcloud(window& app, state& app_state, rs2::points& points);

在实际源码中,该结构体名为glfw_state(见 examples/example.hpp 中glfw_state的定义),字段含义为:

字段类型作用
yaw/pitchdouble点云视图的偏航角与俯仰角,控制旋转
last_x/last_ydouble记录上一次鼠标位置,用于计算拖拽增量
mlbool鼠标左键是否按下(拖拽旋转的开关)
offset_x/offset_yfloat滚轮缩放偏移量
textextureOpenGL 纹理对象,用于上传彩色帧

main中,程序创建窗口、初始化状态并注册 GLFW 回调:

// Create a simple OpenGL window for rendering: window app(1280, 720, "RealSense Pointcloud Example"); // Construct an object to manage view state state app_state = { 0, 0, 0, 0, false, 0, 0, 0 }; // register callbacks to allow manipulation of the pointcloud register_glfw_callbacks(app, app_state);

register_glfw_callbacks的实现同样位于 examples/example.hpp:鼠标左键按下时置位ml,鼠标移动时按位移增量更新yaw/pitch(并分别钳制在±120±80度范围内),滚轮事件更新offset_x/offset_y实现缩放,空格键(key code 32)将视角复位。

核心数据流:pointcloud 与 points

示例使用rs2命名空间下的两个关键类:

using namespace rs2; // Declare pointcloud object, for calculating pointclouds and texture mappings rs2::pointcloud pc; // We want the points object to be persistent so we can display the last cloud when a frame drops rs2::points points;
  • rs2::pointcloud:一个处理块(processing block / filter),负责把深度帧计算为点云并维护纹理映射。其类定义位于 include/librealsense2/hpp/rs_processing.hpp,构造时内部调用rs2_create_pointcloud创建底层处理块。它还支持带流类型参数的构造函数pointcloud(rs2_stream stream, int index = 0),用于限定处理特定流。
  • rs2::points:点云数据帧,继承自rs2::frame,持有顶点数组与纹理坐标数组。声明为持久对象的目的在于:当某一帧数据缺失时,窗口仍可继续显示上一次计算出的点云,避免画面闪断。其类定义与相关数据结构vertextexture_coordinate见 include/librealsense2/hpp/rs_frame.hpp。

取流:Pipeline 启动与帧循环

rs2::pipeline是 SDK 的功能入口,负责管理设备、传感器与流配置:

// Declare RealSense pipeline, encapsulating the actual device and sensors pipeline pipe; // Start streaming with default recommended configuration pipe.start();

pipe.start()会以 SDK 推荐的默认配置启动相机(深度 + 彩色流)。随后主循环反复等待下一组帧:

while (app) // Application still alive? { // Wait for the next set of frames from the camera auto frames = pipe.wait_for_frames(); ... }

while (app)依赖windowoperator bool()(examples/example.hpp):每帧刷新双缓冲、轮询 GLFW 事件,并在窗口关闭时返回false结束循环。wait_for_frames()则阻塞等待一组时间对齐的帧(frameset),这是后续"深度图与彩色图一一对应"的前提。

点云生成与纹理映射:calculate 与 map_to

这是示例的核心逻辑。在真实源码 rs-pointcloud.cpp 中,循环体按如下顺序工作:

auto color = frames.get_color_frame(); // For cameras that don't have RGB sensor, we'll map the pointcloud to infrared instead of color if (!color) color = frames.get_infrared_frame(); // Tell pointcloud object to map to this color frame pc.map_to(color); auto depth = frames.get_depth_frame(); // Generate the pointcloud and texture mappings points = pc.calculate(depth); // Upload the color frame to OpenGL app_state.tex.upload(color);

拆解如下:

  1. 取得彩色帧frames.get_color_frame()从帧集中取彩色流;对于没有 RGB 传感器的设备(例如部分仅提供红外流的型号),示例会回退到get_infrared_frame(),把红外图作为纹理,保证点云始终有颜色可贴。
  2. 映射纹理pc.map_to(color)告诉pointcloud对象以该彩色帧作为纹理来源。查看 include/librealsense2/hpp/rs_processing.hpp 可知,其本质是把彩色流的流类型、像素格式、流索引写入三个底层选项:RS2_OPTION_STREAM_FILTERRS2_OPTION_STREAM_FORMAT_FILTERRS2_OPTION_STREAM_INDEX_FILTER(选项枚举定义于 include/librealsense2/h/rs_option.h),随后把该彩色帧送入处理块完成"纹理帧"登记。
  3. 计算点云points = pc.calculate(depth)将深度帧送入处理块,输出rs2::points。该方法的实现(include/librealsense2/hpp/rs_processing.hpp)会从处理结果中解析出points扩展类型的帧;若底层返回 frameset,则从中逐个提取点云帧。
  4. 上传纹理app_state.tex.upload(color)把彩色帧数据上传为 OpenGL 纹理。texture::upload支持RGB8RGBA8Y8Y10BPACK等格式,并设置线性过滤与GL_CLAMP包裹模式(见 examples/example.hpp 中texture类的实现)。

渲染管线:draw_pointcloud 的 OpenGL 调用

计算完点云后,调用渲染函数:

draw_pointcloud(app.width(), app.height(), app_state, points);

draw_pointcloud的实现位于 examples/example.hpp,其工作分两部分:

第一部分:设置相机与模型变换。依次完成清屏(灰色背景153/255)、gluPerspective(60, width/height, 0.01f, 10.0f)透视投影、gluLookAt视点定位,再根据app_state.pitch/yaw旋转、按offset_y平移缩放视图,最后启用深度测试与纹理绑定。

第二部分:逐点上传顶点与纹理坐标。这是打印点云的关键片段:

/* this segment actually prints the pointcloud */ auto vertices = points.get_vertices(); // get vertices auto tex_coords = points.get_texture_coordinates(); // and texture coordinates for (int i = 0; i < points.size(); i++) { if (vertices[i].z) { // upload the point and texture coordinates only for points we have depth data for glVertex3fv(vertices[i]); glTexCoord2fv(tex_coords[i]); } }
  • points.get_vertices()返回const vertex*顶点数组,vertex{float x, y, z;}结构,并提供到const float*的隐式转换(include/librealsense2/hpp/rs_frame.hpp);
  • points.get_texture_coordinates()返回const texture_coordinate*纹理坐标数组,texture_coordinate{float u, v;}(同上文件);
  • points.size()返回点云总点数,与深度图分辨率(宽 × 高)一致;
  • if (vertices[i].z)这一判空至关重要:深度值为 0(即该像素没有有效深度数据,如遮挡、超量程区域)的点不会被上传,从而避免在无效位置画出残缺点。

顶点与纹理坐标成对提交后,GPU 即可把彩色纹理采样到每个点上,形成带真实色彩的 3D 点云。

底层原理:深度反投影与纹理坐标计算

rs2::pointcloud之所以能把深度图变成三维点,核心在于针孔相机模型的深度反投影。底层实现位于 src/proc/pointcloud.cpp:

template<class MAP_DEPTH> void deproject_depth(float * points, const rs2_intrinsics & intrin, const uint16_t * depth, MAP_DEPTH map_depth) { for (int y = 0; y < intrin.height; ++y) for (int x = 0; x < intrin.width; ++x) { const float pixel[] = { (float)x, (float)y }; rs2_deproject_pixel_to_point(points, &intrin, pixel, map_depth(*depth++)); points += 3; } }

这段代码逐像素调用rs2_deproject_pixel_to_point(定义于 include/librealsense2/rsutil.h),把像素坐标(x, y)连同深度值反投影为相机坐标系下的三维点(X, Y, Z)。反投影前需要把原始 16 位深度值乘以深度单位换算为米:

auto depth_scale = depth_frame.get_units(); deproject_depth(..., depth_scale { return depth_scale * z; });

get_units()返回该深度传感器每 LSB 对应的米数(不同设备/量程设置下不同),这一换算正是点云尺寸真实性的保证。

纹理映射则通过"投影 + 归一化"完成,同一文件中的工具函数清晰地说明了思路:

float2 project(const rs2_intrinsics *intrin, const float3 & point) { ... rs2_project_point_to_pixel(...); } float2 pixel_to_texcoord(const rs2_intrinsics *intrin, const float2 & pixel) { return { pixel.x / intrin->width, pixel.y / intrin->height }; }

即:把每个三维点用彩色相机内参投影回彩色图像平面得到像素坐标,再除以图像宽高归一化为[0,1]的纹理坐标(u, v),从而让每个点知道自己该采样的颜色位置。深度流与彩色流之间的空间变换由set_extrinsics()通过 SDK 的外参图(environment::get_instance().get_extrinsics_graph())查询获得,保证两路传感器坐标系对齐。

另外,src/proc/pointcloud.cpp 还引入了occlusion-filter(遮挡过滤):当深度点投影到彩色图时若落在被遮挡的无效区域,会做剔除处理,避免"透视"到物体背后的错误纹理。在支持 CUDA(RS2_USE_CUDA)、SSSE3(__SSSE3__)或 NEON 的平台上,点云计算会分别走 src/proc/cuda/cuda-pointcloud.cpp、src/proc/sse/sse-pointcloud.cpp、src/proc/neon/neon-pointcloud.cpp 的 SIMD/GPU 加速路径,这也解释了为何示例在低功耗设备上也能流畅显示高分辨率点云。

进阶延伸:从示例到你的项目

掌握了示例主循环后,你可以在此基础上做大量扩展:

  • 导出点云文件rs2::points提供export_to_ply(fname, texture)方法(include/librealsense2/hpp/rs_frame.hpp),可直接把当前点云连同纹理导出为 PLY 格式,供 MeshLab、CloudCompare 等工具查看,无需自己实现序列化。
  • 替换渲染后端:示例用 OpenGL 固定管线绘制点,实际项目中可改为把get_vertices()/get_texture_coordinates()上传到 VBO/VAO,或用 PCL/Open3D 等库消费同一份数据。
  • 按需取流pipe.start()使用默认推荐配置;需要自定义分辨率、帧率或深度量程时,可用rs2::config显式配置,再配合pipe.start(config)启动。
  • 多流/无 RGB 设备适配:示例已示范了"无彩色帧则回退到红外帧"的容错写法,接入双目红外等设备时同样适用。
  • 性能优化:了解底层存在 CUDA/SSE/NEON 加速路径后,可参考 src/proc/CMakeLists.txt 中的平台编译选项,为高性能设备开启对应指令集。

总结

rs-pointcloud以最精简的方式展示了 librealsense 点云能力的完整链路:pipeline取流 →pointcloud::map_to登记纹理 →pointcloud::calculate反投影生成points→ OpenGL 逐点绘制。配合 src/proc/pointcloud.cpp 的底层实现,你可以看到 SDK 如何用相机内参把深度像素反投影为米制坐标、又如何借助外参与彩色内参生成纹理坐标。掌握这一流程后,无论是做三维重建、机器人避障还是交互式可视化,都能快速迁移这套"深度 + 纹理 → 彩色点云"的标准管线。

【免费下载链接】librealsenseRealSense SDK项目地址: https://gitcode.com/GitHub_Trending/li/librealsense

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询