ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

2D激光雷达与相机自动联合标定全流程详解

2D激光雷达与相机自动联合标定全流程详解 去年做一个AGV项目传感器融合链路里既有2D激光雷达又有工业相机雷达负责测距和避障相机负责识别目标两者数据必须对齐到同一个坐标系里才有意义。一开始我用厂家自带的标定工具手动画点选了大半天重投影误差还有十几个像素晚上跑起来偏差更明显整个感知链路都跟着飘。后来没办法自己搭了一套2D激光雷达与相机的自动化联合标定流程把人工选点的环节全踢出去半小时能跑完一轮标定重投影误差稳定压到1像素以内。这篇就把这套流程完整拆开讲从数学本质到标定板怎么做、数据怎么采、算法怎么搭、怎么验收全部按我实际走过的路来写适合刚接触雷达相机融合、被手动标定折磨过、或者想把自己标定流程自动化的人。1. 先搞清楚自动化标定到底在解一个什么问题1.1 外参标定的数学本质标定这事听起来玄说白了就是求两个坐标系之间的换算关系。激光雷达有自己的一套三维坐标系相机有自己的一套三维坐标系图像还有一套像素坐标系。我们要找的是一组旋转矩阵 R 和平移向量 t让同一个物理点在两个传感器各自坐标系下的描述能够互相转换[ p_C R \times p_L t ]其中 (p_L) 是点在雷达坐标系下的坐标(p_C) 是同一个点在相机坐标系下的坐标。有了这个变换雷达点云就能投影到图像上和像素位置对齐。然后再加上相机内参矩阵 K 和畸变参数把相机坐标系下的三维点映射到像素平面[ (u, v) \pi(K, D, p_C) ]这里的 (\pi) 是完整的相机投影函数包含内参和畸变矫正。整个标定的目标就是找到一组 R 和 t让所有三维点投影到图像上的位置和它们真实对应的像素位置尽可能一致。这个误差叫重投影误差也是后面验收的核心指标。用人话讲就像两个人在不同位置看同一张桌子一个人说桌子在我东南方向五步远另一个人说桌子在我照片的某个像素坐标标定就是算出这两个人坐标系之间的换算关系让两种描述方式能互相翻译。1.2 2D雷达标定难在哪只有线没有面3D激光雷达标定的资料很多方法也相对成熟因为一帧点云里有几千几万个分布在三维空间中的点能直接拟合出标定板的完整平面约束非常充分。2D激光雷达就不一样了。2D雷达扫描出来的是一个大平面内的一条线上的一串点本质上是单线点云在绝大多数安装方式下都近似位于一个水平面内。也就是说对于标定板上任意一个点我知道它相对雷达的距离和角度但完全不知道它在这个扫描平面之外的高度信息。这就带来一个直接后果一帧2D雷达点云无法单独确定标定板的完整三维姿态。雷达打在标定板上得到的只是一条水平线段而不是一个面。想从这条线段推断出板子具体怎么倾斜、怎么旋转数学上信息是不充分的。所以2D雷达标定必须引入先验几何约束比如标定板的平面方程、板的尺寸、安装高度等。这也是为什么很多一键标定工具对2D雷达支持很差因为难度不在于求解本身而在于如何用最少的观测信息恢复足够的几何约束。1.3 为什么自动化是必须的手动标定的问题我在项目里体会太深了。点云是稀疏的投影到图像上就那么几个点鼠标一抖就是三五个像素的误差。相机图像里棋盘格角点明明很多但你要在点云里找到对应的点全靠猜。来回调整标出来的结果还不稳定换个人标结果又不一样。自动化标定要把人肉选点这个环节彻底干掉改成算法自动检测标定板、自动提取特征、自动建立对应关系、自动求解和优化。这样做的好处不只是省时间更重要的是可重复性和可批量性——同一套流程可以在不同距离、不同角度下反复采集数据把所有观测累积到一起做联合优化精度和稳定性都远超人手工选点。2. 整体流程与自制标定板的细节2.1 整套标定链路的分工我的自动化标定流程分成六步每一步都有明确的目标准备阶段做一块符合要求的标定板标定相机内参。采集阶段同时触发采集雷达点云和图像变换板子姿态采多组数据。特征提取在雷达点云中自动找标定板线段和强度边界在图像中自动检测棋盘格角点。对应生成把雷达特征和图像特征自动关联成3D-2D对应点。求解优化先用EPnP求初始外参再做光束法平差优化。验收用重投影误差和三维精度做最终判定。这里面有个隐藏前提相机内参必须先标好否则外参标定会把内参的误差一起吃进去。相机内参标定用OpenCV的棋盘格流程就行采集20到30张不同姿态的图片calibrateCamera一步出结果重投影误差压到0.1像素以内再继续。2.2 标定板选型与自制细节这块是整个标定成败的关键很多人的标定结果不理想根源就在板子上。我的方案是自制的平板结构一块黑色哑光铝塑板作为基底上面贴白色漫反射棋盘格。黑白棋盘格本身用于相机角点检测而黑白区域在雷达反射强度上的差异恰好能作为雷达侧的特征。具体参数参考项目推荐值说明板子整体尺寸700mm x 900mm太小的板子在雷达点云里只有十几个点特征提取不稳定棋盘格格子边长80mm兼顾雷达扫描分辨率与图像角点精度棋盘格行列9格 x 7格内角点8 x 6足够求解基底材质黑色哑光铝塑板平面度好哑光减少反光表面处理白色漫反射膜不能用镜面或亮面材料否则相机过曝且雷达多路径严重这里有个关键细节黑色基底和白色棋盘格在雷达反射强度上有明显差异。2D雷达的强度值是收到的回波能量白色漫反射面回波强黑色哑光面回波弱。于是雷达扫描线扫过板子时点云里会出现一段一段的强度变化黑白格的边界就是强度阶跃点可以和棋盘格的竖线位置关联起来。板子打印的时候要注意不能用普通亮光相纸必须用哑光打印或者覆哑膜。以前我用亮光相纸做过一块板子相机标定的时候角点检测倒是没问题但雷达打上去出现了很多跳变点因为光泽面在某些角度会产生镜面反射回波忽强忽弱点云都毛了。2.3 场景与工况要求标定场地也有讲究。板子背后不要紧贴墙壁至少留出0.5到1米的空间否则雷达打出的点不仅落在板子上还会在后面的墙上产生第二个回波簇聚类分割时要多花很多功夫去滤除。板子必须垂直地面放置最好是靠在自制的简易支架上用水平尺确认。雷达扫描平面近似水平板子垂直时扫描线和板面接近垂直相交得到的线段特征是稳定的。如果板子倾斜雷达扫描线打在板上的几何关系就复杂了第一版流程没必要搞那么难。场景里不要有太多其他反射物。我踩过一个坑标定室里有一根金属柱子雷达点云里它和标定板几乎一样亮聚类之后有两条差不多的线段程序差点认错。后来给聚类加上了几何约束——标定板线段必须落在图像中板子的对应区域内才把这个误检解决掉。3. 数据采集环节时间同步、曝光与点云质量很多人把数据采集想简单了觉得只要同时开雷达和相机录一会就行。实际上采集质量直接决定标定结果的精度上限这块值得单独说。3.1 时间同步与同时触发雷达和相机是两个独立工作的设备每一帧数据都有自己的时间戳。如果时间戳不一致采集到的雷达点云和图像对应的不是同一个时刻的场景那标定出来的外参就是错的。最稳的方案是硬件同步。工业相机一般带外触发接口可以用雷达的同步输出信号去触发相机曝光也可以让两者都接受同一个外部触发源。这样做的好处是相机曝光瞬间和雷达扫描的某个角度严格对齐时间偏差是微秒级别的。如果用的是普通USB相机或者没有硬件同步条件也不要慌。标定时让场景完全静止——机器人和标定板都不动然后软件层面用ROS的message_filters做时间同步或者干脆采集时只取时间戳最接近的雷达帧和图像帧。静止场景下时间偏差影响很小因为场景根本没变。3.2 帧内运动畸变标定时的隐形杀手2D雷达是一圈一圈旋转扫描的一圈的扫描时间通常在50到100毫秒之间。这意味着雷达一帧数据里不同角度的点实际上是不同时刻测到的。如果雷达装在一个移动的底盘上底盘一边走一边扫描同一帧内的点就被拉歪了点云会变形。这个现象叫帧内运动畸变。标定时这个问题尤其致命。外参标定要求雷达点云和图像严格对应点云都畸变了对应关系自然全错。我在项目里第一次标定时没注意机器人处于待机但轮子还在轻微调节位置结果标出来的外参怎么看怎么不对重投影误差一直在两三个像素降不下去。解决方式很简单标定过程中把机器人断电或者把轮子锁死场景物理静止。标定板也放稳不要有人扶着——人再稳也有呼吸和抖动毫米级抖动对雷达点云来说就是噪声。3.3 相机曝光与图像质量相机参数必须固定不能用自动曝光、自动白平衡。自动曝光在标定板移动时会不停调整明暗角点检测精度会波动。我用的是固定曝光时间、固定增益室内光源下曝光设在1/60秒左右同时确认标定板上没有高光溢出。还有一个容易忽略的点标定板在图像里要占足够面积。目标尺寸控制在图像的1/4到1/2之间太小了角点提取精度不够太大了板子边缘超出画面点云和图像对应不上。每采集一组数据就检查一下板子的四个角是否都在画面内有一个角出去了就重新摆。采集数量方面我的习惯是采集8到12组不同位姿的数据每组里雷达和相机各取30帧左右用于后续联合优化。位姿要有变化包括左右移动、前后移动、轻微旋转但不能让板子转得太歪导致棋盘格角点检测失败。4. 自动化特征提取从点云和图像里把特征抠出来4.1 雷达点云预处理与标定板线段提取雷达侧特征提取的第一步是点云预处理。我按照这个顺序处理裁剪距离只保留0.3到8米范围内的点去掉雷达近场盲区和远处杂点。强度粗筛标定板白色区域强度高可以按强度直方图先粗筛出一批候选点。欧式聚类按相邻点距离阈值0.03米把点云分成若干簇每个簇就是场景里的一个物体。线段拟合对每个簇用RANSAC拟合线段得到端点、长度和方向。几何筛选长度和板子宽度接近的线段候选为标定板再结合图像中板子的位置做二次确认。伪代码大概是这样的cloud load_one_scan() cloud cloud[(cloud.r 0.3) (cloud.r 8.0)] clusters euclidean_cluster(cloud.xy, eps0.03) for label in unique(clusters): pts cloud.xy[clusters label] seg ransac_line_fit(pts) if 0.4 seg.length 1.0: candidates.append(seg)标定板垂直放置时雷达扫描线切过板子得到一条水平线段。如果雷达角分辨率0.25度工作距离1.5米相邻扫描点间距大约6.5毫米板宽700毫米的板子上能打好几十个点线段拟合的精度很高。但要是距离拉到5米点间距变成22毫米板子上只有三四十个点精度就差很多。所以采集标定数据时我一般把板子放在1到2.5米的距离范围内。4.2 图像角点检测与亚像素细化图像侧用OpenCV的棋盘格检测一行代码就能拿到角点ret, corners cv2.findChessboardCorners(gray, (cols, rows)) if ret: criteria (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) corners cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)cornerSubPix这一步是必须的它把角点精度从像素级提升到亚像素级。对于外参标定来说图像角点的精度直接影响最终结果能拿亚像素就不要停留在整数像素。真实场景里棋盘格检测偶尔会失败尤其是板子轻微反光或者处于阴影中。我在流程里做了一个很实用的策略连续三帧图像都检测到同样数量角点才认为这个位姿有效。偶尔一帧检测失败直接跳过不中断整个采集流程。4.3 对应关系自动装配不靠手点的做法这是整个自动化流程里最核心的一步。雷达点云里的一个点怎么和棋盘格图像里的某个角点对应上我的做法利用了板子的物理几何。雷达扫描线打在标定板上会留下一条线段这条线段在板平面上对应一个水平高度。又因为板子的棋盘格行列数是已知的棋盘格每一列竖线在板坐标系下的x坐标是固定的。我们需要找出雷达扫描线和棋盘格某条竖线的交点这个交点在雷达坐标系中的位置可以从点云得到在板坐标系中的位置可以从棋盘格尺寸算出。具体分三步第一步拟合雷达坐标系下的板平面方程。雷达扫描平面是z0平面板子垂直地面时雷达点云里的线段点都在板平面上可以拟合出平面法向量n和距离d得到 [ n_x x n_y y d 0 ]第二步找出雷达扫描线上的强度阶跃点。黑白棋盘格的边界在雷达强度序列里表现为明显跳变用一阶差分加阈值就能检测到。每个阶跃点对应一个扫描角度。第三步把阶跃点对应的扫描光线与板平面的交线联合起来计算出该交点在雷达坐标系下的三维坐标。同时根据棋盘格的物理尺寸知道这个边界对应棋盘格哪一列竖线以及扫描线在板面上的高度位置从而得到该交点在板坐标系下的坐标。这样每条扫描线都能生成一组2D-3D对应关系而且是自动完成的。这里要提醒一个容易踩的坑单帧雷达扫描线上的点是近似共线的用共线的点去解外参必然退化。所以必须采集板子在不同距离、不同横向位置的位姿让所有观测点不共线约束才能充分。这也是为什么我坚持要多组位姿采集而不是一帧搞定。5. 外参求解与光束法平差优化5.1 初始解EPnP与RANSAC有了若干组3D-2D对应点之后第一步是求一个初始外参。这个问题在计算机视觉领域叫PnPOpenCV的solvePnP提供了多种实现其中EPnP在点数量适中的情况下鲁棒性和速度都不错。但实际数据里一定会有外点。可能是雷达强度边界检测偏了一个点也可能是图像角点亚像素细化在某些图片上失败了。直接用最小二乘求解的话一个外点就能把结果拉飞。我的做法是先做RANSAC循环随机采样4组对应点用EPnP求出一组外参把所有点投影到图像上计算误差误差小于阈值的视为内点。重复几百次保留内点最多的一次再用所有内点重新做一次EPnP求解。这一步跑出来的R和t已经基本靠谱了重投影误差大概在几个像素的水平。但离最终目标还不够因为PnP只用到了一部分对应点没有把所有采集到的数据都用上。5.2 联合优化目标函数与LM迭代初始解出来之后把所有采集到的有效数据全部扔进同一个优化问题里。优化的目标函数是[ \min_{R,t} \sum_{i} \rho(| \pi(K, D, R X_i t) - u_i |^2) ]其中(X_i)是雷达坐标系下的三维点(u_i)是对应的图像像素坐标(\pi)是带畸变的相机投影函数(\rho)是鲁棒核函数我用Huber核来抑制外点影响。优化变量只有R和t相机内参K和畸变D在优化中固定不变。我推荐用Ceres Solver来做这个优化自动求导、LM算法都内置了写起来不费劲。用scipy的least_squares也能做但效率稍低。迭代几十次之后重投影误差从几个像素能压到1像素以内。这一步步把几十帧的数据累积起来一起优化比单帧单点求解强太多。雷达单点噪声在毫米到厘米级单点约束很弱但几百个点加在一起统计上就能把噪声平均掉。5.3 优化里的两个坑旋转参数化与权重分配旋转矩阵直接用3x3矩阵做优化变量是不行的九个参数有冗余约束优化器会迷茫。我用的是旋转向量本质上就是李代数so(3)的参数化方式Ceres里自带支持。千万不要用欧拉角万向锁问题会让你优化中途突然发散。另一个坑是雷达和图像特征的权重分配。图像角点精度是亚像素级的大概0.1到0.3像素而雷达点的位置噪声可以到3到5毫米投影到图像上可能是1到2个像素。如果两者的误差项权重一样优化器会被雷达噪声带偏。我的做法是在目标函数里给两类误差项设置不同的信息矩阵雷达项权重给低一些图像项权重给高一些。具体比值可以先按3:1试再根据初始优化后各项残差的实际分布调整。6. 验收与维护别标定完就不管了6.1 怎么判定标定结果合格外参标定完必须做验收不能光看优化报告里的数字。我自己用三组指标交叉验证指标目标值验证方法重投影误差均值 1像素所有观测点投影误差求平均重投影误差最大 3像素检查有没有个别离群点点云套合效果板边界贴合棋盘格边缘把雷达点云投影到图像上目视检查三维距离精度 2cm 3m在场景中放已知尺寸目标对比雷达测距和图像推算距离重投影误差是常用指标但必须配合目视检查。我见过有人指标很好看一投影到图像上却发现雷达点和物体边缘整体偏移这不是偶然说明对应关系里有系统性偏差。把点云投影到图像上用肉的眼光扫一遍板子边缘比任何指标都直接。三维距离精度的验证方法很朴素在标定板旁边放一个直径已知的圆柱体雷达扫过去能测出它的距离和边界相机看到它的像素位置和外接框两者换算出的空间位置和实际测量的误差就是最终答案。6.2 环境变化引起的失标与快速复检很多项目标定完就完事了但外参是会漂的。震动、螺丝松动、车辆碰撞、热胀冷缩任何一个因素都会让R和t慢慢偏离真值。我见过一台AGV标定完用了三个月某天客户反映识别不准一查外参已经偏了七八厘米。我习惯在车上放一块固定的退役标定板作为基准靶。每周跑一次快速复检流程站在固定位置扫一遍标定板把实时数据和标定时记录的基准对比重投影误差超过阈值就报警。这种固定靶的维护标定成本很低不用每次做全套流程。复检可以用简化的流程只要检测到标定板雷达提取线段图像提取角点做一次PnP解算看重投影误差是否在可接受范围内。整个过程跑一次只要十几秒完全可以自动化。6.3 扩展到多雷达多相机系统的思路如果项目里有多个相机或者多个雷达也不要慌。核心原则是每个相机分别和雷达做一次标定得到各自的R和t。多雷达的情况先标定雷达之间的相对位姿再把所有雷达统一到主雷达坐标系下。双目相机和深度相机也是类似的思路只是深度相机多一步RGB-D对齐的校验。鱼眼相机则要换成Fisheye畸变模型来做投影函数。不管传感器怎么组合底层都是同一套理论找对应点、求初始解、批量优化、验收。标定这件事最难的不是数学而是把每个环节的误差来源都控制住。如果让我给新手一个建议第一版不要贪多先用一块板、一个雷达、一个相机的固定场景把整套链路跑通。跑通之后你就有底气把标定从最怕的一环变成随手可做的日常维护。
返回列表