前阵子帮朋友调一个桌面小零件抓取的项目,机械臂要抓的东西离镜头只有二三十厘米,手上那台常规双目深度相机在这个距离上基本是"瞎子":深度图大片空洞,偶尔冒出来的点还飘。后来换了这颗主打近距离测距的 OAK-D-SR,同样的工位、同样的光照,深度图第一次完整地盖住了整个料盒。社区里管它叫"大白深度相机",名字听着挺可爱,但它真正值钱的地方不在体积,而在于它是少数把"近距离"当成主战场来设计的深度相机。
这篇就把我这两周踩过的东西摊开讲:它为什么能在近处工作、拿到手怎么把自己的机器参数读出来、DepthAI 流水线该怎么配、近距离场景里那六个坑分别怎么排、以及什么时候你其实不该选它。内容偏实战,参数给了推导过程,代码能直接跑,刚上手的人和有几年经验的都能拿走点东西。
1. 近距离测距才是真正的地狱难度:OAK-D-SR解决了什么问题
1.1 "看得远"是常规操作,"看得近"是硬骨头
绝大多数人对深度相机的直觉是"测距范围越大越牛",所以选型时第一眼看的是最大量程。真正做过项目的人都知道,远距离只是精度衰减的问题,近距离是"根本测不出来"的问题。原因有两个,而且都是物理层面的。
第一个是视差搜索范围。双目深度靠的是左右两幅图的像素偏移量(视差)反推距离,而芯片能搜索的视差是有上限的,一般几十到一百九十像素。距离越近,同一个物理点在左右图上的像素偏移越大,一旦超过搜索上限,这个点就直接被判为"无效"。所以每一台双目相机都有一个"最小可测距离",不是镜头限制,是算法限制。这也解释了为什么 OAK-D-SR 的近距离测距能力本质上来自"更短的基线 + 更宽的有效视场",而不是什么神秘算法。
第二个是遮挡。两台相机分开了距离 B,看同一个物体时各自能看到的部分是不一样的。基线除以距离这个比值越大,两侧视角差异越大,被一侧看到、另一侧看不到的区域就越多。30cm 距离配常规基线时,这个比值相当可观,左右一致性检查会毫不留情地把这些点全部剔掉,深度图上就出现一圈"描边式空洞"。近距离测距的难点,一大半都在这里。
1.2 从 Z = f·B / d 这条公式,看清"近"的代价
立体视觉的核心公式就一行:
Z = (f_px × B) / d
Z 是深度(米),f_px 是焦距换算成像素后的值,B 是基线(米),d 是视差(像素)。最小可测距离就是视差取到搜索上限时的 Z:
Z_min = (f_px × B) / d_max
我按几种常见的小基线量级和不同匹配分辨率,把 Z_min 算了一遍,你可以直接对照自己手里的设备:
| 基线 B | f_px @640 宽 | d_max=95 | d_max=190(扩展视差) |
|---|---|---|---|
| 3.5 cm | 440 px | 16.2 cm | 8.1 cm |
| 5.0 cm | 440 px | 23.2 cm | 11.6 cm |
| 7.5 cm | 440 px | 34.7 cm | 17.4 cm |
| 7.5 cm | 880 px @1280 宽 | 69.5 cm | 34.7 cm |
这张表里最有信息量的是最后两行。同一个物理基线,匹配分辨率从 640 宽提到 1280 宽,f_px 翻倍,最小可测距离也直接翻倍。反过来说:想让相机贴得更近,把参与匹配的分辨率降一档是个有效手段,代价是每个像素代表的角度变大,深度分辨率变粗。这就是工程上的取舍,没有免费午餐。
注意表里第二、三行的 f_px 是我按水平视场约 72 度估的(f_px = (W/2) / tan(HFOV/2)),你手上的实际值要用标定文件读,别照抄。我在第 2 节会给出读取脚本,读出来的才是真数。
1.3 体积做小之后,被换掉的是什么
"全网最小"这个说法当然有营销成分,但体积小这件事在近距离任务里确实是实打实的加分项,前提是你清楚它换掉了什么。
换掉的第一样是散热面积。算力芯片满载跑深度推理时外壳会明显温热,这是正常的,但温度变化会让结构件产生微米到几十微米级的形变,而近距离对角度误差极其敏感。第二样是镜头口径和通光量,进光少意味着暗光下噪声大、匹配质量下降。第三样是接口和固定点,小体积模组往往只有几个安装孔,刚性安装比大机器更难做。
但它加回来的东西同样明显:能塞进机械臂末端执行器旁边、能卡进狭窄的设备腔体、能装在移动平台的前裙板里补近场盲区。这些位置大机器根本进不去。我这次的项目就是把它直接固定在夹爪基座上,跟着机械臂一起动,线缆直接从拖链里走,整机没有任何额外支架。这种安装自由度,是省下来的体积换来的。
2. 先把自己的机器测明白:从标定文件里挖出真实基线与fx
2.1 读EEPROM标定,二十行代码拿到内参与基线
我不建议你照抄任何网上的参数来配流水线。不同批次、不同镜头版本的模组,基线和内参都会有差异,自己读出来的才作数。DepthAI 把出厂标定烧在 EEPROM 里,读起来非常方便:
import depthai as dai with dai.Device() as device: calib = device.readCalibration() # 1) 内参:分辨率要和你后面参与匹配的分辨率一致 W, H = 640, 400 K = calib.getCameraIntrinsics(dai.CameraBoardSocket.LEFT, W, H) fx, fy = K[0][0], K[1][1] cx, cy = K[0][2], K[1][2] print(f"fx={fx:.2f} fy={fy:.2f} cx={cx:.1f} cy={cy:.1f}") # 2) 基线(默认单位厘米) B_cm = calib.getBaselineDistance(dai.CameraBoardSocket.LEFT, dai.CameraBoardSocket.RIGHT) print(f"baseline = {B_cm:.3f} cm") # 3) 出厂标定先备份,改坏了还能刷回去 calib.eepromToJsonFile("factory_calib.json") # 4) 顺手把传感器型号打出来,确认批次 for socket, name in device.getCameraSensorNames().items(): print(socket, name)两个提醒。第一,getCameraIntrinsics的第二个参数是你想要的输出分辨率,DepthAI 会按比例缩放内参,所以这里传的分辨率必须和后面实际参与深度计算的分辨率一致,否则算出来的 fx 是错的。第二,不同 SDK 版本的方法名偶尔会调整,getBaselineDistance如果报错,用dir(calib)看一眼当前版本叫什么,别硬套。
拿到 fx 和 B 之后,把你机器的最短可测距离算出来:
fx_px, B_m, d_max = 440.0, 0.075, 190 print("Z_min = %.3f m" % (fx_px * B_m / d_max))这一步花不了一分钟,但它决定了你后面所有的参数取舍。如果你算出来的 Z_min 是 35cm,而你的工位最近要测 20cm,那你必须开扩展视差、或者降匹配分辨率、或者用视差偏移,否则怎么调都是在跟物理规律较劲。
2.2 三个"近距离增强"开关的真实收益与代价
DepthAI 的 StereoDepth 节点上有几个开关,网上教程大多只告诉你"打开更好",但没说代价。我在实际项目里逐个试过,结论是这样的:
| 开关 | 作用 | 收益 | 代价 |
|---|---|---|---|
setExtendedDisparity(True) | 搜索上限翻倍 | 最近距离大约缩短一半 | 计算量上升,边缘噪点变多,对分辨率有约束 |
setLeftRightCheck(True) | 左右一致性校验 | 剔除绝大部分错误匹配 | 遮挡区和物体边缘空洞明显变多 |
setSubpixel(True) | 亚像素插值 | 深度值更平滑,量化台阶消失 | 极小视差处的可信度下降,需要过滤 |
setConfidenceThreshold(n) | 匹配置信度门限 | 低置信度区域被清空 | 阈值调太高会把有效点也吃掉 |
setDisparityShift(n) | 视差范围整体前移 | 能看更近 | 最远距离被硬截断 |
关于setDisparityShift,用法很简单,但要想清楚再开:
# 已知我只看 0.15m - 1.2m,远距离对我没用,就把搜索窗口整体往前推 stereo.setDisparityShift(24)它的逻辑是"牺牲远场换近场"。如果你的场景里确实有远距离目标(比如移动平台既要看脚下又要看前方三米),那这个开关不能开,得换方案或者加一台相机。我吃过一次亏:为了看得更近把视差偏移调大了,结果机械臂抬起来之后完全看不到料架高度,排查了半天才发现是被自己截断的。
还有一个坑藏在setOutputSize里。这个参数设成比输入小的尺寸时,参与匹配的等效焦距会变小,最近距离反而能拉近,但深度精度会下降。不同 SDK 版本对这个参数的处理细节不完全一致,所以别信文档结论,自己验证:同一个物体固定不动,改一下输出尺寸,看深度图的空洞分布和数值有没有变化。这是最快搞清楚你手上这套 SDK 行为的方法。
2.3 用标定文件验证精度:误差是随距离平方增长的
这一点特别值得单独说,因为它经常被误读。双目的深度误差大致和 Z² 成正比:
ΔZ ≈ Z² × Δθ / B
其中 Δθ 是标定和匹配引入的角度误差(弧度)。我拿 0.1 度(约 0.00175 弧度)的角误差和 5cm 基线估算:
| 目标距离 | 深度误差估算 |
|---|---|
| 20 cm | 约 1.4 mm |
| 50 cm | 约 8.8 mm |
| 1 m | 约 35 mm |
| 3 m | 约 315 mm |
结论很反直觉:近距离不但更容易测,而且精度天然更好。这正好是 OAK-D-SR 这类小基线近距离机器存在的意义——它把双目方案最擅长的那段距离做成了主场。反过来,你如果想用它去测三米外的东西,物理上就注定不准,硬调参数也没用。
3. 跑通第一条近距离流水线:DepthAI节点逐个拆解
3.1 相机节点:为什么近距离场景要锁死曝光
先看相机节点。近距离场景我最常做的一件事是手动锁定曝光,而不是让它自动调:
import depthai as dai pipeline = dai.Pipeline() monoL = pipeline.create(dai.node.MonoCamera) monoR = pipeline.create(dai.node.MonoCamera) for cam, socket in ((monoL, dai.CameraBoardSocket.LEFT), (monoR, dai.CameraBoardSocket.RIGHT)): cam.setBoardSocket(socket) cam.setResolution(dai.MonoCameraProperties.SensorResolution.THE_800_P) cam.setFps(30) # 关键:左右目必须用完全相同的曝光,否则两幅图亮度不一致,匹配质量断崖式下跌 cam.initialControl.setManualExposure(8000, 800)为什么一定要手动?因为立体匹配本质上是在两幅图里找"长得一样"的区域。自动曝光是每颗传感器独立决策的,两边的积分时间稍微差一点,同一块表面在左右图里的灰度就对不上,纹理相似度下降,匹配直接就崩了。近距离场景里这类问题尤其致命,因为物体离得近、反光强,自动曝光容易来回振荡,深度图会跟着一帧好一帧烂。
setManualExposure(曝光微秒数, ISO)这两个数要按你的实际光照试。室内常规照明下 5000 到 10000 微秒是个合理起点,太长了会拖帧率,太短了噪声大。全局快门传感器在这里帮了大忙——它是整帧同时曝光的,机械臂快速运动时不会出现果冻式的行间错位,这一点对跟随运动的场景是刚需。
3.2 深度节点的参数组合,以及每一行为什么这么写
深度节点的配置是整个流水线的核心,我按注释逐行解释:
stereo = pipeline.create(dai.node.StereoDepth) monoL.out.link(stereo.left) monoR.out.link(stereo.right) # 预设:近距离小物体建议 HIGH_DENSITY,人脸类场景可试 FACE stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY) # 近场视差大,必须开扩展视差,否则 20-40cm 直接没数据 stereo.setExtendedDisparity(True) # 左右一致性检查:宁可留下空洞,也不要一堆假点 stereo.setLeftRightCheck(True) # 亚像素让深度值平滑,抓取场景里很重要,否则点会一跳一跳 stereo.setSubpixel(True) # 置信度门限,先给 200 左右,太低会有飞点,太高近处有效点也保不住 stereo.setConfidenceThreshold(200) # 中值滤波压掉散点,代价是物体边缘会被磨掉一两个像素 stereo.setMedianFilter(dai.MedianFilter.KERNEL_7x7) # 输出尺寸决定后续可视化和点云的密度 stereo.setOutputSize(640, 400)这几行里最容易被忽略的是setConfidenceThreshold。它不是一个"越高越好"的参数,而是一个"你更怕假点还是更怕空洞"的选择。做抓取的时候我通常偏保守,因为一个假的深度点会让机械臂直接抓空甚至撞上去;做三维重建的时候我会调低,因为点云配准能容忍少量离群点。
如果你需要把深度对齐到彩色图(比如要把颜色贴到点云上),加一行stereo.setDepthAlign(dai.CameraBoardSocket.CAM_A)。但注意,对齐之后深度图的有效边缘会变窄,因为对齐是一个重采样过程,近场视差大、遮挡多,边缘本来就不牢靠。我的习惯是先在原始左目坐标系里把深度算准,需要上色的时候再对齐。
3.3 从深度图到彩色点云:输出节点的完整写法
# 深度图通道 xout_depth = pipeline.create(dai.node.XLinkOut) xout_depth.setStreamName("depth") stereo.depth.link(xout_depth.input) # 点云通道(可选,近距离重建时很有用) pointcloud = pipeline.create(dai.node.PointCloud) stereo.depth.link(pointcloud.inputDepth) xout_pcl = pipeline.create(dai.node.XLinkOut) xout_pcl.setStreamName("pcl") pointcloud.outputPointCloud.link(xout_pcl.input)跑起来之后,读深度图并转成真实的米:
with dai.Device(pipeline) as device: q_depth = device.getOutputQueue("depth", maxSize=4, blocking=False) while True: in_depth = q_depth.tryGet() if in_depth is None: continue frame = in_depth.getFrame() # uint16,单位毫米 z_m = frame.astype("float32") / 1000.0 # 0 表示无效点,画图前先屏蔽掉 cv2.imshow("depth", cv2.applyColorMap( cv2.convertScaleAbs(frame, alpha=0.03), cv2.COLORMAP_JET)) if cv2.waitKey(1) == ord('q'): break深度帧是 uint16,单位毫米,值 0 代表没有有效视差。做任何统计之前先把 0 屏蔽掉,否则算出来的平均深度会被拉偏。
3.4 上手第一件事:拿尺子量,别信"看起来不错"
可视化出来的彩虹图特别有欺骗性,"看着挺完整"和"数值准不准"是两件事。我的验证流程很简单:拿一块贴了报纸或者打印了随机纹理的硬纸板,正对相机放在刻度尺上,从 20cm 开始每 5cm 挪一次,到 100cm 为止,每次记录中心区域的深度中位数、标准差和空洞率。参考值大概长这样(我的环境和参数,你的会有差异):
| 实际距离 | 深度中位数 | 标准差 | 空洞率 |
|---|---|---|---|
| 20 cm | 20.4 cm | 2.1 mm | 12% |
| 30 cm | 30.1 cm | 1.2 mm | 6% |
| 50 cm | 50.1 cm | 1.5 mm | 4% |
| 100 cm | 100.3 cm | 4.0 mm | 9% |
空洞率这一列特别有诊断价值。如果 20cm 处空洞率超过一半,说明你的最近距离还没压够,该开扩展视差或者调视差偏移;如果 30cm 处反而比 50cm 空洞更多,那就是纹理或者曝光的问题,跟距离无关。用同一套流程量一遍,你对这台机器的边界就有数了,后面调参不会再靠感觉。
4. 近距离深度图的六个典型坑(附排查链路)
4.1 白墙、桌面、纯色零件:深度图成片空洞的根因
这是新手遇到的第一个也是最常见的坑。现象是深度图中间一条一条的横向条纹,或者大面积全黑。根因不是相机坏,而是立体匹配需要"纹理"——左右两幅图里得有能唯一对应的图案。一块纯白、纯灰的平面上,每个像素周围长得都一样,匹配算法根本不知道哪个对哪个,置信度自然上不去。
排查顺序很简单:把相机对着有纹理的报纸、木纹桌面、带印花的地毯,如果深度图瞬间变完整,那就是纹理问题,不是设备问题。
补救手段按成本从低到高排:一是更换表面或临时贴标记(工业场景里最常见的做法,贴几块随机纹理贴纸,几块钱解决问题);二是调整打光角度,让表面产生自然的明暗渐变,斜射光比正射光强得多;三是加主动纹理投射(散斑投影器),这是最彻底的方案,但要额外加硬件,而且户外强光下效果会打折;四是调整setConfidenceThreshold和setLeftRightCheck,用"放宽标准"硬挤出一些点来,代价是假点变多。我一般只在静态测量场景用最后一种,动态抓取绝对不用。
4.2 曝光与红外干扰:户外白天为什么表现掉档
双目深度是纯被动视觉方案,靠的是环境光。到了户外,阳光里含大量红外成分,会把近处的暗部细节全部淹没,对比度被压扁,匹配质量直线下降。这不是设备缺陷,是所有被动双目在强光下的共性问题。
排查办法:看深度图的空洞是不是呈现"越亮的地方越差"的规律,如果是,基本就是过曝。处理方式是手动降低曝光时间、必要时加窄带滤光片,或者把工作时段挪开正午。近距离室内场景里,另一个相关坑是对着窗户或灯管拍,高光区域直接饱和成一片白,那片区域的深度也是废的。调整相机俯仰角避开直射光源,往往比调参数有效得多。
4.3 玻璃、透明与镜面:物理上就无解的那类目标
如果你的项目里要测玻璃板、亚克力、抛光金属,先接受一个事实:被动双目对这类表面基本无能为力。透明物体不反射红外到相机,镜面则把附近的场景反射进去,算法看到的是"假目标"。我见过有人把置信度调到最低试图抢救,最后拿到的是一堆噪声点,比没有更危险。
工程上的解法只有绕过:换个角度让表面产生可测的漫反射(斜 30 到 45 度打光),在玻璃上贴一小块哑光胶带做基准点,或者干脆换成接触式测量。这一条我建议写进项目文档的需求评审里,别等调试阶段才发现。
4.4 热漂移与标定:为什么长时间跑之前要先热机
这是最少被提及、但影响最直接的一条。算力芯片工作一段时间后温度上升,结构件产生微米级形变,等效于基线长度和左右目的相对姿态发生了极小变化。对远距离相机这几乎无感,但对近距离相机,这个变化会体现在深度值的系统性偏移上。
我的做法是:设备开机后先空跑 8 到 10 分钟让温度稳定,再做任何精度相关的采集或标定。如果项目要求长时间连续运行,就记录温度与深度偏移的对应关系,必要时做温度补偿查表。
顺带说标定的注意事项。旋转镜头调焦之后一定要重新标定,因为光学状态变了。写 EEPROM 之前先执行calib.eepromToJsonFile()存一份出厂备份,这个习惯救过我一次——改错参数之后是靠备份文件刷回去的。标定板建议用打印精度高的棋盘格贴在刚性平板上,平板不平是标定误差的常见来源,比算法本身影响还大。
4.5 带宽与供电:USB线材导致的帧率崩塌
现象是帧率莫名其妙掉到个位数,或者干脆设备识别不到。近距离高密度深度图的数据量不小,双路高分辨率图像加深度输出,走 USB2 或者劣质延长线、带供电不足的 Hub,带宽立刻不够。
排查链路:先看设备是不是枚举在高速口上,再换一根短的、质量好的数据线直连主板后置接口,最后去掉所有 Hub。我在一个项目里被一根三米长的廉价延长线坑了整整一个下午,换线之后帧率恢复满值。这条经验值很低但很实用:调试阶段一旦出现"性能莫名下降",先怀疑线,再怀疑代码。
4.6 对齐到彩色图后边缘"歪了"是怎么回事
开了深度到彩色的对齐之后,你会发现物体边缘出现一圈彩色的晕,深度值在边缘处也不准。这不是 bug,是两个原因叠加:一是两个相机在物理上位置不同,近场视差大,遮挡区域大,对齐是重采样,遮挡区没有真实数据;二是彩色和单目分辨率不同,缩放插值会模糊边界。
处理办法:尽量在原始左目坐标系里做几何计算,只在需要展示或者上色时才对齐;如果必须要对齐后的彩色点云,把对齐后的边缘区域裁掉再使用,别拿边缘的深度值做测量。
5. 能直接抄的四个近距离用法(含ROI取三维坐标代码)
5.1 桌面抓取:用ROI拿一个稳定的三维点
抓取场景不需要整张深度图,只需要目标物体中心那一小块的三维坐标,而且用 ROI 取平均能有效压掉噪声:
spatial = pipeline.create(dai.node.SpatialLocationCalculator) stereo.depth.link(spatial.inputDepth) spatial.inputConfig.setWaitForMessage(False) cfg = dai.SpatialLocationCalculatorConfigData() cfg.depthThresholds.lowerThreshold = 150 # 只看 15cm 以上 cfg.depthThresholds.upperThreshold = 800 # 忽略 80cm 以外的背景 cfg.roi = dai.Rect(dai.Point2f(0.42, 0.42), dai.Point2f(0.58, 0.58)) config = dai.SpatialLocationCalculatorConfig() config.addROI(cfg) spatial.initialConfig.addROI(cfg) xout_spatial = pipeline.create(dai.node.XLinkOut) xout_spatial.setStreamName("spatial") spatial.out.link(xout_spatial.input)读取的时候:
q = device.getOutputQueue("spatial", maxSize=8, blocking=False) data = q.tryGet() if data is not None: for loc in data.getSpatialLocations(): c = loc.spatialCoordinates print("X=%.1fmm Y=%.1fmm Z=%.1fmm" % (c.x, c.y, c.z))坐标单位是毫米,原点在左目相机光心,X 向右、Y 向下、Z 向前。这里的lowerThreshold和upperThreshold一定要设,它们是过滤背景的关键——近距离场景里最常见的错误就是料盒边缘的深度混进来,导致抓取点偏移。我一般让 ROI 比物体实际投影小一圈,宁可取到物体内部的一个小区域,也不要吃到边缘。
5.2 微距三维重建:转台加多视角配准的实际细节
要把小零件扫成完整模型,单视角不够,得转。我用的方案是转台每转 30 度采一帧点云,一共 12 帧。
细节一:先用标定好的内参把深度图转成点云,不要靠 SDK 直接出的点云做配准,因为你自己转换的时候可以控制是否屏蔽无效点、是否做下采样。转换公式就三行:
z = depth_mm / 1000.0 x = (u - cx) * z / fx y = (v - cy) * z / fy细节二:无效点(深度 0)必须在配准前剔除,否则 ICP 会被拉到无穷远或者原点。
细节三:转台的旋转角度是已知的,直接用这个先验做初始对齐,比纯 ICP 快得多也稳得多。纯 ICP 对初始位姿很敏感,两个视角差 30 度时容易收敛到错误解。
细节四:近距离点云稠密,下采样到 2 到 3mm 的体素再做配准,精度损失可以接受,速度提升好几倍。
5.3 近场补盲:给移动平台补上脚下的死角
移动机器人正前方的大基线相机,在一米以内基本是盲区,桌腿、台阶、地面上的线缆全都看不到,这是很多碰撞事故的直接原因。用一颗小基线近距离相机朝前下方装,专门管 10cm 到 80cm 这一段,两个传感器分工明确,成本也不高。
这里有个实际经验:两个深度源的坐标系统一问题,比算法本身更花时间。我建议所有深度输出统一转到机器人基座坐标系,用一套外参管理,别在业务代码里到处做手动的偏移补偿,后面改一个参数会牵动一片。
5.4 手部与指尖跟踪:小视差范围的意外好处
近距离做手部交互的时候,我发现一个反直觉的好处:因为视差搜索范围有限,远处背景根本不会产生有效深度,这就相当于自带了一个距离滤波器,背景干扰天然被排除。用人脸或手部预设跑,深度图里只有手是实的,后面的墙是空的。
代价是要注意手的运动速度。手在近场移动时像素位移很快,曝光时间必须压短,我一般用 3000 到 5000 微秒。另外手的表面纹理弱(皮肤在红外下比较均匀),空洞率会比测纸板高不少,做指尖定位时要加时序滤波补点。
6. 选型账本:什么时候SR是对的,什么时候该换
6.1 一张表看清几类方案的边界
| 方案类型 | 近场(20-40cm) | 中远场 | 强光户外 | 无纹理表面 |
|---|---|---|---|---|
| 小基线被动双目(SR这类) | 好 | 精度快速衰减 | 差 | 差 |
| 常规/大基线双目 | 基本不可用 | 好 | 差 | 差 |
| 主动纹理投射+双目 | 好 | 好 | 中等 | 好 |
| 结构光 | 好 | 差(衰减快) | 差 | 好 |
| 飞行时间类 | 受最小距离限制 | 中等 | 中等 | 好 |
看这张表就很清楚了:如果是"近距离 + 有纹理 + 室内受控光照",小基线被动双目是性价比最高的选择,算力还自带在模组里,不用额外主机。一旦你的场景里出现"强光户外"或者"大面积白墙",就必须考虑主动投射,这时候小基线被动方案的短板暴露得最彻底。
6.2 我自己的选型顺序:距离、精度、体积
吃过几次亏之后,我现在的评估顺序固定成三步。第一步先问"最近要测多近、最远要测多远",把区间画出来,然后对照 Z_min 公式判断哪些方案在区间内。这一步能砍掉大部分候选。第二步问"深度误差容忍多少",用 ΔZ ≈ Z²Δθ/B 估算,如果算出来的误差大于公差,方案直接否掉,别指望后处理能把物理误差修回来。第三步才问体积、接口、算力、功耗这些工程约束。
这个顺序的关键在于,前两步是物理约束,改不了;第三步是工程约束,能用钱和时间解决。很多人反过来先挑型号再看参数,最后只能在参数上妥协。
6.3 想往上走,下一步可以试什么
如果你发现被动方案在你的场景里实在撑不住,两个方向可以试。一是加主动纹理投射,把无纹理表面的问题解决掉,同时扩展近距离的可用范围,这是收益最直接的一步。二是做多相机分工,近距离一颗、中距离一颗,用统一的坐标变换把数据合起来,软件上多写一点融合逻辑,但每颗相机都在自己最擅长的区间工作,整体精度比单颗硬撑高得多。
如果你的目标是把近距离的精度再往上顶一档,还有一条路是提高匹配分辨率再配更好的标定。前面那张表里,f_px 翻倍会让最小距离变远,但深度精度会明显变好,所以"要更近"和"要更准"在同一个方案里是要权衡的,想同时拿到就得双相机分工,这是绕不过去的取舍。
最后分享一个小习惯。我现在每拿到一颗新的深度相机,第一件事不是跑官方示例,而是读标定、算 Z_min、量一遍尺子。这三件事加起来不到半小时,但它决定了后面两周我会不会在参数里瞎转。踩过几次坑之后我越来越确信,深度相机的调试从来不是调参数的艺术,而是先把物理边界摸清楚,再在边界内做工程的过程。