ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

相机标定全链路:内参、畸变、重投影误差与实测验证

相机标定全链路:内参、畸变、重投影误差与实测验证

调相机标定这件事,我最早是抱着"跑个函数就完事"的心态去的。十几张棋盘格照片喂进去,重投影误差 0.08 像素,看起来漂亮得不行。结果把标定板挪到两米外一测,测出来的距离比卷尺量出来的少了 15 毫米。那次之后我才明白,相机标定(camera calibration)不是一个"调用 API 拿参数"的动作,而是一条从物理世界到像素坐标的可信链路,链路上任何一环松了,最后那个重投影误差都只是自欺欺人的数字。这篇内容想讲清楚的就是这条链路:内参和畸变系数到底在描述什么、采集环节哪些细节决定结果上限、参数拿到手之后怎么验证它真的能用、以及为什么重投影误差很小但实际测量还是不准。适合刚接触视觉测量和机器人定位的开发者,也适合已经用过几次标定函数、但对结果始终不太放心的朋友。

1. 相机标定真正要解决的三个映射问题

1.1 从三维世界到像素的那条链路

很多人把标定理解成"求一个矩阵",这个理解偏了。标定本质上是在建立一套坐标变换关系:世界坐标系里的一个点 (X, Y, Z),先经过外参(旋转 R 和平移 t)变到相机坐标系,再经过内参矩阵投影到归一化平面,最后加上畸变修正落到像素坐标 (u, v)。这条链路上,外参描述的是"相机装在哪里、朝向如何",内参描述的是"这台相机的光学和传感器本身长什么样"。

区分这两者的意义在于:外参是会变的,相机挪个位置就失效;内参在镜头、焦距、分辨率、对焦状态不变的前提下是稳定的,标一次可以用很久。我在项目里见过不少人每次开机都重新标定,理由是"怕不准",结果反而引入了采集随机性带来的抖动。正确的做法是内参离线标定、稳定存档,外参用标定板或已知靶标在线求解,两者分开管理。

还有一个容易被忽略的点:标定得到的参数永远是针对某一个特定成像配置的。同一台相机,换镜头、改分辨率、切 ROI、开 binning、动对焦环,这四件事里任意一件发生,内参就必须重新标定或者做等效换算。我把这条写在团队文档的第一行,因为它是后续所有"为什么测不准"问题的源头。

1.2 内参矩阵里 fx、fy、cx、cy 各管什么

内参矩阵长这样:

K = [[fx, 0, cx], [ 0, fy, cy], [ 0, 0, 1]]

fx和fy是把物理焦距折算到像素尺度后的结果,量纲是像素。折算方式很朴素:fx = f / dx,其中 f 是镜头焦距(毫米),dx 是传感器单个像元的物理尺寸(毫米)。举个例子,8 mm 焦距配 3.45 μm 像元,fx = 8 / 0.00345 ≈ 2319像素。这也是为什么同样焦距的镜头装在不同相机上,fx 差别会很大——像元尺寸不一样。正常情况下 fx 和 fy 应该非常接近,比值偏离 1 超过 1% 就要怀疑是不是像元不是正方形,或者标定过程有问题。

cx和cy是主点,也就是光轴与像平面的交点,理想情况下在图像正中心,实际会偏几十个像素,这属于正常装配公差。主点的精度对普通成像影响不大,但对单目测距和三维重建影响相当直接——主点偏 20 像素,在远距离上换算成物理偏差可能就是厘米级。

有个实操细节值得说:如果你后续要换分辨率使用,内参是可以换算的,不必重标。整幅图缩放 k 倍(比如从 2448×2048 降到 1224×1024,k = 0.5),则fx' = k·fx、fy' = k·fy、cx' = k·(cx + 0.5) - 0.5、cy' = k·(cy + 0.5) - 0.5。那个 ±0.5 是像素中心约定带来的,漏掉它在大分辨率下会带来接近一个像素的系统偏差。如果只是裁剪 ROI,则是cx' = cx - x0、cy' = cy - y0,fx、fy 完全不变。

1.3 畸变模型:k1 k2 p1 p2 该不该全放开

畸变系数是标定里最容易"过度配置"的地方。OpenCV 的calibrateCamera默认返回 5 个系数 (k1, k2, p1, p2, k3),也支持 8 个、12 个、14 个的扩展模型。系数越多,模型对训练数据的拟合能力越强,但泛化能力可能反而下降——这是典型的过拟合。

