首页 / 资讯中心 / 文章详情

Realsense相机内参获取全攻略:从Viewer到ROS的避坑指南

Realsense相机内参获取全攻略:从Viewer到ROS的避坑指南 ★ FEATURED ARTICLE
1. 从一次翻车经历说起为什么相机内参这件事绕不过去刚接触Realsense那会儿我天真地以为插上USB线、打开Realsense Viewer看到彩色图和深度图就算大功告成了。直到我把相机装到小车上跑SLAM建出来的地图歪得像个被踩扁的纸箱才意识到问题的严重性——相机内参没标定或者标定错了后面所有的视觉算法都是在沙滩上盖楼。Realsense Viewer和ROS获取相机内参这件事看起来只是读几个数字但里面藏着不少门道。有人拿到的内参和实际对不上有人ROS里死活读不到话题有人在ARM64平台上连Viewer都打不开。这些问题我都踩过而且不止一次。这篇文章就是把我这些年用Realsense D435i、D455、L515这几款相机获取内参的完整流程、踩坑记录和修复方法全部倒出来从Windows下的Realsense Viewer到Ubuntu下的ROS话题读取再到常见错误的排查思路争取让你少走弯路。不管你是刚入手Realsense的新手还是已经在跑VINS-Fusion、ORB-SLAM3的老手只要涉及到相机内参的获取和验证这篇内容都能直接拿来参考。我会把每个步骤背后的逻辑讲清楚为什么这么做、不这么做会出什么问题以及那些官方文档里不会写的实操细节。2. 先搞明白相机内参到底在描述什么2.1 内参矩阵的物理含义与常见误区相机内参本质上描述的是“三维空间中的点如何投影到二维像素平面”这件事。用最朴素的话说就是相机把真实世界拍扁成一张图的时候用的那套“换算规则”。这套规则用一个3x3的矩阵K来表示K [fx 0 cx] [0 fy cy] [0 0 1]其中fx和fy是焦距在x和y方向上的像素表示cx和cy是光心在图像坐标系中的位置。很多人第一次看到这四个数会觉得抽象其实你可以这样理解fx和fy决定了相机“看东西有多放大”数值越大同样的物体在图像里占的像素越多cx和cy决定了图像中心偏到哪里去了理想情况下是图像宽高的一半但实际制造误差会让它偏几个像素。这里有个特别容易搞混的点Realsense相机有多个传感器——深度传感器、RGB彩色传感器、红外传感器。每个传感器都有自己的内参而且左右红外相机还有各自的内参和外参。你在Realsense Viewer里看到的“Intrinsics”是当前选中那个传感器的内参不是整个相机的统一内参。我见过有人把深度内参当成RGB内参用结果跑视觉里程计时特征点匹配全乱套。另一个误区是认为内参是固定不变的。实际上Realsense出厂时做过标定内参存在相机固件里但温度变化、机械振动、镜头轻微形变都会让内参发生微小漂移。对于精度要求高的应用比如亚厘米级的三维重建重新标定是必要的。但对于大多数SLAM和导航任务出厂内参已经够用了。2.2 为什么ROS里读到的内参和Viewer里不一样这个问题我被问过不下二十次。有人在Realsense Viewer里看到fx615.3到了ROS的/camera/color/camera_info话题里发现fx612.8立刻就慌了以为哪里配置错了。真相是Realsense Viewer显示的是相机固件中存储的原始标定值而ROS驱动在启动时可能会根据分辨率配置对图像进行裁剪或缩放导致内参发生相应变化。比如你在Viewer里看的是1280x720分辨率下的内参但ROS驱动配置的是640x480驱动会自动按比例调整fx、fy、cx、cy。这不是bug是正常的适配行为。还有一种情况是ROS驱动开启了“对齐深度到彩色”功能align_depth这时候深度图会被重投影到彩色相机坐标系下深度内参会变成彩色相机的内参。如果你没注意到这个设置就会觉得“怎么深度内参和彩色一模一样了”。注意在ROS中获取内参时一定要确认当前图像的分辨率和你读取camera_info的分辨率一致否则内参对不上。2.3 内参、外参、畸变系数的关系梳理内参解决的是“相机内部怎么投影”的问题外参解决的是“相机在空间中什么位置和姿态”的问题畸变系数解决的是“镜头让图像扭曲了多少”的问题。这三者经常被混在一起说但用途完全不同。Realsense Viewer里你会看到三个标签页Intrinsics、Extrinsics、Distortion。Intrinsics就是内参矩阵Extrinsics是传感器之间的相对位置比如深度相机相对于彩色相机的平移和旋转Distortion是畸变系数Realsense出厂前做过畸变校正所以畸变系数通常很小甚至为零。在ROS中这些信息都打包在camera_info消息里。消息结构包含K内参矩阵、D畸变系数、R校正矩阵、P投影矩阵。对于大多数应用你只需要关心K和D。R和P在双目校正和立体匹配时才会用到。3. 用Realsense Viewer获取内参的完整流程3.1 Windows和Ubuntu下的安装差异Realsense Viewer的安装在不同平台上差异挺大。Windows下最简单去官方发布页下载exe安装包双击一路下一步就行。Ubuntu下稍微麻烦一点官方推荐用apt源安装但国内网络环境有时候会卡在下载环节。Ubuntu下的安装命令大致是这样的sudo apt-key adv --keyserver keys.gnupg.net --recv-key F6E65AC044F831AC80A06380C8B3A55A6F3EFCDE sudo add-apt-repository deb https://librealsense.intel.com/Debian/apt-repo $(lsb_release -cs) main sudo apt-get update sudo apt-get install librealsense2-utils librealsense2-dev装完之后直接终端输入realsense-viewer就能打开。如果你用的是ARM64平台比如Jetson系列或者树莓派官方apt源可能没有对应的包需要从源码编译。源码编译的坑比较多后面单独说。提示Ubuntu 20.04和22.04对Realsense的支持最好18.04也能用但内核版本较老可能需要打补丁。Ubuntu 24.04下部分依赖包版本冲突建议用源码编译方式安装。3.2 在Viewer中正确读取内参的操作步骤打开Realsense Viewer后左侧会列出检测到的相机型号。点击相机名称展开你会看到Stereo Module、RGB Camera、Motion Module等选项。每个选项旁边有个开关打开后开始出图。读取内参的步骤打开你需要获取内参的那个传感器比如RGB Camera在右侧面板顶部找到“Info”下拉菜单选择“Camera Info”面板中会显示该传感器的内参信息包括Width、Height、Fx、Fy、PPX、PPY、Model、Coeffs这里的PPX和PPY就是cx和cyCoeffs就是畸变系数。Model通常显示“Brown Conrady”这是Realsense使用的畸变模型。关键细节在打开传感器之前先在上方选择好分辨率。比如RGB Camera支持1920x1080、1280x720、640x480等多档不同分辨率下的内参是不同的。你选了什么分辨率读到的就是那个分辨率下的内参。我建议先用你实际应用中要用的分辨率来读取避免后续换算。还有一个隐藏功能Viewer右上角有个“Save”按钮可以把当前所有传感器的内参导出成JSON文件。这个文件在后续配置ROS驱动或者标定工具时非常有用建议养成随手导出的习惯。3.3 导出内参数据并验证一致性导出JSON后打开文件你会看到类似这样的结构{ device_name: Intel RealSense D435I, serial_number: xxxxxxxxxxxx, color_intrinsics: { width: 1280, height: 720, fx: 615.321, fy: 615.567, ppx: 639.123, ppy: 359.456, model: Brown Conrady, coeffs: [0, 0, 0, 0, 0] } }验证一致性有个简单方法用Viewer里的“3D View”功能打开深度图和彩色图在场景中放一个已知尺寸的物体比如A4纸210mm x 297mm然后在3D视图里测量它的尺寸。如果测量值和实际值偏差在1%以内说明内参基本可信。偏差过大就要考虑重新标定。我实测过十几台D435i出厂内参的一致性还是不错的fx和fy的偏差通常在0.5%以内。但L515这款激光雷达相机就参差不齐了有几台fx偏差超过2%必须重新标定才能用。4. 在ROS中获取相机内参的实操方法4.1 realsense-ros驱动的安装与配置要点ROS下获取Realsense内参核心是realsense-ros这个功能包。安装方式有两种apt安装和源码编译。apt安装简单但版本可能较老源码编译灵活但依赖较多。apt安装以ROS Noetic为例sudo apt-get install ros-noetic-realsense2-camera sudo apt-get install ros-noetic-realsense2-description源码编译的话先建工作空间然后clone代码mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone https://github.com/IntelRealSense/realsense-ros.git cd realsense-ros git checkout git tag | sort -V | grep -P ^2.\d\.\d | tail -1 cd ~/catkin_ws catkin_make编译时有个常见错误找不到ddynamic_reconfigure包。这个包在ROS Melodic之后被移除了需要手动安装sudo apt-get install ros-noetic-ddynamic-reconfigure启动相机节点的命令roslaunch realsense2_camera rs_camera.launch启动后相机内参信息会发布在/camera/color/camera_info、/camera/depth/camera_info等话题上。你可以用rostopic echo查看rostopic echo /camera/color/camera_info输出中的K数组就是内参矩阵按行展开的9个数。D数组是畸变系数。4.2 通过camera_info话题读取内参并解析直接rostopic echo看数字不够直观我习惯写个小Python脚本把内参矩阵打印成易读格式#!/usr/bin/env python import rospy from sensor_msgs.msg import CameraInfo import numpy as np def callback(msg): K np.array(msg.K).reshape(3, 3) D np.array(msg.D) print(分辨率: {}x{}.format(msg.width, msg.height)) print(内参矩阵 K:) print(K) print(畸变系数 D: {}.format(D)) print(---) rospy.init_node(camera_info_reader) rospy.Subscriber(/camera/color/camera_info, CameraInfo, callback) rospy.spin()这个脚本订阅一次就打印一次方便你快速查看。如果你需要持续监控内参变化比如温度漂移测试可以把print改成写入CSV文件。解析时要注意K数组是行优先展开的reshape(3,3)之后第一行是[fx, 0, cx]第二行是[0, fy, cy]第三行是[0, 0, 1]。D数组的长度可能是5或8对应不同的畸变模型。Realsense通常输出5个系数k1, k2, p1, p2, k3。4.3 不同分辨率下的内参换算逻辑前面提到ROS驱动会根据分辨率调整内参这个调整逻辑其实很简单假设原始标定是在1280x720下做的你配置成640x480那么fx、fy、cx、cy都乘以0.5。但前提是图像是等比例缩放的没有裁剪。如果驱动做了裁剪比如只取图像中心区域换算就复杂了。cx和cy需要减去裁剪偏移量再缩放。好在realsense-ros驱动会自动处理这些你读到的camera_info已经是当前分辨率下的正确值。但有一种情况驱动不会自动处理你自己在launch文件里设置了color_width和color_height但驱动内部还是按原始分辨率出图然后软件缩放。这时候读到的内参可能和实际图像不匹配。验证方法是在图像中找一个已知位置的物体用内参反投影计算它的三维坐标看是否合理。注意如果你在launch文件中同时设置了enable_color:true和color_width:640建议同时设置color_fps:30避免驱动内部做不必要的帧率转换导致时间戳错乱。5. 那些年我踩过的坑常见错误与修复方法5.1 Viewer打不开或识别不到相机这是最常见的问题尤其是在Ubuntu下。症状是终端输入realsense-viewer后要么没反应要么报错“No device connected”。排查步骤先用lsusb确认系统是否识别到相机。Realsense的VID是8086你应该能看到“Intel Corp.”相关的设备。如果lsusb能看到但Viewer识别不到大概率是udev规则没装。运行官方提供的脚本sudo cp ~/librealsense/config/99-realsense-libusb.rules /etc/udev/rules.d/ sudo udevadm control --reload-rules sudo udevadm trigger如果lsusb都看不到换USB线、换USB口。Realsense对USB线材质量很敏感劣质线缆会导致供电不足或数据丢包。D435i建议用原装线或带屏蔽的USB 3.0线。ARM64平台Jetson上还有个特殊问题内核版本和librealsense的兼容性。Jetson Nano的默认内核是4.9librealsense 2.50以上版本需要内核5.4的UVC驱动支持。解决办法是升级JetPack或者用老版本librealsense。5.2 ROS中camera_info话题无数据启动realsense-ros后rostopic list能看到/camera/color/camera_info但rostopic echo一直没输出。这种情况通常是相机没出图camera_info就不会发布。检查顺序确认enable_color参数为true确认color_width和color_height设置合理不能超过相机支持的最大分辨率查看节点日志roslaunch的输出有没有“No device connected”或“Failed to set power state”之类的错误如果是USB供电不足尝试用带外部供电的USB Hub还有一个隐蔽问题如果你同时启动了多个realsense节点或者之前启动的节点没完全退出会导致设备被占用。用ps aux | grep realsense检查残留进程全部kill掉再重启。5.3 内参与实际图像不匹配的排查思路这个问题最让人头疼因为症状不明显但后果很严重。表现包括SLAM建图漂移、三维重建尺寸不对、AR物体位置偏移。排查方法我总结了一个流程排查项操作方法预期结果分辨率一致性对比camera_info的width/height和实际图像尺寸完全一致内参合理性fx和fy应该在图像宽度的0.5-1.5倍之间例如640宽图像fx在320-960之间光心位置cx和cy应该接近图像宽高的一半偏差不超过10%畸变系数D数组前两个值应该在-0.5到0.5之间超出范围说明标定异常实际验证用已知尺寸物体做反投影测量误差小于2%如果排查发现内参确实不对最彻底的解决办法是重新标定。ROS下有camera_calibration包可以用棋盘格标定板重新计算内参。标定过程这里不展开但记住一点标定时的分辨率必须和实际使用分辨率一致否则标定结果无效。5.4 ARM64平台上的特殊问题与解决Jetson系列和树莓派上跑Realsense问题比x86平台多得多。我整理了几个高频问题问题一Viewer打开后闪退。通常是OpenGL驱动问题。Jetson上需要确保安装了正确的GPU驱动运行glxinfo | grep OpenGL检查。如果显示“llvmpipe”说明用的是软件渲染性能极差且容易崩溃。解决办法是安装NVIDIA的GPU驱动或者用export LIBGL_ALWAYS_SOFTWARE0强制硬件加速。问题二ROS节点启动后帧率极低。ARM64的CPU性能有限如果开启了多个传感器流深度彩色红外处理不过来。建议降低分辨率或帧率比如用640x48015fps代替1280x72030fps。**问题三编译librealsense时报错“undefined reference to__atomic_load_8”。** 这是ARM64上常见的原子操作链接问题在CMakeLists.txt中添加-latomic链接选项即可。问题四鱼香ROS一键安装脚本在ARM64上失败。鱼香ROS的脚本主要针对x86_64架构ARM64上部分依赖包没有预编译版本。建议手动安装ROS基础包然后单独编译realsense-ros。6. 内参获取后的验证与标定建议6.1 用已知尺寸物体做快速验证拿到内参后别急着跑算法先花五分钟做个快速验证。找一张A4纸210mm x 297mm平放在桌面上相机垂直向下拍摄。用内参和深度图计算A4纸的长宽如果计算值和实际值偏差在2%以内说明内参基本可用。具体计算方法在深度图中找到A4纸的四个角点读取每个角点的深度值然后用内参反投影到三维空间计算相邻角点之间的距离。这个验证方法不需要标定板也不需要额外工具非常适合现场快速检查。6.2 什么时候需要重新标定出厂内参在以下情况下需要重新标定相机摔过或受到剧烈振动工作温度与标定温度差异超过15摄氏度需要亚厘米级精度比如三维扫描、精密测量发现内参验证偏差超过2%重新标定用ROS的camera_calibration包配合棋盘格标定板。标定板建议用8x6的棋盘格方格尺寸根据相机工作距离选择。标定过程中要覆盖图像的不同区域包括四个角和中心采集至少30组不同姿态的图像。标定完成后你会得到一个新的内参YAML文件。在realsense-ros的launch文件中通过camera_info_url参数加载这个文件驱动就会用新内参替换出厂值。6.3 内参文件的保存与跨设备复用内参文件建议按“相机型号_序列号_分辨率.yaml”的格式命名比如“D435i_123456789_640x480.yaml”。这样在多相机系统中不会搞混。跨设备复用要谨慎同型号相机的内参虽然接近但不完全相同。我实测过5台D435ifx的标准差大约是3个像素。对于精度要求不高的应用可以复用但高精度应用必须每台单独标定。保存内参时除了K和D建议把标定时的分辨率、标定日期、环境温度也记录下来。这些信息在后续排查问题时非常有用。7. 几个提高效率的实操技巧7.1 用脚本批量导出多相机内参多相机系统中手动一个个读取内参效率太低。我写了个脚本自动遍历所有连接的Realsense相机导出各自的内参到独立文件import pyrealsense2 as rs import json ctx rs.context() devices ctx.query_devices() for dev in devices: name dev.get_info(rs.camera_info.name) serial dev.get_info(rs.camera_info.serial_number) for sensor in dev.sensors: for profile in sensor.get_stream_profiles(): if profile.stream_type() rs.stream.color: intr profile.as_video_stream_profile().get_intrinsics() data { serial: serial, width: intr.width, height: intr.height, fx: intr.fx, fy: intr.fy, ppx: intr.ppx, ppy: intr.ppy, model: str(intr.model), coeffs: list(intr.coeffs) } filename f{name}_{serial}_{intr.width}x{intr.height}.json with open(filename, w) as f: json.dump(data, f, indent4) print(f已导出: {filename})这个脚本依赖pyrealsense2库用pip安装即可。运行一次就能把所有相机的内参全部导出省时省力。7.2 ROS中实时监控内参变化的简易方法如果你怀疑内参在运行过程中发生了变化比如温度漂移可以写个节点持续记录camera_info并对比import rospy from sensor_msgs.msg import CameraInfo import numpy as np ref_K None def callback(msg): global ref_K K np.array(msg.K).reshape(3, 3) if ref_K is None: ref_K K rospy.loginfo(参考内参已记录) else: diff np.abs(K - ref_K) max_diff np.max(diff) if max_diff 1.0: rospy.logwarn(内参变化超过1像素: 最大偏差{:.2f}.format(max_diff)) rospy.init_node(intrinsics_monitor) rospy.Subscriber(/camera/color/camera_info, CameraInfo, callback) rospy.spin()这个节点在启动时记录第一帧内参作为参考后续每帧对比偏差超过阈值就报警。对于长时间运行的应用这个监控很有必要。7.3 内参不准导致SLAM漂移的补救措施如果你已经跑了一段时间SLAM发现漂移严重怀疑是内参问题但又不想重新标定可以尝试在SLAM算法中手动调整内参。以VINS-Fusion为例配置文件中有model_type和intrinsics参数你可以把内参微调几个像素观察漂移是否改善。但这种方法治标不治本而且调参过程很痛苦。我的建议是如果确认是内参问题老老实实重新标定花半小时标定比花三天调参划算得多。8. 关于内参获取这件事的个人体会用Realsense这些年我最大的体会是内参这件事宁可多花十分钟验证也不要省事跳过。我见过太多项目因为内参不对导致返工包括我自己早期做的一个AGV项目因为用了错误的深度内参导致避障距离计算偏差20厘米差点撞上货架。Realsense Viewer和ROS获取内参的流程本身不复杂复杂的是各种环境差异和隐藏问题。Windows下顺风顺水Ubuntu下可能卡在udev规则ARM64上可能连编译都过不了。我的经验是每换一个平台先花时间把相机跑通确认内参能正确读取再开始做上层算法。这个时间投入绝对值得。最后分享一个小技巧如果你手头有多台同型号Realsense建议给每台相机贴个标签记录序列号和标定日期。内参文件按序列号命名保存。这样当某台相机出问题时你能快速定位并替换不会因为搞混了内参文件而浪费时间。这个习惯我坚持了三年帮我省下了至少几十个小时的排查时间。
阅读完成 · 觉得有帮助?
咨询建站