ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

手眼标定从入门到实战:2D与3D相机标定流程及精度验证指南

2026/9/18 11:30:15 拓冰建站 浏览量
手眼标定从入门到实战:2D与3D相机标定流程及精度验证指南 1. 为什么2D和3D相机的手眼标定总被混为一谈做机器人视觉引导的人迟早要跟手眼标定打一场持久战。我在现场调试时见过太多这种情况2D相机项目里标定一次就过换到3D结构光相机后拿着同一套思路去标结果要么精度飘忽不定要么干脆解算出错最后折腾几天发现是连坐标系都没对齐。这里面的核心原因在于手眼标定不是一个固定的算法而是“数据形式 坐标系约束 求解策略”的组合。2D相机拿到的是一张灰度图或彩色图特征点是像素坐标3D相机拿到的是深度图、点云或视差图特征是空间坐标。两者虽然都叫手眼标定但采集方式、优化目标、误差来源完全不同。先明确手眼标定的本质它要求解的是相机坐标系和机械臂末端或基座坐标系之间的变换关系。经典公式就是 AX XBA 是机械臂末端在两个位姿之间的运动B 是相机在两个位姿之间观测到的运动X 就是我们要的手眼矩阵。这个等式看起来简单但放到2D和3D场景里A 和 B 的构造方式天差地别。写这篇文章的初衷很简单把我自己在2D和3D相机手眼标定上踩过的坑、验证过的方法、以及最终沉淀下来的标定流程做一个完整的总结。内容覆盖从原理理解到实操步骤再到位姿采集技巧和精度验证方法适合正在做机械臂抓取、上下料、定位装配、检测引导的工程师参考。2. 手眼标定的底层逻辑坐标系链条和AXXB2.1 坐标系链条到底有哪几环手眼标定本质上是在串联一组坐标系变换关系。以眼在手外Eye-to-Hand为例视觉系统固定在支架上机械臂在视野范围内运动坐标系链条是这样的机械臂基座坐标系 Base机械臂末端坐标系 End标定板坐标系 Board相机坐标系 Camera我们最终想要的是 Camera 到 Base或者 Board 到 End的变换。但相机直接看到的是 Board机械臂直接知道的是 End 在 Base 下的位姿中间缺两环标定板在相机下的位姿以及相机在基座下的位姿。眼在手上Eye-in-Hand则反过来相机装在机械臂末端标定板固定在外部此时要解的是 Camera 到 End 的变换坐标链条变成 Base → End → Camera → Board。很多新人分不清这两种模式其实只需要记住一点X 永远指的是相机固定在谁身上。相机固定在机械臂上就求 Camera→End相机固定在外部就求 Camera→Base。2.2 AXXB 的含义与矩阵构造AXXB 的推导过程并不复杂。假设机械臂从位姿1运动到位姿2末端运动为 A同时相机观测到标定板的运动为 B。因为相机和末端之间的变换 X 始终不变就得到A X X B注意这个公式里 A 和 B 都必须是齐次变换矩阵包含旋转和平移。A 由机械臂示教器或控制器读出B 由相机在不同位姿下对标定板的观测结果求得。这个公式的求解在OpenCV里有现成函数比如cv2.calibrateHandEye支持Tsai、Park、Daniilidis等多种算法。但这里有个关键容易踩的坑不同算法对 A、B 的输入格式有约定有的要求将 A 定义为机械臂末端运动有的要求定义为基座运动方向反了算出来的 X 可能就是个错误的矩阵。2.3 为什么2D和3D场景下的B矩阵构造方式不同2D相机中B 矩阵是通过标定板角点的像素坐标求解得到的。相机对标定板做 PnP 求解得到 Board 在 Camera 下的位姿。因为标定板是平面的2D相机只能依赖角点特征来恢复位姿对图像质量、畸变、视角都非常敏感。3D相机中B 矩阵可以通过多种方式获得。一种是直接对标定球做球拟合用球心位置代替角点得到多个球心在相机坐标系下的三维坐标再做三点或四点求解位姿。另一种是直接将标定板点云与CAD模型或理论点云做配准得到完整的6D位姿。还有一种是利用平面拟合提取标定板平面的法向量和中心点来构造约束。从数据维度上讲3D相机提供了更丰富的约束理论上标定应该更容易但3D点云本身有噪声、有离群点深度图边缘还有飞点反而引入了2D场景中不存在的误差源。这就是为什么很多人从2D转到3D标定时会处处碰壁。3. 2D相机手眼标定从内参到外参的完整操作链路3.1 内参标定是手眼标定的地基别偷懒2D相机的手眼标定有个前置条件相机的内参和畸变系数必须先标定好。内参不准后面算出来的 B 矩阵就会带误差而且这种误差不会因为采集更多数据而消失只会让结果稳定地错。内参标定我用的是 OpenCV 的cv2.calibrateCamera标定板选用 12×9 的棋盘格方格边长 30mm。采集时注意几点标定板必须在视场内保持多种姿态倾角从 0° 到 45° 都要覆盖图像要覆盖画面的中心和四个角落不要只拍正前方至少采集 15-20 张有效图像剔除模糊和有反光的重投影误差要控制在 0.1 像素以内超过这个值就检查标定板是否平整内参标定完成后畸变系数要和内参矩阵一起保存。后续所有 PnP 求解都应该传入畸变系数对像素坐标做去畸变处理否则角点位置会系统性偏移。3.2 Eye-to-Hand 标定的位姿采集策略2D 相机手眼标定的数据采集说白了就是让机械臂带着标定板在相机视野里做一系列运动同时记录机械臂末端位姿和相机检测到的标定板位姿。以 Eye-to-Hand 为例我在项目里通常这样操作将标定板固定在机械臂末端法兰盘上确保标定板平面与法兰盘平面尽量平行最好用夹具保证刚性连接控制机械臂移动到 15-20 个不同位姿这些位姿要覆盖视野的不同区域和不同角度每个位姿下记录机械臂末端在基座下的齐次矩阵 A_i同时通过相机检测标定板角点用cv2.solvePnP求出标定板在相机下的齐次矩阵 B_i将 A_i 和 B_i 构造成 A、B 序列输入cv2.calibrateHandEye这里有个容易忽略的细节机械臂末端位姿的读取方式。有些控制器的返回值是位置加欧拉角需要转换成齐次矩阵有些直接返回四元数或旋转矩阵。转换时务必搞清楚旋转角的顺序是 RPY 还是欧拉角 ZYX搞错顺序整个标定就全废了。3.3 位姿数量与姿态多样性的定量分析很多人问到底采集多少组数据才够。我的经验是位姿数量不能太少但盲目堆数量也没用关键是姿态要有足够的差异性。从数学角度看AXXB 的求解依赖机械臂运动 A 的旋转轴方向分布。如果机械臂只在同一个平面内平移旋转轴方向几乎不变那么方程组的约束条件会退化X 的旋转部分求解不稳定平移部分更是无法收敛。实际操作中我会保证至少 15 组有效数据机械臂姿态包含绕 X、Y、Z 三个轴的旋转变化旋转角度差异最好超过 30°标定板在图像中的位置覆盖画面的 9 宫格区域机械臂末端运动方向尽量不要平行或共线我自己验证过15 组姿态恰当的数据比 30 组姿态相似的数据标定结果更稳定。这一点在工业现场尤其重要因为现场往往时间紧张能用15组解决的事就不要拖到30组。4. 3D相机手眼标定的特殊方法和数据形式4.1 3D相机标定的三种主流路线3D相机的手眼标定没有统一标准工业界大致有三种路线第一种是基于球拟合的方法。在机械臂末端固定一个高精度球体3D相机获取点云后通过球拟合算法得到球心在相机坐标系下的三维坐标。由于球心与球的姿态无关这个方法的优势在于不需要标定板在图像中保持特定姿态对遮挡、视角都有较强的鲁棒性。但球拟合对点云质量要求高球的点云至少要覆盖一半以上的球面且边缘飞点不能太多。第二种是基于3D标定板/多球板的方法。在一块平板上固定3-4个已知间距的高精度球体3D相机对整个板面采集点云识别多个球心后根据球心间的几何约束来计算板的6D位姿。这种方法比单个球更快因为一次采集就能得到足够的位姿约束但需要保证所有球都能被相机看到。第三种是基于点云配准的方法。将3D相机采集的标定板点云与理论模型点云做 ICP 配准直接得到6D位姿。这种方法的优势是通用性强不需要特制标定物但配准算法对初始值敏感点云噪声大时容易陷入局部最优。我在项目中用得最多的是第二种多球板标定。原因很简单效率高、鲁棒性好、结果可重复。前提是球体的加工精度要够高球的圆度误差控制在 0.01mm 以内间距误差控制在 0.02mm 以内。4.2 球心提取的点云处理流程球心提取是整个3D标定中最关键的一步直接决定 B 矩阵的精度。我总结了一套稳定的处理流程对采集到的原始点云做直通滤波裁剪出标定板区域去掉背景干扰用统计滤波或半径滤波去除离群点通过 RANSAC 平面拟合提取标定板平面移除平面点云剩余的点云就是3个球面的点云用欧式聚类分割成3个独立点簇对每个点簇用最小二乘球拟合输出球心和半径球拟合这一步我推荐使用开源库open3d或者 PCL 的SACModelSphere。实测下来球心重复精度可以做到 0.05mm 以内前提是点云质量正常、球面覆盖率超过60%。这里有一个细节球拟合前一定要把标定板平面的点云完全移除干净。如果平面点和球面点混在一起拟合球心位置会被平面点拉偏误差可以达到毫米级。4.3 RGB-D对齐和深度图噪声对标定结果的影响3D相机中有一类特殊情况就是RGB-D相机比如 Intel RealSense、Azure Kinect。这类相机的深度图和彩色图来自不同的传感器需要先做对齐对齐精度直接影响后续的标定。我踩过的一个坑是直接用对齐后的RGB图去做标定板角点检测再把角点的像素坐标映射到深度图上取深度值得到角点的3D坐标。听起来没问题但实际因为RGB图和深度图之间存在视差尤其在物体边缘角点处的深度值经常是错的。如果你的3D相机是RGB-D类型建议优先使用深度图本身的点云或者用点云中的3D特征比如球心、平面交点来做标定而不是通过RGB角点映射深度。另外深度图在物体边缘会产生飞点这些飞点在点云里表现为悬浮在空中的离群点。如果标定球刚好位于视野边缘球面点云会被飞点污染导致球心计算偏移。我的做法是在点云预处理阶段对每个点簇做一遍统计滤波把离群点彻底清掉再拟合。5. 位姿采集的数据质量和手眼标定的退化问题5.1 标定数据退化的典型表现和规避方法无论2D还是3D手眼标定都会遇到退化问题。所谓退化就是采集的位姿虽然很多但信息量不足导致方程组病态。退化的典型表现是标定结果的重投影误差很小但实际引导抓取时精度很差。导致退化的几个常见原因机械臂运动只发生平移几乎没有旋转旋转轴方向始终不变比如机械臂只绕 Z 轴旋转标定板/标定球始终在图像的同一区域机械臂运动幅度过小A 矩阵之间的差异接近零针对这些问题我在采集数据时给自己定了几条硬性要求相邻两个位姿之间的机械臂运动必须足够大尤其是旋转角度差至少要有 15° 以上整个数据集中机械臂绕 X、Y、Z 三个轴旋转的姿态都要覆盖标定物在相机视野中要分布在不同的位置和深度记录位姿时同一姿态不要重复采集重复数据不会带来新的信息量5.2 如何快速判断一组标定数据是否合格标定完成后先别急着求 X先用数据本身做个预检。我的做法是计算相邻位姿之间的旋转轴方向和旋转角度。用一个简单脚本就能完成将每个 A_i 和每个 B_i 都拆成旋转矩阵 R 和平移向量 t计算相邻两个姿态之间的旋转角度看分布是否均匀。如果所有角度都集中在某一个小范围直接重采。此外还有一个判断技巧把 X 求出来之后用任意一组 A 和 B 验证 AX 是否等于 XB。通常在矩阵范数意义上误差小于 1e-6 才说明求解本身是稳定的。如果在验证时误差很大大概率是数据集中有异常值。这时候要么重采这一组数据要么通过 RANSAC 框架剔除异常位姿。我在自己的工具链里实现了简单的 RANSAC 手眼标定随机采样 5 组数据求解 X计算所有数据的残差保留残差最小的一组。5.3 2D和3D混合场景下的标定板选择有些项目比较特殊同一套系统里既有2D相机做定位又有3D相机做测量。比如视觉引导的锁螺丝工作站2D相机负责粗定位3D相机负责高度测量。这种情况下我建议分别做标定不要把2D和3D混在一起求解。混合标定不是不可以但会引入额外的对齐误差。2D相机有畸变和视角偏差3D相机有深度噪声和点云配准误差两者性质完全不同。混合在一起后误差会互相传递最后找不到问题出在哪个环节。实际操作中我给2D和3D相机各自设计一套标定流程各自求一个手眼矩阵。在应用层再做一个相机间坐标变换的标定通过一个共同的标定板或者特征点把2D相机和3D相机的坐标系关联起来。6. 标定结果验证不验证的手眼标定等于白做6.1 针尖验证法是最可靠的精度测试手段标定完成后验证环节是绝对不能省的。我最常用的验证方法是针尖验证法在机械臂末端装一根针尖针尖位置已知通过标定出的手眼矩阵让视觉系统引导机械臂去触碰空间中的一个固定点。具体操作流程在相机视野内放置一个固定尖点比如一个锥形块用相机识别该尖点在相机坐标系下的坐标利用标定出的手眼矩阵将相机坐标转换为机械臂基座坐标控制机械臂末端针尖移动到该坐标点测量针尖与固定尖点的实际偏差这个偏差就是整个视觉引导系统的综合精度包含了手眼标定误差、相机标定误差、机械臂绝对定位误差。对于2D系统偏差在 1-2mm 以内可以接受对于3D系统通常要求偏差在 0.5-1mm 以内。6.2 用多组独立测试点做统计评估单点验证不够至少要在视野内不同位置、不同高度选取 5-10 个测试点分别做触碰验证统计平均误差和最大误差。我在项目里会刻意选择靠近视野边缘、远离标定采集区域的测试点。因为机械臂和相机的性能在视野中心通常最好边缘才是真正的短板。如果边缘测试点误差明显偏大说明标定数据覆盖范围不足需要补充边缘区域的采集位姿重新标定。还需要注意验证时机械臂的姿态尽量模拟真实工作时的姿态。有些项目机械臂在抓取时末端姿态变化很大如果只在一个姿态下验证通过换个姿态可能就不行了。因为机械臂在不同姿态下的绝对定位精度不同手眼矩阵只是坐标系变换不能补偿机械臂自身定位误差。6.3 验证时区分机械臂误差和标定误差这一点非常重要。现场经常出现一种情况标定结果验证时误差很大但视觉系统自身的特征检测精度很高这说明问题可能出在机械臂而非标定。区分方法很简单让机械臂在同一个位姿下重复运动测量其重复定位精度。如果重复定位精度本身就有 0.5mm那么标定精度再好系统综合精度也不可能超过这个值。如果机械臂重复定位精度很好但视觉引导误差很大那才需要回头检查标定流程。还有一个容易忽略的问题机械臂在负载不同的情况下末端实际位置会有微弱变化。标定时机械臂末端带的是标定板工作时空载或带了夹具重力变形会导致末端偏移几十丝到几毫米。这种误差不是标定能解决的需要在机械臂侧做负载补偿。7. 现场实施中的工具链搭建和资源规划7.1 标定软件的架构设计思路手眼标定虽然可以借助 OpenCV 等现成库完成核心求解但完整的工作流涉及数据采集、位姿记录、文件解析、可视化验证等多个环节。我在实际项目里会写一个小工具链完成以下功能从相机SDK获取图像/点云支持离线文件回放从机械臂控制器读取当前位姿或从日志文件解析位姿数据自动检测标定板/标定球计算 B 矩阵完成 AXXB 求解输出手眼矩阵自动计算重投影误差和验证结果这个工具链用 Python 写好处是生态丰富OpenCV、Open3D、numpy 都能直接用适合快速验证算法缺点是性能一般但标定本身就是离线过程对实时性没有要求。7.2 相机SDK和机械臂通信的常见坑现场实施时相机SDK和机械臂通信往往是问题最多的环节。我遇到过的典型问题包括首先是相机SDK接口不统一。不同厂商的SDK获取点云的方式不同有的是直接返回点云数组有的是返回深度图和相机内参需要自己做换算。比如某些国产3D相机SDK返回的是 16bit 深度图单位是毫米但有些是0.1mm搞错单位的话标定结果会整体偏移。其次是时间同步问题。相机采集图像和机械臂记录位姿必须尽量同步。如果两者存在较大的时间差机械臂在运动中时图像对应的实际末端位姿和记录值就会有偏差。我的做法是让机械臂在每个位姿停下来等相机采集完成后再运动到下一个位姿从根本上避免时间同步问题。最后是坐标系约定的问题。不同机械臂厂商对末端坐标系的原点和轴向定义不同有的在法兰盘中心有的在法兰盘端面有的Z轴朝外有的Z轴朝内。拿到机械臂位姿后一定要和机械臂手册核对确认坐标系定义否则标定结果会包含一个固定的旋转偏移。7.3 标定周期的规划建议手眼标定不是一次性工作。现场设备经过运输、安装、碰撞后相机和机械臂的相对位置可能会发生微小变化导致标定结果失效。我的建议是首次安装时做一次完整标定之后每隔三个月做一次复核。复核时不需要重新采集全部数据用之前保留的几组典型位姿重新计算一遍偏差超过阈值才需要重新标定。如果项目中有多台相同的设备标定程序最好做成参数化配置换设备时只需要修改相机参数和机械臂参数不需要改代码。这能大幅减少实施阶段的调试时间。我在几个批量项目中就是这么做的单台设备的标定时间从最初的4小时压缩到了40分钟以内。7.4 2D/3D相机选型时对标定精度的影响最后聊一下相机选型对标定的影响。很多人只关注分辨率、帧率、视野忽略了标定相关的参数。我给几个实际建议2D相机方面分辨率不是越高越好关键是镜头畸变要小。畸变大的镜头虽然可以通过标定校正但校正后的残余误差在图像边缘仍然明显。选镜头时尽量选低畸变工业镜头标定信息完整不要用监控级或消费级镜头。3D相机方面注意深度精度和点云密度。深度精度直接决定了球心拟合的精度点云密度太低的话球面上的点数太少拟合结果不稳定。在我的经验里Z方向精度在 0.1mm 级别的3D相机标定后系统综合精度可以到 0.5-1mm如果Z方向精度是毫米级标定精度就很难低于毫米级。另外3D相机的视野和测量距离也需要匹配。有些相机在近距离精度高但视野小远距离视野大但精度差标定时的工作距离应该和实际使用距离保持一致。如果标定距离和使用距离差太多由于镜头畸变和深度误差的非线性标定结果在目标距离上会失效。