径向畸变 k1、k2、k3 描述的是"越靠画面边缘,直线越弯"的现象,广角镜头尤其明显。切向畸变 p1、p2 来自镜头与传感器平面不严格平行,正常情况下数值应该很小,量级在 1e-4 到 1e-3。如果标出来 p1、p2 明显偏大,先别急着用,去检查镜头是不是没拧紧、传感器是不是歪了——这是装配问题的信号,不是靠标定能"修"好的。

我的经验做法是:

  • 普通工业镜头、视场角小于 60 度,用默认 5 参数足够;
  • 广角、短焦、有明显桶形畸变,先试 5 参数,看边缘区域残差是否偏大,再考虑打开 k3 或用 rational 模型;
  • 只有在鱼眼、超大广角场景下才值得上 8 参数以上的复杂模型,而且必须用足够多的边缘样本支撑。

注意:打开高阶畸变项之后,务必用未参与标定的独立图片做验证。训练集上的重投影误差下降不代表模型变好了,很可能只是多出来的自由度把噪声也拟合进去了。

2. 采集环节就决定了结果上限:标定板与拍摄姿态

2.1 棋盘格、圆点阵列板与编码板的取舍

算法再精细,也救不回一组质量糟糕的采集数据。标定板的选择是第一道分水岭,我按实际使用体验整理了一下:

标定板类型优点短板适用场景
棋盘格角点定位精度高,工具链最成熟对模糊、过曝敏感,大畸变下检测易失败常规镜头、实验室标定
圆点阵列板抗模糊、抗噪声能力强,检测鲁棒存在透视偏心误差,需专门处理工业现场、光照不稳定环境
非对称圆点板可自动确定方向,无需人工确认板面制作精度要求高自动化产线
编码标志板支持单张图求解,适合大视场制作成本高,需要专门算法大尺寸、多相机系统

棋盘格的角点是两条边缘的交点,数学定义清晰,亚像素细化之后精度可以做到 0.02 像素级别,这是它的核心优势。但它的短板也很致命:图像一模糊,角点检测就开始漂。圆点板用的是重心或椭圆拟合,对模糊的容忍度高得多,代价是"圆心在图像上的投影"并不等于"圆心的投影"——这个透视偏心误差在标定板倾斜角度大时会达到零点几像素,必须用专门的聚类检测模式来抑制。

我现在的默认选择是:实验室环境用棋盘格,现场环境用圆点板。如果标定板要做得比较大(比如 1 米以上),优先考虑编码板或者拼接方案,因为大尺寸的平整度很难保证。

2.2 姿态覆盖比照片张数更重要

新手最常见的误区是"拍 50 张总比拍 20 张准"。实际上 50 张姿态雷同的图,效果远不如 15 张覆盖充分的图。原因在于标定的求解过程本质上是在约束一个超定方程组,每个姿态提供的是不同方向的约束,姿态单一意味着某些参数方向上根本没有信息。

采集时我会刻意保证这几件事:

  • 倾斜角度覆盖:至少有一半的图,标定板与像平面夹角在 30 度到 45 度之间。完全正对拍摄的图对内参约束很弱,尤其是焦距。
  • 位置覆盖:标定板要出现在画面的四个角、四条边、中心,不能只在中间晃。畸变参数的估计完全依赖边缘区域的样本,中间拍一百张也约束不了 k1。
  • 尺度覆盖:既有占满画面 80% 的近景,也有占 20% 的远景,帮助解耦焦距和主点。
  • 姿态多样性:绕三个轴都要有旋转,不要只在一个平面内平移。

数量上,15 到 25 张是一个比较稳妥的区间。少于 10 张,参数估计的方差会明显变大;多于 40 张,边际收益迅速递减,而且采集时间拉长反而容易引入手抖、光照变化等干扰。

2.3 现场最容易忽略的几个采集细节

有几个细节,文档里基本不写,但每一个都能让标定结果偏掉:

标定板打印后的实际尺寸必须量。打印或曝光制版时,缩放误差是普遍存在的,标称 25 mm 的方格实际可能是 24.7 mm。如果你直接把 25 写进代码,标定出来的 fx、fy 就会整体偏大约 1.2%,最后所有测距结果都系统性偏小。正确做法是用卡尺量十个格子的总长度再除以十,把这个实际值写进objectPoints。

