资讯动态

livox_camera_calib实战指南:激光雷达与相机外参标定避坑全流程

发布时间:2026/10/7 4:41:59 来源:尧图企业网站定制
做多传感器融合的兄弟应该都有体会当雷达点云和相机图像各说各话的时候整个世界都是割裂的。你辛辛苦苦重建出点云图想知道某个目标在图像里到底长什么样结果投影过去怎么都对不上边缘错位、轮廓发虚那多半不是算法不够硬而是外参没标准。激光雷达和相机标定求的就是两个传感器坐标系之间那个旋转矩阵和平移向量让两种数据能在同一个坐标系下好好说话。livox_camera_calib 就是专门干这件事的它把揽沃Livox系列激光雷达和相机之间的外参求出来而且不依赖雷达强度信息纯靠几何特征解算精度和鲁棒性都还不错。我自己前前后后用这个工具标过 mid-360、horizon 和好几款工业相机踩了不少坑这次把完整流程和能避开的雷区一次性写清楚希望能帮你少走点弯路。如果你正准备做激光雷达和相机的联合标定或者已经打开过 livox_camera_calib 的 GitHub 页面但被编译和操作流程劝退了那这篇内容就是给你准备的。不需要你提前懂多少李群李代数只要跟着步骤走理解每个环节为什么这么做基本都能顺利跑完整个标定流程。1. 标定前必须想清楚的三件事1.1 雷达和相机标定到底在标什么很多人一开始会把标定这事想复杂了其实拆开看就是求一个 4x4 的变换矩阵里面有一个 3x3 的旋转矩阵和一个 3x1 的平移向量。逻辑上就三步雷达坐标系下的点云先旋转、再平移变成相机坐标系下的坐标然后通过相机内参投影到像素平面。写作公式就是X_C R * X_L t再套上内参矩阵 K得到像素坐标u K * X_C / z。这里面 R 和 t 是雷达和相机之间的外参K 是相机内参。内参一般提前用标定板单独标好外参才是我们这次要解的东西。那为什么不靠肉眼手动对齐因为人眼在三维空间里估计六自由度变换实在太不靠谱。R 里三个旋转角t 里三个平移分量任何一项偏一点投影到图像上的位置就会偏很多。尤其在自动驾驶的障碍物检测、机械臂抓取、无人机避障这类场景里外参偏一度几十米外的目标在像素平面上就偏出十几个点直接导致目标框错位甚至漏检。所以标定这事不是可做可不做的加分项而是雷达和相机真正融合之前绕不开的必经步骤。1.2 livox_camera_calib 的核心思路这个工具是 Livox 官方开源的思路也相对直接它用一块平面标定板作为中介相机这边检测标定板的角点雷达这边从点云中分割出标定板平面并计算法向量两边建立起对应关系之后通过 PnP 或者类似的几何方法求出初始外参最后再做一次非线性优化把重投影误差压到最小。它最大的优点是不依赖雷达的反射强度信息。这一点对 mid-360 这类非重复扫描雷达来说特别重要因为非重复扫描模式下每帧点云的密度不均匀反射强度也不是稳定可靠的观测很多基于强度图的标定方案在这种雷达上效果很差。纯几何方案就不一样只关心点云中平面的形状和法向量对点云密度变化没那么敏感只要给定足够多帧数据平面拟合精度就有保障。1.3 硬件与软件准备清单先说硬件。雷达必须是 Livox 系列的产品mid-360、horizon、avia 我都试过都能跑通。相机没有太多限制工业相机、普通 USB 摄像头、甚至一些车载相机都行但是镜头畸变不能太大太大以后角点提取和投影验证都会比较痛苦。标定板建议用棋盘格尺寸要够大我实测下来在 3 到 6 米的距离上标定板边长至少要占到图像高度的四分之一到三分之一太小了角点检测会不稳定。光照环境尽量均匀避免强反光和直射阳光不然相机那边角点提取容易翻车。软件方面官方推荐的是 Ubuntu 18.04 或 20.04 配 ROS1Melodic 和 Noetic 我都用过。需要提前装好的依赖包括 libpcl-dev、libeigen3-dev、libceres-dev以及 ROS 的 cv_bridge、image_transport、pcl_ros 这些常用包。如果你用的是 ROS2那就得先想好怎么接 ros1_bridge 或者干脆在 Docker 里跑 ROS1毕竟这个工具本身只支持 ROS1这一步省不了。2. 编译安装与实际部署2.1 把依赖一口气装好依赖安装这件事看起来简单但版本坑特别多。我最开始直接在 Ubuntu 20.04 上用 apt 装 libceres-dev结果编译到一半就开始报错后来排查发现是 Ceres 库版本太新接口和 livox_camera_calib 里的代码对不上。所以依赖版本千万别随缘建议按我下面的方式装。# 安装基础依赖 sudo apt-get update sudo apt-get install ros-$ROS_DISTRO-pcl-ros ros-$ROS_DISTRO-cv-bridge \ ros-$ROS_DISTRO-image-geometry ros-$ROS_DISTRO-camera-calibration \ libpcl-dev libeigen3-dev # Ceres Solver 建议用 1.14.0这个版本被 livox_camera_calib 验证过 # 如果 apt 源里的版本太新就源码编译安装 git clone https://github.com/ceres-solver/ceres-solver.git cd ceres-solver git checkout 1.14.0 mkdir build cd build cmake .. make -j4 sudo make installCeres 1.14.0 这个版本挺关键因为某些新版 Ceres 把LocalParameterization改名成了Manifoldlivox_camera_calib 的代码还是老接口直接编译会报No member named LocalParameterization in namespace ceres。与其后面花时间改代码不如一开始就锁定老版本省心得多。2.2 编译过程中见过的高频报错装完依赖之后接着编译 livox_camera_calib。记得先把 livox_ros_driver 也编译好并且 source 到当前终端环境里否则编译时找不到雷达消息类型会直接报错。cd ~/catkin_ws/src git clone https://github.com/Livox-SDK/livox_camera_calib.git cd ~/catkin_ws catkin_make source devel/setup.bash我遇到的第一个高频报错是Could not find a package configuration file provided by livox_ros_driver。这个原因很简单catkin_make 的时候 livox_ros_driver 的包路径没有暴露出来。解决办法是先把 livox_ros_driver 编译好或者在同一个工作空间里把两个包放在一起重新 catkin_make。还有一个容易踩的坑是 OpenCV 版本导致的cv::imshow相关错误尤其是当你系统里同时装了 OpenCV 3 和 4 的时候编译时可能链接到了错误的版本。建议编译前先确认一下pkg-config --modversion opencv4的输出确保 cv_bridge 和 livox_camera_calib 用的是同一个 OpenCV 主版本。2.3 数据采集决定标定成败的关键一步工具编译完还不能直接开始标定数据采集是整套流程里最考验耐心、也最决定标定成败的环节。我的习惯是先把雷达和相机节点分别启动确认两个话题都有数据再开始录包。录包命令很简单rosbag record /livox/lidar /camera/image_raw -O calib_data.bag但命令简单不等于采集简单。激光雷达和相机标定我强调下面几件事第一传感器保持静止标定板动。如果是车载场景车辆一定要停稳让标定板在视野里变换姿态。如果传感器本身也在晃数据就会“糊”点云和图像对不上后面优化很容易发散。第二每个姿态都要停留足够时间。mid-360 是非重复扫描点云在同一个位置停留越久点云越密平面拟合越准。我个人的做法是在每个姿态停 1 到 2 秒再切换下一个姿态。第三姿态要有足够的变化。标定板要出现在视野的左边、右边、中间、远处、近处倾斜角度也要覆盖多种情况。如果所有帧都是标定板正对着相机那旋转矩阵的某些自由度可能约束不足优化结果会飘。第四避免背景中过多平面物体。墙、地面、桌面这些都会干扰点云中的平面分割采集的时候尽量让标定板周围空一点或者让标定板离其他平面足够远方便后续把标定板对应的点云单独分割出来。整个采集过程大概持续两三分钟就够了录出的 bag 文件也不会太大后面工具加载和回放都比较方便。3. 手把手操作流程3.1 配置文件逐项解读livox_camera_calib 的配置是通过 yaml 文件加载的里面主要包含了相机参数、标定板参数、话题名称和初始外参。我拿一份典型的配置逐项说明。要注意的是不同版本的仓库字段名称可能略有差异以你实际拉取的代码为准但核心逻辑大差不差。# camera_params.yaml camera: image_width: 1920 image_height: 1080 camera_matrix: [1425.04, 0.0, 960.5, 0.0, 1423.68, 540.2, 0.0, 0.0, 1.0] distortion_coeff: [-0.1052, 0.1183, -0.0002, 0.0007, -0.0358] target: target_type: checkerboard pattern_size: [11, 8] # 内角点数宽 11高 8 square_size: 0.03 # 单个格子边长单位米 livox: lidar_topic: /livox/lidar camera_topic: /camera/image_raw init_R: [0.0, -1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 0.0] init_t: [0.0, 0.0, 0.0]这里的 camera_matrix 和 distortion_coeff 就是相机的内参必须先用camera_calibration或者 Kalibr 标定好。如果你跳过内参标定直接做外参标定后续的结果基本没法看重投影误差会一直压不下去。target 部分最关键的是pattern_size和square_size一个填棋盘格内角点数一个填格子实际边长。这两个数错了后面角点提取和位姿解算全都会错所以填写之前拿尺子量一下别靠记忆。init_R和init_t是初始外参。很多教程把这里当成无关紧要的初值随便填其实错了。非线性优化对初值很敏感如果初始外参跟真实值差太远优化很容易收敛到局部最小值。我的经验是先大致估计一下雷达和相机的相对位置关系比如雷达在相机下方 5 厘米、偏左 3 厘米就在 init_t 里填上这些平移量init_R 则根据安装方向大致转个角度。初始值不需要太精确但方向不能反平移量级别不能差太多。3.2 开始标定的完整操作路径工具提供了一个图形界面启动之后可以加载刚才录好的 bag 文件。操作路径大致是这样的roslaunch livox_camera_calib calib.launchlaunch 起来之后GUI 窗口会打开按顺序选择 bag 文件并加载然后工具会开始逐帧回放。到某一帧图像上能看到完整标定板、点云中也有清晰的标定板点簇时就可以暂停下来进行角点提取和点云选取。角点提取这一步工具会调用 OpenCV 的棋盘格角点检测检测成功会在图像上把角点画出来。如果检测失败最常见的三个原因是曝光过高导致黑白格子对比度不足、运动模糊、以及标定板太小或太倾斜。遇到检测失败别硬扛调整一下相机曝光参数重新采集或者换一帧图像再试。点云选取则是在点云视图中手动框选标定板区域工具会基于框选区域做平面拟合计算出平面法向量。这个框选同样有讲究尽量只框标定板区域别把后面的墙面框进去否则平面拟合出来的法向量就不准了。处理完一帧数据之后工具会累积多帧观测等累积到足够多的帧数再触发优化。优化完成后会输出外参结果同时显示重投影误差。如果误差很大可以先看看是不是标定板角点和点云平面之间的对应关系错乱了也就是图像上选了标定板 A点云里框的却是标定板 B这种低级错误在标定板数量多的时候特别容易发生。如果误差不大结果基本就能用了。3.3 标定结果怎么解读和使用优化完之后工具会输出最终的外参矩阵通常以旋转矩阵和平移向量的形式给出。旋转矩阵看起来不像欧拉角那么直观但可以直接用于代码。你可以把它写成一个静态变换发布出去也可以存成参数文件供后续算法读取。实际使用中我更建议把结果转成一个 4x4 的齐次变换矩阵每次使用前先验证一遍确认它确实能把你预期的点云对应到图像上。验证方法很简单取一个新场景把标定板放到一个不曾在训练数据里出现过的位置录一帧然后用标定结果把雷达点云投影到图像上看看标定板边缘跟图像中的标定板是否贴合。如果误差在几个像素以内算合格如果差了几十个像素那说明标定过程有地方出问题了要先排查再使用。4. 避坑指南这些问题我几乎都踩过4.1 标定失败八成是数据问题工具本身出 bug 的时候少多数标定失败、精度差的根源都出在数据上。最典型的特征就是优化一直不收敛或者重投影误差很大。遇到这种情况别急着调参数先回头看看录的 bag 数据质量。我印象很深的一次是在室内环境下标定灯光很强标定板表面反光严重雷达点云里标定板的那一片点明显比周围稀疏平面拟合一直不稳。后来换了一块哑光表面的标定板问题一下子就好了。还有一个高频坑是时间同步。相机和雷达是两个独立传感器各自的时间戳如果偏差太大标定板稍微一动图像里的位置和点云里的位置就对不上了。录包之前建议先用rostopic echo /camera/image_raw/header和rostopic echo /livox/lidar/header对比一下时间戳看看两个话题的时间戳是否大致同步。如果发现相机的时间戳比雷达慢了或者快了几十毫秒最好在驱动层先校准或者采集的时候让标定板尽量保持静止减少时间不同步带来的影响。4.2 初始外参给偏了优化救不回来这个坑我掉过两回。第一次标定的时候我觉得“反正后面要优化初始外参随便给给就行”结果优化出来的结果惨不忍睹重投影误差大得离谱怎么调整迭代次数都没用。后来我试着把 init_t 填上雷达和相机之间真实的安装距离把 init_R 按安装角度大致设了一下优化马上就收敛了。这里面有个数学上的原因非线性最小二乘问题在目标函数非凸的时候存在很多局部极小值。初始点落在错误的局部极小值附近算法再强也回不到全局最优。所以千万别跳过初始外参这一步它相当于给优化提供一个合理的起点方向错了后面白干。最简单的初始外参设置方法先量出雷达和相机之间的三维安装距离填进 init_t再根据相机坐标系的朝向大概把 init_R 设为[0, -1, 0, 0, 0, -1, 1, 0, 0]或类似的正交旋转然后跑一遍看优化结果是否合理如果相差很大再手动调整。4.3 标定板点云分割与平面拟合问题平面拟合算是这个标定方法的核心步骤之一。雷达点云里的标定板如果拟合出来的法向量偏了初始外参的约束就错了后面结果也不会好。我在使用中总结出几个关键点。第一框选点云时避开边缘。标定板的边缘在雷达扫描中容易混入背景点尤其是当标定板比较薄的时候框选区域稍微大一点拟合法向量的点集里就可能混入背景。第二多帧数据里标定板的点云密度如果太低拟合出来的平面也会抖。mid-360 在同一个位置停留 0.5 秒和停留 2 秒点云密度差别很大建议每个姿态停留时间尽可能长一点。第三标定板最好离地面和墙面远一点如果现场条件实在不允许那就确保框选时只选标定板本身的点宁可框小一点也别框进杂点。4.4 问题排查速查表为了方便遇到问题时快速定位我把常见的现象、原因和对策整理成一张表现象可能原因解决办法编译时报找不到 livox_ros_driver雷达驱动包未编译或未 source先编译并 source livox_ros_driver再重新 catkin_makeCeres 相关编译报错Ceres 版本太新切换到 1.14.0 重新编译安装图像中检测不到棋盘格角点光照不足、过曝、标定板太小调整曝光增大标定板尺寸或更换帧点云中没有标定板点簇标定板距离过远、反光太强拉近标定板距离使用哑光标定板优化后重投影误差大初始外参偏差太大、对应关系错误重新设置 init_R 和 init_t检查是否选了错误标定板结果对不上边缘错位时间不同步、内参不准检查时间戳重新标定相机内参5. 标定效果验证与后续扩展5.1 用重投影验证标定精度标定完成之后一定不要急着把结果拿去用先做一次验证。最简单的验证方式是重投影把雷达点云里的某个突出特征点比如标定板的某个角点通过标定外参投影到图像上看它是否落在图像中对应的像素位置。如果偏差在几个像素以内说明外参精度不错如果偏差很明显那就是标定过程还有问题最好的选择是重新采集数据再标一次而不是硬着头皮用这个结果。我自己习惯用一组单独录制、不参与标定的验证数据来做这个检查。遍历验证数据里的每一帧逐帧投影然后把所有帧的平均像素误差统计出来。这个误差能比较客观地反映外参的精度水平。一般 5 个像素以内的平均误差对于多数融合任务来说已经够用了如果做到 2 到 3 个像素那就相当不错了。5.2 点云着色与融合效果展示外参标好之后雷达点云和相机图像才真正融合在一起。我最常用的一个应用是点云着色把每个雷达点投影到图像上取出对应像素的颜色并赋给这个点。着色后的点云可以直接在可视化工具里检查融合效果看一眼墙面、车辆、行人的颜色边界是否清晰一致就能直观判断标定结果好不好。如果颜色沿着物体的边缘有明显的“渗色”说明投影位置还有偏差可能需要再微调。如果要做目标检测或者语义分割融合标定好的外参就等于是地基。雷达检测到目标并给出 3D 位置后通过外参投影到图像上生成 2D 框跟相机检测框做融合这一步的精度直接取决于外参标定的质量。很多融合框架跑起来效果差最后查下来都是外参偏了所以在这个环节多花一点时间绝对值得。5.3 关于标定精度的一些个人体会我把前前后后标定过的项目经验总结一下。精度的上限其实由三件事决定相机内参的精度、标定板数据的质量、初始外参给得靠不靠谱。内参不准后面的一切都会跟着偏标定板数据里如果混入了很多干扰帧优化结果会不稳定初始外参如果偏差太大非线性优化很容易掉到局部最优。所以整个标定流程里最值得花时间打磨的往往不是工具参数而是数据采集环节和初始外参的估计。我个人的习惯是同一组设备进行多次标定每次稍微改变标定板的姿态范围然后对结果做对比。如果多次标定的外参结果一致性很好说明标定过程稳定可信如果几次结果差异明显那说明数据里存在某些我们的标定流程没覆盖到的误差源需要回到采集环节排查而不是直接取个平均就完事。毕竟取平均只能抹平随机误差对系统性的偏差毫无帮助。这个工具虽然名字里带 livox但我试过如果只是把话题名改一改配合一些非 Livox 雷达的点云数据只要点云里有清晰的平面特征同样也能跑通流程。当然官方支持的主力还是自家雷达在这个生态下使用标定效果和稳定性是最有保障的。如果你用的是其他品牌雷达又想做类似的外参标定也可以参考这个工具的思路自己写一套基于平面拟合的方案核心逻辑是相通的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