1. 先把“三角测量”这四个字拆开看:它到底在量什么
1.1 隔河量一棵树:最土但最直白的入门场景
假设你站在河边,对岸有一棵树,河太宽、水太急,卷尺甩不过去,你手上只有一把皮尺和一台能测角的仪器。这时候三角测量就派上用场了,而且整个过程不需要任何高深数学。
第一步,在你这一侧的地面上选两个点,一个叫 A,一个叫 B,A 到 B 的距离用皮尺直接量出来,比如 50 米。这条已知长度的边,在整个三角测量体系里有个专门的名字叫基线,它是所有计算的立足点,后面所有的距离都靠它“生”出来。
第二步,把仪器架在 A 点,瞄准对岸那棵树,测出基线与视线的夹角,记作 α;再搬到 B 点,同样测一次夹角,记作 β。到这里,一个三角形就已经确定了:一条边长已知,两个角已知。
第三步,剩下的完全交给初中几何。三角形内角和 180°,第三个角 γ = 180° − α − β。然后套正弦定理:AC / sinβ = AB / sinγ,于是 AC = AB × sinβ / sin(α+β)。树到你 A 点的距离就出来了,河再宽也没关系。
这个流程之所以成立,靠的是平面几何里的“角边角”全等判定:一个三角形只要确定一条边和它两端的角,形状和大小就唯一锁死了,其他所有边长、所有角度都能反算出来。三角测量听起来像某种高深的现代技术,本质上就是这条初中定理的工程化应用。
1.2 只有角度不够:为什么“基线”是整个体系的命门
很多人第一次接触三角测量会有个误区,觉得只要能精准测角就够了,边长随便定。这个想法一旦带到工程里就会出大问题。
你可以做个思想实验:如果只知道三个角,不知道任何一条边,那么这个三角形可以任意放大缩小,形状完全一样,但大小可以是一米,也可以是一公里。几何上这叫相似而不全等。也就是说,纯角度观测只能得到一个“形状”,不能得到“尺寸”。
这条约束在技术领域里随处可见。单目相机为什么测不出绝对深度?因为它本质上只观测角度信息,图像的每一个像素对应一条射线,所有射线交于同一个光心,整个场景可以任意缩放而不改变成像结果,这就是所谓的尺度不确定性。双目相机为什么就能测深度?因为左右两个镜头之间存在一条物理上已知的、固定不变的基线,这条基线把尺度“钉”死了。激光雷达、结构光这些方案,本质上也是用别的手段提供了一条等效的已知尺度。
所以看任何一个测距系统,第一件事就是找它的基线在哪。找不到基线的系统,输出的必然是相对量,用之前必须想办法把它锚定到一个已知尺度上,否则就是空中楼阁。
1.3 一条必须背下来的误差公式:距离越远,错得越快
三角测量最容易翻车的地方,不是算错,而是误差被几何关系放大。这里有一条从业者必须刻在脑子里的关系式,我推导一遍,你看完就忘不掉。
假设基线长 b,目标距离 d,两者构成的视差角 θ 大约满足 θ ≈ b/d(小角度近似)。对这个式子做微分,可以推出距离误差和角度误差的关系:
Δd ≈ d × Δθ / θ ≈ d² × Δθ / b
这个式子非常关键,它告诉你三件事:
- 误差随距离平方增长。距离翻一倍,误差涨四倍。这就是为什么所有测距手段都有个“有效距离”上限,超出之后精度是断崖式下跌。
- 误差与基线长度成反比。基线加长一倍,误差减半,这是最有效但也最贵的提升手段。
- 误差与测角分辨率成正比。角度测得越准,距离越准,但测角精度的提升通常受限于硬件物理极限,边际收益递减。
举两个真实量级的例子对比一下,感受会更直观:
| 场景 | 基线 b | 距离 d | 测角分辨率 Δθ | 距离误差 Δd |
|---|---|---|---|---|
| 野外工程测距(全站仪级) | 100 m | 1000 m | 2 角秒 ≈ 9.7e-6 rad | 约 10 cm |
| 双目相机(短基线) | 0.12 m | 10 m | 1 像素 ≈ 1.25e-3 rad | 约 1.0 m |
| 双目相机(短基线) | 0.12 m | 30 m | 1 像素 ≈ 1.25e-3 rad | 约 9.4 m |
最后一行不是笔误。一台常见的双目相机放到 30 米外的目标上,深度误差已经接近 10 米,基本等于“知道前面有东西,但不知道多远”。这也是为什么车载感知系统要么把双目基线做得尽量宽,要么在中远距离直接换用别的传感器。
1.4 交会角:决定“图形强度”的隐藏参数
同样是两条视线交会,交会角不同,精度差得很远。工程上把这种与几何布置相关的精度优劣叫做图形强度。
道理不难理解:如果两条视线几乎是平行的(交会角接近 0°),那这个交会点对角度误差极其敏感,一点点角度抖动就会让交点沿视线方向跑很远。反过来,如果两条视线接近垂直(交会角接近 90°),交会点就非常“稳”,误差被压到最小。
业内的经验区间是:交会角尽量控制在30° 到 120°之间,理想值在90° 左右。低于 30° 基本可以认为这次观测没有价值,数据处理时应该直接剔除或者重新布置测站。
这条约束在实际作业里经常被忽略。我见过有人为了省事,测站布得离得很近,觉得“反正两个点都能看到目标就行”,结果交会角只有十几度,数据回头一算,误差大得离谱,还得重测一遍。
2. 从纸面走到现场:测角工具怎么选、基线怎么布
2.1 三代测角工具的性能阶梯
测角设备的精度直接决定了整套方案的上限,选错了设备,后面的算法再精巧都是白搭。我在实际项目里用过的工具,基本可以分成三个梯队:
| 工具类型 | 典型测角精度 | 有效作业距离 | 使用门槛 | 典型用途 |
|---|---|---|---|---|
| 光学经纬仪 | 2 秒~6 秒 | 数百米至数公里 | 中等,需要调平、读数 | 传统控制测量、施工放样 |
| 全站仪 | 1 秒~5 秒(测角) | 数百米至数公里 | 中等,但功能多、操作流程长 | 地形测量、工程放样、变形监测 |
| 手机传感器(磁力计+陀螺仪) | 0.5°~2°(约 1800~7200 秒) | 数十米以内 | 极低 | AR 测距、粗略估算、科普演示 |
差距有多大?经纬仪和手机的测角精度差了三个数量级左右。把手机那套传感器放进刚才的误差公式里,1 米外的误差可能就有几厘米到几十厘米,超过 10 米基本就不能用来做正经测量了。所以手机上的“AR 测距”功能,我的建议是只用来估计家具尺寸、目测一下房间大概多长,别拿去干正经活。
全站仪相比经纬仪的关键升级,是加上了光电测距模块,能直接测出仪器到目标点的斜距。这带来的变化是根本性的:一旦能测距,就不再需要依赖那条基线去推算距离了,整个测量模式从“测角交会”变成了“边角网”,作业效率和可靠性都上了一个台阶。当然,全站仪测距本身也有误差来源,比如气象改正(温度、气压对光速的影响)、棱镜常数、加常数乘数改正,这些在正式作业里都得输入。
2.2 基线布设:不是越长越好,也不是越短越省事
新手最容易犯的错是走向两个极端:要么基线随便定,要么觉得越长越好。实际布设要综合考虑几个互相拉扯的因素。
基线加长,好处是同样的测角误差下距离误差更小,这一点由公式直接决定。但代价也很实在:长基线意味着你要把仪器搬到更远的地方,多一次搬站就多一份对中误差,而且地球曲率和大气折光在长距离上会显现出来,几百米以上就得考虑球气差改正。更麻烦的是,长基线的两个端点很难保证对同一个目标都有好的通视条件,树木、建筑、地形都可能挡视线。
我的经验做法是:先把目标的预估距离算出来,然后反推需要多长的基线。比如目标距离 500 米,测角精度 2 角秒,要求距离误差不超过 10 厘米,代入 Δd ≈ d²Δθ/b,反解得 b ≈ d²Δθ/Δd = 250000 × 9.7e-6 / 0.1 ≈ 24 米。也就是说基线不需要很长,二十几米就够,把仪器搬近一点、对中做扎实,反而比拉一条一百米的基线更靠谱。
注意:这个反推的前提是交会角落在合理区间。如果反推出的基线太短导致交会角小于 30°,那就得重新考虑方案,比如换更高精度的测角设备,或者干脆改用测距方案。
2.3 现场操作的几条硬规矩,每一条都是踩坑换来的
这部分是教科书上不太强调、但实际作业中决定成败的细节。
对中误差是最隐蔽的杀手。仪器架在三脚架上,如果光学对中器没有精确对准地面点,实际测站位置就偏了,这个偏差会直接进入基线长度和角度观测里。短基线上这个误差尤其致命,因为它是绝对量,而基线本身很短,相对误差被放大了。我的习惯是:架好之后先粗对中,调平,再精对中,再调平,来回两三次直到气泡和十字丝同时稳定。别嫌麻烦,这一步做扎实能省掉后面所有的返工。
正倒镜观测必须做。把望远镜转到盘左测一次,倒转 180° 到盘右再测一次,取平均值。这个操作能抵消掉视准轴误差、横轴倾斜误差、度盘偏心误差这些仪器系统误差。很多人图快只做盘左,数据看着挺规整,实际上系统偏差一直在里面,用多台仪器交叉检查的时候立刻就露馅。
测回法多测几组取平均。单个测回的结果随机误差大,通常要求测 2 到 4 个测回,检查各测回之间的互差是否在限差内。互差超标说明观测过程中有干扰(比如脚架被碰、风吹、目标晃动),必须重测。
必须安排检核条件。三角测量最怕的是“错了但没人知道”。好的布网方案一定包含闭合条件,比如测回一个三角形内角和,理论上应该是 180°,实测值和 180° 的差值就是闭合差,超过限差就说明有问题。有时候还会加测一条额外的边做检核,多余观测是发现错误唯一可靠的手段。
记录气象参数。全站仪测距受温度和气压影响,长距离作业必须记录并做气象改正。这一点在夏天正午和清晨温差大的时候特别明显,同一段距离上午测和下午测能差出几毫米到一两厘米。
别在高温时段测长边。地表受热后空气密度不均匀,视线会弯曲,产生大气折光。中午时段折光最严重,尤其视线贴近地面或水面的时候。合理安排作业时间(清晨、傍晚)比什么改正公式都管用。
3. 计算机视觉里的三角测量:两个镜头怎么“看”出深度
3.1 闭一只眼感受一下:视差就是深度的来源
先做个小实验。伸出一根手指放在眼前,闭上左眼看,记住手指相对背景的位置;换闭右眼,你会发现手指相对背景“跳”了一段距离。手指离眼睛越近,跳动幅度越大;伸到胳膊尽头,跳动就很小。
这就是视差。人类双眼的间距大约 6 到 7 厘米,这就是一条天生的基线,大脑靠左右眼图像的视差反推出深度。双目相机做的事情一模一样,只不过把眼睛换成了两个传感器,把大脑换成了一个公式。
理想平行双目模型下,同一个空间点在左右图像上的横坐标差值为视差 d(单位是像素),那么深度 Z 和视差的关系是:
Z = f × B / d
其中 f 是焦距(像素单位),B 是基线长度(米)。这个式子看起来和前面的角度公式不一样,其实是等价的另一种写法:视差 d 越大,深度越近;视差趋近于 0,深度趋近于无穷远。所以视差图里,近距离物体是亮的(视差大),远距离物体是暗的(视差小),这也是很多视差图看起来像“负片”的原因。
顺手给一段把视差转成深度的代码,参数取常见的工业双目模组:焦距 800 像素,基线 0.12 米。
import numpy as np f_px = 800.0 # 焦距,像素单位 baseline = 0.12 # 基线,米 disp = np.array([1.0, 2.0, 5.0, 9.6, 20.0, 48.0], dtype=np.float32) depth = f_px * baseline / disp for d, z in zip(disp, depth): print(f"视差 {d:5.1f} px -> 深度 {z:7.2f} m")跑出来的结果分别是 96 m、48 m、19.2 m、10 m、4.8 m、2 m。可以看到,视差从 9.6 像素掉到 1 像素,深度就从 10 米跳到了 96 米。视差越小,深度误差越大,这个非线性的反比关系是所有双目系统的先天特性,不是算法好坏能改变的。
3.2 标定:让两个镜头“说同一种语言”
拿两个相机直接拍,是没法算视差的。因为它们的镜头畸变不同、感光元件装配角度有微小差异、焦距也可能不一致。所以标定是绕不过去的一步,它要解决两件事。
内参标定,解决的是“这个相机怎么看世界”的问题。输出包括焦距 fx、fy、主点坐标 cx、cy,以及径向畸变和切向畸变系数。常用方法是用一块已知的棋盘格标定板,从十几个不同角度拍摄,让算法优化求解这些参数。拍摄的时候有个非常实用的经验:标定板一定要覆盖到图像的四个角和边缘。很多人只在画面中央晃两下就收工,结果标出来的畸变系数在边缘区域完全不准,导致图像边缘的深度图一塌糊涂,还以为是匹配算法的问题。
外参标定,解决的是“两个相机相对位置关系”的问题。输出是一个旋转矩阵 R 和一个平移向量 t,t 的长度理论上就是基线长度。这个 t 的准确性直接决定了深度尺度,所以标定完我一般会检查一下求出来的基线长度和物理测量值是否吻合,差得太多就说明标定过程有问题。
标定完还有一步极线校正,作用是把两个相机的成像平面“掰”成理想平行配置,并消除畸变。校正之后,同一个空间点在左右图像上必然位于同一行,匹配搜索就从二维降到了一维,计算量和误匹配率同时下降。这一步不做,后面所有的匹配算法都会很难调。
import cv2 # 假设已经有了一组棋盘格角点 object_points / img_points_left / img_points_right ret, K1, D1, K2, D2, R, T, E, F = cv2.stereoCalibrate( object_points, img_points_left, img_points_right, image_size=(1280, 720), flags=cv2.CALIB_FIX_INTRINSIC # 内参已单独标定好,这里不再优化 ) R1, R2, P1, P2, Q, _, _ = cv2.stereoRectify( K1, D1, K2, D2, (1280, 720), R, T, flags=cv2.CALIB_ZERO_DISPARITY, alpha=0 ) map1x, map1y = cv2.initUndistortRectifyMap(K1, D1, R1, P1, (1280, 720), cv2.CV_32FC1) map2x, map2y = cv2.initUndistortRectifyMap(K2, D2, R2, P2, (1280, 720), cv2.CV_32FC1)这段代码里值得多说一句的是alpha参数。取 0 表示校正后只保留两幅图都有效的重叠区域,图像会被裁掉一圈但所有像素都可用;取 1 表示保留原图所有像素,但边缘会出现黑色无效区。做深度图我一般选 0,省得后面还要处理无效区。
3.3 三角化:已知位姿,怎么把像素点还原成三维点
前面讲的是平行双目这个特例。在更通用的场景里,比如视觉里程计、多视图重建,两个相机的位置姿态是任意摆放的,这时候要用通用的三角化方法。
数学描述是:两个相机光心 C1、C2,已知;同一个空间点在两幅图上的归一化坐标 x1、x2,已知。每个观测点确定一条从光心出发的射线,理想情况下这两条射线应该相交于空间中的那一点。但实际有噪声,两条射线往往不相交,所以工程上求的是“离两条射线都最近的那个点”,也就是中点法。
import numpy as np def triangulate_midpoint(C1, d1, C2, d2): """ C1, C2: 两个相机光心,形状 (3,) d1, d2: 两条射线的单位方向向量,形状 (3,) 返回:两条射线公垂线段的中点 """ r = C1 - C2 a = d1 @ d1 b = d1 @ d2 c = d2 @ d2 d = d1 @ r e = d2 @ r denom = a * c - b * b if abs(denom) < 1e-12: raise ValueError("两条射线近乎平行,三角化退化") t1 = (b * e - c * d) / denom t2 = (a * e - b * d) / denom p1 = C1 + t1 * d1 p2 = C2 + t2 * d2 return (p1 + p2) / 2.0这段代码里那个denom的判断非常关键。当两条射线近乎平行时(等价于前面的交会角接近 0°),分母趋近于零,解会剧烈放大,结果完全不可信。这个判据在实际系统里一定要加上,不然某次退化观测就能把整个地图拉歪。
工程上正经做法一般不会只用两帧,而是把同一个点在多帧里的观测放在一起,做重投影误差的非线性最小二乘优化。原理还是三角测量,只是用上了多余观测来压制噪声,结果会稳得多。
3.4 视差图为什么“麻点”一片:几个无法回避的物理限制
刚接触双目的人几乎都会被同一个问题困扰:明明标定做得很认真,为什么深度图还是坑坑洼洼、满屏噪点?这往往不是算法不好,而是双目本身的物理限制。
无纹理区域。白墙、纯色地板、晴朗天空,这些地方左右图长得完全一样,匹配算法根本找不到对应点。这类区域的视差只能靠邻域插值填补,本质上是猜出来的,不要指望它准。
重复纹理。栅栏、瓷砖、百叶窗、键盘,这些周期性图案会让匹配算法认错位置,产生系统性的错配。表现出来的现象是深度图上出现一层一层的“台阶”。
反光和透明。玻璃、水面、抛光金属,同一个点在左右相机里看到的颜色和亮度都不一致,匹配直接失败。
遮挡区。左相机能看到的地方,右相机可能被前景挡住了。这部分在物理上就不存在对应点,任何算法都补不出来,正规的视差算法会把它们标记为无效值,而不是硬塞一个数字进去。
曝光不一致。两个相机的自动曝光参数不同,或者镜头镀膜老化程度不同,导致同一点的灰度值有系统性偏差。解决办法是关闭自动曝光、手动锁定相同的曝光和增益,或者用对光照不敏感的匹配代价(比如 Census 变换)。
实操心得:我调双目的时候有个固定顺序——先锁曝光,再查同步,再看标定残差,最后才动匹配参数。反过来做的话,你会发现参数怎么调都调不出干净的结果,因为问题根本不在参数上。
3.5 一套可以直接拿走的匹配参数
用半全局匹配(SGBM)这一类算法时,真正需要调的参数其实不多,但每一个都很关键。
| 参数 | 含义 | 取值建议 | 调错的典型表现 |
|---|---|---|---|
| numDisparities | 视差搜索范围,必须是 16 的整数倍 | 按最近距离反算,稍留余量 | 太小明暗处出现假深度,太大速度断崖下降 |
| blockSize | 匹配块边长,奇数 | 3~11,纹理弱用大值 | 太小噪点多,太大边缘变胖、细节丢失 |
| minDisparity | 最小视差值 | 一般 0,校正良好时可为负 | 设置不当导致近处大块无效 |
| uniquenessRatio | 唯一性检验阈值 | 5~15 | 太小误匹配多,太大有效点变少 |
| speckleWindowSize | 斑点滤波窗口 | 50~200 | 太小噪声去不干净,太大连真实小目标一起抹掉 |
| disp12MaxDiff | 左右一致性检查阈值 | 1~2 | 太松遮挡区混入错误值 |
numDisparities的算法很直接:最近工作距离 Z_min 对应的视差是 f×B/Z_min,把这个值向上取整到 16 的倍数就是下限。比如焦距 800、基线 0.12,最近要测到 0.5 米,那视差是 192,取 192 或 208。这个参数设得过大,计算量会线性增长,实时性直接崩掉。
4. 卫星定位和室内定位:名字叫“三角”,干的其实是“三边”
4.1 一字之差:三角测量与三边测量
中文语境里大家习惯把各种定位统称“三角定位”,但严格来说,卫星导航用的不是三角测量,而是三边测量。区别在于观测量的类型:三角测量测的是角度,三边测量测的是距离。
这个区别在原理上很清楚。三角测量靠两个已知点加两个角度,用正弦定理算出未知点位置。三边测量靠三个以上已知点,测量到每个已知点的距离,然后以每个已知点为圆心、以距离为半径画圆(在三维里是球),多个圆/球的交点就是未知点位置。
GNSS 接收机测的是从卫星到接收机的距离,卫星位置由星历解算得出,所以是典型的三边测量。基站定位、UWB 室内定位、声学定位,本质上也都是三边测量。
4.2 为什么至少要四颗卫星:钟差是第四个未知数
三边测量在二维平面上,理论上两个圆的交点就能定出位置(会有两个解,用第三个圆来消除歧义)。三维空间里三个球面一般交于两点,第四个球就能唯一确定。所以直觉上,三维定位需要四颗卫星——但这只是几何上的解释,真正的原因在方程组里。
接收机测得的是伪距,不是真实距离。因为接收机的石英钟精度远不如卫星上的原子钟,存在一个未知的钟差 δt,这个误差乘以光速后是个不得了的数字:1 微秒的钟差就是 300 米的距离误差。所以必须把它当成未知数一起解。
于是方程组长这样:
(x − xᵢ)² + (y − yᵢ)² + (z − zᵢ)² = c²(tᵢ − δt)²
未知数是 x、y、z、δt,一共四个,所以至少要四条方程,也就是四颗卫星。这就是“必须四颗星”的真正来源。收到更多卫星就是超定方程组,用最小二乘求解,精度更高、可靠性更好。
这也解释了为什么很多设备“冷启动”时要等一会儿才能定位——它得先接收星历数据、解算出卫星位置,再凑够四颗可见星才能解出第一个位置。
4.3 DOP 值:卫星几何分布决定精度上限
同样是四颗卫星,位置分布不同,定位精度差得非常多。衡量这个几何好坏的量叫精度因子,英文缩写 DOP。它是观测矩阵的函数,与信号强弱无关,纯粹反映几何构型。
| DOP 类型 | 含义 | 数值与评价(经验参考) |
|---|---|---|
| GDOP | 几何精度因子,综合反映 | < 2 优,2~5 良,> 10 差 |
| PDOP | 位置精度因子 | < 3 优,> 6 明显变差 |
| HDOP | 水平精度因子 | 影响平面坐标精度 |
| VDOP | 垂直精度因子 | 通常最差,高程精度一般是水平的 1.5~3 倍 |
卫星全挤在天顶一个方向上,几何构型就很差,DOP 值大,精度低;卫星均匀撒在天空各个方向,构型好,DOP 值小。所以城市高楼之间、峡谷里、茂密林下,遮挡导致可见卫星集中在一小块天空,DOP 值飙高,定位就会出现明显的“跳点”和漂移。这种时候只能靠惯导、里程计、视觉等传感器做融合来压住,光靠卫星自己救不回来。
4.4 室内定位:把三边测量缩小到几十米
室内没有卫星信号,但三边测量这套思路照样能用,只是把“卫星”换成了部署在室内的基站。
UWB 方案常见的是测到达时间差,多个基站之间保持时间同步,通过时间差反推距离差,画出来是一组双曲线,多条双曲线的交点就是标签位置。本质上还是三边测量的变体。
室内定位的精度瓶颈和卫星完全不一样:不是几何构型,而是多径效应和非视距误差。信号打到墙、金属柜、人身上再反射过来,测出的距离偏大,而且偏大的量不固定,很难用简单模型矫正。所以室内方案特别强调基站布设,要尽量保证标签和基站之间视线通畅,基站高度、朝向、密度都得实际测试后再定。
5. 常见问题与排查实录
5.1 问题速查表
| 现象 | 最可能的原因 | 排查方向和解决办法 |
|---|---|---|
| 所有测距结果整体偏大或偏小,比例一致 | 基线长度输入错误,或尺度系数问题 | 检查基线实测值单位(米/厘米混用极常见),用已知距离做一次标定比对 |
| 近距离准,远距离误差爆炸 | 正常的几何放大,符合 Δd ≈ d²Δθ/b | 加长基线、提高测角分辨率,或承认该距离超出现有能力 |
| 双目深度图整体偏移但形状正常 | 外参标定的基线长度不准,或焦距有系统偏差 | 检查标定求出的基线是否与实际物理尺寸吻合,误差应小于 1% |
| 深度图边缘糊成一片 | blockSize 过大 | 减小匹配块,配合亚像素插值 |
| 深度图噪点多但边缘还行 | 曝光不一致、无纹理 | 锁定曝光增益,检查左右镜头是否同型号同批次 |
| 动态场景深度全乱 | 左右相机没有硬件同步 | 改用硬触发同步,软同步在运动场景下基本不可用 |
| 卫星定位在城区跳动明显 | 多径 + DOP 值变大 | 看 HDOP 数值,融合其他传感器,或换开阔位置 |
| 标定后仍感觉图像有扭曲 | 标定板覆盖区域不足 | 重新标定,让标定板出现在画面四角和边缘 |
| 长时间作业后精度下降 | 温度漂移导致基线变化 | 记录温度,对金属结构做热膨胀改正,或等温稳定后重测 |
| 三角网闭合差超标 | 存在粗差观测 | 逐条边检查,剔除超限观测后重算 |
5.2 几条我踩过坑之后才想明白的事
别指望软件去救硬件几何。这是我最深的一条体会。刚开始调双目的时候,我花了很多时间去调匹配参数、加各种滤波、上后处理,试图把深度图修干净。搞了两周才承认一个事实:基线短了、同步差了、标定歪了,这些是几何层面的缺陷,软件只能掩盖症状,不可能真正修复。真正管用的动作是换更宽的基线、加硬同步、把标定重做一遍。
基线长度的误差是系统性误差,比角度误差更致命。角度误差是随机的,多测几组取平均能压下去;但基线长度如果量错了,所有结果会按同一个比例整体偏移,取多少次平均都没用。所以我现在的习惯是,基线用两种方法各测一遍做交叉验证,比如卷尺加激光测距,两者差超过阈值就重测。
时间同步的优先级高于一切算法优化。双目在静态场景上调得再好,一旦物体是运动的,左右图拍摄时刻不同,同一个点就落在了不同位置,算出来的视差是错的。这类误差没有任何算法能修正,因为它不满足“同一时刻同一场景”的前提。硬触发同步的成本远比在软件里折腾低。
标定的验证比标定本身更重要。标定完不要直接拿去用,一定要做验证:找一个已知距离的目标,实测一下精度,看是否落在理论预期范围内。如果实测误差比理论估计大好几倍,那说明标定或者装配环节有问题,这时候回去查比继续往下做要省时间得多。我一般会拿一块标定板放在 1 米、3 米、5 米处各测一次,看看误差曲线是否符合平方增长的趋势,如果不符合,通常是某个参数出了问题。
多余观测是唯一可靠的检错手段。单次观测错了你永远不知道,只有引入多余观测(多测几个角、多拍几帧、加一条检核边),才可能通过闭合差发现粗差。这是测量学几百年来最基本的经验,放到视觉和定位领域同样成立。
精度指标要写清楚是哪个方向上的。说“精度 5 厘米”,这话是没法用的。是水平还是垂直?是单次观测还是多次平均?是标准差还是最大误差?实际工程里这三者的差别能到好几倍。写方案的时候把条件和统计口径交代清楚,比报一个漂亮的数字重要得多。
最后分享一个我一直在用的判断方法:拿到任何一个测距或定位方案,先别急着看算法多先进,先问三句话——它的基线在哪、基线多长、测角或测距的分辨率是多少。把这三个数代进 Δd ≈ d²Δθ/b,就能在五分钟内判断出这个方案在你的场景下到底行不行,比看一百页说明书都快。三角测量这套东西之所以值得花时间吃透,就是因为它不只是某个具体技术的原理,而是所有“从已知推未知”的空间测量方案的共同骨架。