标定板必须足够平。A4 纸打印出来贴在硬纸板上,稍微有点翘曲,平面假设就不成立了。我用过一个土办法检验:把标定板贴到玻璃上,从侧面看有没有透光缝隙。有条件的话用亚克力或者铝基板,平整度能控制在 0.05 mm 以内。

关闭自动曝光、自动增益、自动白平衡。这些功能会让每一帧的成像特性发生微小变化,等于在给标定引入额外的噪声源。

锁定对焦。自动对焦在拍摄过程中反复动作,焦距会变,内参直接失效。手动对焦到工作距离上,然后用胶带把对焦环固定住——这招听着糙,现场非常管用。

避免运动模糊。手持拍摄时快门速度不够,角点会被拉成一条短线,检测出来的位置是模糊区域的某种加权中心,偏差可能超过 0.5 像素。用固定支架或者提高快门速度。

3. 把标定跑通:代码骨架、参数配置与结果解读

3.1 一份可直接复用的标定脚本

下面这段是基于 OpenCV 的最小可用流程,我把几个关键参数的取值和理由都标了出来:

import cv2 import numpy as np import glob # 棋盘格内角点数量(列, 行),注意是内角点,不是格子数 PATTERN = (9, 6) # 实测的单格边长,单位与后续测量保持一致,这里用毫米 SQUARE_MM = 24.72 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) objp = np.zeros((PATTERN[0] * PATTERN[1], 3), np.float32) objp[:, :2] = np.mgrid[0:PATTERN[0], 0:PATTERN[1]].T.reshape(-1, 2) * SQUARE_MM obj_points, img_points = [], [] files = sorted(glob.glob("images/*.png")) for f in files: img = cv2.imread(f, cv2.IMREAD_GRAYSCALE) ok, corners = cv2.findChessboardCorners( img, PATTERN, flags=cv2.CALIB_CB_ADAPTIVE_THRESH | cv2.CALIB_CB_NORMALIZE_IMAGE ) if not ok: print("detect failed:", f) continue # 亚像素细化窗口 11x11 是经验值,太小收敛不稳,太大容易受邻域干扰 corners = cv2.cornerSubPix(img, corners, (11, 11), (-1, -1), criteria) obj_points.append(objp) img_points.append(corners) h, w = img.shape[:2] rms, K, dist, rvecs, tvecs = cv2.calibrateCamera( obj_points, img_points, (w, h), None, None, flags=cv2.CALIB_FIX_K3, # 先固定 k3,数据不足时避免过拟合 criteria=criteria ) print("RMS reprojection error:", rms) print("K =\n", K) print("dist =", dist.ravel())

几个参数的取舍理由:CALIB_FIX_K3在样本数量不够、边缘覆盖不足时很有必要,它能把高阶项的抖动压住;cornerSubPix的窗口设成 11×11 是平衡了收敛速度和稳健性的经验值,如果图像噪声大可以放大到 15×15,但迭代次数要相应增加。

如果要保存结果供生产环境使用,建议同时存下 K、dist、图像尺寸、标定日期和标定板实际尺寸这几个字段。少存任何一项,半年后回来看这堆参数就是天书。

3.2 重投影误差这个数字到底怎么读

calibrateCamera返回的 rms 是所有图片、所有角点的重投影误差均方根,单位是像素。这个数字的解读需要分层:

RMS 范围含义建议
< 0.1 px拟合非常好警惕过拟合,必须做独立验证
0.1 ~ 0.3 px正常水平大多数测量应用可用
0.3 ~ 0.5 px偏大检查采集质量,看误差分布
> 0.5 px明显异常不要使用,回到采集环节排查

关键点在于:不要只看总数,要看分布。我习惯把每张图、每个角点的误差都算出来,然后画两张图——一张按图片编号,一张按图像位置。如果误差集中出现在某几张图上,说明那几张采集有问题(模糊、过曝、姿态极端);如果误差集中在画面边缘,说明畸变模型不合适,需要放开 k3 或者换模型;如果误差在画面里呈现明显的方向性梯度,那多半是标定板不平或者主点估计偏了。

还有一个反直觉的结论:RMS 太小反而要警惕。理论上限是角点检测的亚像素精度,一般在 0.05~0.1 像素量级。如果你标出来 0.01 像素,那基本可以确定是过拟合——模型自由度太多,把噪声也吃进去了。这种情况下拿去测实际物体,误差会大得让你怀疑人生。

3.3 标定完必须做的三项验证

参数拿到手,别急着上线,先做三件事:

第一,留出验证集。从采集的图片里随机抽出 3 到 5 张不参与标定,用标定结果计算这几张图的重投影误差。如果验证集误差是训练集的 3 倍以上,说明泛化能力不行,模型或者数据有问题。这一步几乎零成本,但我见过太多人跳过。

第二,畸变校正后的直线检测。找一个有明显直线的场景(比如实验室的墙角、网格板),拍一张,用undistort校正后检查直线是否笔直。可以用霍夫直线拟合,看同一条直线的点偏离拟合线的距离是否小于 0.5 像素。这个检验直观、快速,而且直接对应"畸变参数对不对"这个核心问题。

第三,物理尺寸实测。这是最有说服力的一步。用标定后的内参和已知的外参,去测一个已知尺寸的物体(比如一块量块、一段标准间距),对比测量值和真实值。我一般会测三个位置:近端、中段、远端,如果三个位置的相对误差都在 0.5% 以内,这套参数才算能用。如果近端准、远端偏,问题多半在焦距;如果整体偏一个固定比例,问题在标定板尺寸或者单位。

# 用校正后的图像验证直线度 undist = cv2.undistort(img, K, dist, None, newK) # 再配合 cv2.HoughLinesP 或 cv2.fitLine 统计偏离量

4. 误差很小但测距不准:一条完整的排查链路

4.1 先判断是内参偏还是使用方式偏

这是我遇到最多的一类问题:标定 RMS 明明 0.1 像素,做测量却差出去好几毫米。排查的第一步不是怀疑标定,而是把使用链路拆开。整个链路是"像素坐标 → 去畸变 → 归一化坐标 → 乘深度 → 世界坐标",任何一步的处理方式和标定的假设不一致,结果就错。

我按顺序查这几件事:一是图像是否做了和标定时一致的预处理,有些人标定用原始图,使用的时候先做了裁剪或者缩放,那内参当然不对;二是去畸变的调用方式,undistort和initUndistortRectifyMap + remap在边界处理和插值上有细微差别,混合使用会引入亚像素偏差;三是外参的坐标系定义,OpenCV 的相机坐标系是 Z 轴向前、X 向右、Y 向下,和很多机器人坐标系的约定不同,符号搞反了会出现"左右颠倒"或"上下颠倒"的诡异现象。

一个具体的排查手段:把标定板放在工作距离上,用solvePnP求出它的位姿,然后计算标定板上两个已知间距的角点在三维空间里的距离,和真实值对比。这一步能直接告诉你误差是来自内参还是来自外参。

4.2 标定板本身的物理误差

如果上面那步就发现有偏差,八成是标定板的问题。我遇到过三种情况:

第一种是打印缩放,前面提过,标称值和实际值差 1%~2%,导致所有结果的尺度整体偏移。这种误差的特点是"比例性"——测什么都按同一个比例偏,很容易识别,也很容易修正:把实际尺寸量准,重新标定。

第二种是板面不平。亚克力板在温度和应力作用下会翘曲,尤其是大面积板。翘曲导致的误差不是比例性的,而是"位置相关"的,标定板上某些区域的点会系统性偏离平面,重投影误差在这些点上会略高,但整体 RMS 可能被稀释得不明显。判断方法很简单:单独看每个角点的残差,如果残差在板面上呈现明显的平滑梯度,就是不平。

第三种是图案精度。喷墨打印的边缘会有毛刺,激光打标会有热影响区,这些都会让角点的"真实位置"和"理论位置"产生零点几毫米的偏差。标定板越小、格子越密,这个问题越突出。

4.3 角点检测的亚像素偏差与偏心误差

即使板子完美、图像清晰,角点检测本身也有系统偏差。棋盘格的角点在理想模型里是一个数学点,但在实际图像里,由于镜头的光学传递函数、传感器的采样、图像的插值,角点附近会形成一个宽度约 2 到 3 像素的过渡带。cornerSubPix是在这个过渡带上做迭代优化,收敛到的是"灰度对称中心",不完全等于几何交点。

这个偏差通常在 0.02 到 0.1 像素,看起来很小,但在大视场、长工作距离的场景下会被放大。举个例子:fx = 2000 像素,工作距离 2 米,0.1 像素的角点偏差对应的横向误差是 0.1 × 2000 / 2000 = 0.1 毫米。单点误差不大,但如果偏差在整幅图上有一致性(比如总是偏向同一侧),累积起来就是系统误差。

圆点板的偏心误差更明显。一个圆在透视投影下变成椭圆,椭圆的几何中心不等于圆心投影的位置,偏差量在标定板倾斜 40 度时可以达到 0.3 像素以上。解决办法是用CALIB_CB_CLUSTERING标志,让算法改用基于轮廓聚类的方式定位,而不是简单拟合椭圆中心。

5. 特殊成像条件下的分支:广角、双目与手眼

5.1 大畸变镜头的模型选择与标定策略

视场角超过 100 度的镜头,用常规的 5 参数模型基本压不住。这时候有两条路:一是 OpenCV 的 rational 模型(打开CALIB_RATIONAL_MODEL,用 8 参数),二是鱼眼模型(cv2.fisheye模块)。

rational 模型适合畸变剧烈但仍属于"径向畸变主导"的镜头,模型是多项式的有理分式,拟合能力强,代价是需要更多的边缘样本。鱼眼模型则是专门为等距投影、等立体角投影这类成像方式设计的,它不用全局多项式而用角度映射,对超广角的表现更稳。

选型的判断依据我一般用一条:把校正后的图像拿来看边缘。如果边缘的直线明显还弯,或者画面四角被拉伸得不成样子,说明模型不够或者标定样本边缘覆盖不足。这时候与其堆参数,不如先补采集——在画面四角各拍几张倾斜的标定板,往往比换模型更有效。

鱼眼标定的调用方式和常规不同,参数是分开的:

K = np.zeros((3, 3)) D = np.zeros((4, 1)) rms, K, D, rvecs, tvecs = cv2.fisheye.calibrate( obj_points, img_points, (w, h), K, D, flags=cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC | cv2.fisheye.CALIB_FIX_SKEW, criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-6) )

注意鱼眼模块要求输入点集的形状是 (1, N, 3) 和 (1, N, 2),和常规标定的 (N, 3) 不同,这个细节坑过不少人。

5.2 双目标定多出来的那部分约束

双目系统的标定不只是把两个相机分别标一遍。分别标定只能得到各自的内参,还需要stereoCalibrate来求解两个相机之间的旋转和平移,也就是基线。这个基线的精度直接决定深度精度,影响关系大致是:深度误差 ≈ Z² / (f · B) · 视差误差。基线 B 越大,同样视差误差下的深度误差越小;工作距离 Z 越远,误差按平方增长。

一个常见的错误做法是:先用stereoCalibrate联合优化,然后把结果里的内参单独拿出来用。这样做的问题是联合优化时内参和基线是耦合优化的,如果某个相机的图像质量差,会拖累整体。我的建议是:先分别标定两个相机的内参并固定(用CALIB_FIX_INTRINSIC),再单独优化外参。这样内参的物理意义清晰,出问题也好定位。

采集方面,双目标定的同步性要求很高。两个相机如果不是硬件同步,运动中的标定板会在两幅图里处于不同位置,联合优化时会被当成"外参不一致",直接把基线算歪。静态拍摄可以规避这个问题,但如果现场必须动态采集,同步触发是硬要求。

5.3 手眼标定的两种构型与采集要求

手眼标定解决的是"相机和机械臂之间的位姿关系",本质是求解 AX = XB 这个方程。它分两种构型:eye-in-hand,相机装在机械臂末端,跟着动;eye-to-hand,相机固定在外部,看着机械臂动。前者的 X 是末端到相机的变换,后者是基座到相机的变换,方程形式略有不同,cv2.calibrateHandEye通过参数区分。

采集的核心要求是运动要有足够的旋转多样性。如果机械臂只在平面内平移,或者所有运动的旋转轴都是同一个方向,方程会退化,解出来的结果在某个方向上完全没有约束。我一般要求至少 15 组位姿,且绕至少两个不同方向的轴都有明显旋转,单次旋转角度在 20 度以上。

还有一个容易忽略的点:标定板在末端上的安装必须刚性。用胶带、用夹子,稍微有点松动,标定出来的残差就会忽大忽小。我吃过这个亏——标定板用双面胶粘在末端法兰上,采集到一半翘起来一点,结果整组数据作废,重新来了一遍。

6. 项目现场积累的几条经验

6.1 分辨率、ROI 与 binning 变化后的内参换算

生产环境里经常出现这种情况:标定的时候用全分辨率,实际运行时为了帧率切到 ROI 或者开了 binning。这时候不是重标一遍,而是做等效换算。ROI 裁剪的换算最简单,主点平移即可:

def adjust_intrinsics_roi(K, x0, y0): K2 = K.copy() K2[0, 2] -= x0 K2[1, 2] -= y0 return K2 def adjust_intrinsics_scale(K, scale): K2 = K.copy() K2[0, 0] *= scale K2[1, 1] *= scale K2[0, 2] = scale * (K[0, 2] + 0.5) - 0.5 K2[1, 2] = scale * (K[1, 2] + 0.5) - 0.5 return K2

换算之后一定要验证。方法很简单:用换算后的参数去undistort一张 ROI 图,看直线还直不直,看主点是不是还在图像的合理位置。我用过一次 binning 2×2 的换算,忘了那个 0.5 的偏移,结果主点偏了半个像素,在 5 米工作距离上表现为 2 毫米的系统偏差,查了大半天。

注意:换算只对"同一光学配置下的数字变化"成立。如果换镜头、动对焦、改光圈,必须重新标定,没有捷径。

6.2 对焦、变焦和温度带来的参数漂移

内参不是永恒不变的。最直接的影响来自对焦——对焦环一动,镜头的等效焦距和主点都会变。有研究数据显示,普通工业镜头在对焦行程上走一圈,fx 的变化可以达到 1%~3%。这个量级在精密测量里是致命的。

变焦镜头更不用说,每一个焦段都是一套独立的内参。如果项目里必须用变焦,我的做法是按常用焦段分段标定,做成一个查找表,用的时候根据当前焦距索引。

温度的影响更隐蔽。镜头筒、镜片、传感器封装的热胀冷缩会导致焦距和后截距变化,典型量级是每摄氏度几十个 ppm。这意味着在 20℃ 标定的参数,拿到 45℃ 的车间里用,可能会有 0.1% 左右的偏差。对于要求高的场景,要么做温度补偿(在不同温度点标定,插值查表),要么在设备内部维持恒温。

一个实用的自检手段:在设备上固定一个参考靶标,每次开机拍一张,用当前内参反算靶标上已知点的间距,和标准值对比。偏差超过阈值就触发重新标定提醒。这套机制成本很低,但能挡住绝大多数"参数悄悄漂了但没人发现"的事故。

6.3 一套可维护的标定记录习惯

最后说说工程化管理。标定参数这种东西,最怕的是"当时标了、当时能用、半年后没人知道这堆数字是怎么来的"。我现在强制要求每条标定记录包含这些字段:

字段内容作用
设备编号相机与镜头的唯一标识追溯硬件配置
分辨率与 ROI标定时的实际成像尺寸判断参数是否可直接用
标定板规格图案类型、角点数、实测格距复现标定过程
图像数量与位姿分布张数、倾斜角范围评估参数可信度
RMS 与验证集误差两组数字判断是否过拟合
环境条件温度、对焦位置评估漂移风险
标定日期与操作人时间戳建立维护周期

这套表格看起来繁琐,但它救过我一次——某批设备的测量结果集体偏了 0.8%,查了一周才发现是其中一个批次的镜头供应商换了镀膜,焦距有微小差异,而标定参数还是按老配置下发的。有了记录表,一比对就定位到了问题批次。

说到底,相机标定这件事的门槛不在算法,算法都是现成的;门槛在于对物理世界的敬畏——你得相信镜头会热胀冷缩、标定板会翘、角点检测会有偏差,然后在这些"不完美"的缝隙里,用一次次验证把结果钉在可信的范围内。我现在的习惯是,任何一套标定参数上线前,必须过一遍物理尺寸实测那一关,哪怕 RMS 再漂亮。因为漂亮的重投影误差只说明模型拟合得好,不说明它描述的这台相机真的长成那样。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进