1. ToF 相机不是一颗摄像头,是一套小型雷达系统
我做机器视觉这些年,被问得最多的问题就是"ToF 相机到底和普通相机有什么区别"。如果只从外观上看,它就是一个黑乎乎的带镜头的小盒子,甚至很多国产模组看起来和普通 USB 摄像头没有差别。但一旦你把镜头盖拧开,或者翻一下规格书,就会发现它完全不是"摄像头"这么简单。
本质上,ToF(Time-of-Flight,飞行时间)相机是一套小型化的激光雷达系统。普通相机被动接收环境光,把光子打在传感器上形成图像;ToF 相机则主动发射近红外激光,等光从目标表面反射回来,通过测量光的飞行时间差,直接算出场景中每个点的距离。这个过程很像你在山谷里喊一声,靠回声到达的时间判断山壁离你多远——只不过 ToF 相机每秒重复几十万次这样的"呼喊",并且是以像素为单位在做。
这就会引出一个关键认知:做 ToF 相机的项目,不是在调一个摄像头,而是在调一套包含激光发射、光学、传感器、驱动、标定、算法、系统同步的完整链路。任何一个环节出了偏差,最后落到深度图上都是问题。这篇文章我就按从下到上的顺序,把这根链路完整捋一遍。从 VCSEL 激光器怎么选、iToF 和 dToF 有什么区别,到寄存器配置、标定流程、点云处理,再到 Android、ROS、工业现场的集成落地,最后附上我做项目时踩过的一些坑。无论你是刚接触深度相机的入门开发者,还是已经接了工业项目但被深度图质量折磨的同行,这篇文章应该都能给你一些参考。
2. 底层硬件:一颗深度传感器是怎么把光变成距离的
2.1 发射端:VCSEL 激光器与扩散片
ToF 相机的发射端,核心器件是 VCSEL(垂直腔面发射激光器)。和传统的边发射激光器不同的是,VCSEL 的光是垂直于芯片表面射出的,非常容易在半导体工艺上做成二维阵列,实现高功率、小体积的面发射光源。绝大多数 ToF 模组发射的光波长是 850nm 或 940nm,其中 940nm 用得更多。原因很直接:太阳光中 940nm 波段的辐射强度比 850nm 低不少,在户外场景下环境光的干扰会更小。
但 VCSEL 只是光源,真正决定照射范围的是它前面那颗 DOE 扩散片(衍射光学元件)。DOE 的作用是把原本发散角度有限的光束拆分成点阵,再扩散成均匀的照明场,让它能覆盖到镜头视场角对应的区域。这里有个特别容易忽略的匹配问题:DOE 的扩散角度必须和镜头的 FOV(视场角)匹配。如果 DOE 扩散角和镜头视场不一致,就会出现画面边缘照度不够、深度图四周发黑、中心过曝的现象。所以你在做硬件选型或者自己搭模组时,千万别只盯着相机的分辨率和帧率,发射端和接收端的角度匹配比什么都重要。
2.2 接收端:ToF 传感器与光学系统
接收端的光学系统其实和普通相机很像:镜头、窄带滤光片、图像传感器。区别在于传感器本身。
窄带滤光片是一个容易被低估的器件。它只让 940nm 附近很窄一个波段的光通过,其他波段的可见光和红外光统统过滤掉,用来压制环境光。好的滤光片带宽可以做到 10~30nm,配合 VCSEL 的窄带发射,能显著提升信噪比。很多出厂深度图花花绿绿噪声大,第一排查项就是滤光片,要么带宽太宽,要么装反了,要么根本没用窄带片。
传感器则是整条链路的心脏。ToF 传感器虽然是 CMOS 工艺制造,但像素结构和普通 RGB 像素完全不同。iToF 的像素内部通常包含两个或者多个抽头(Tap),通过让电荷在电场驱动下按调制信号分配,积攒出与光信号相位差成正比的电荷量,从而反推出光的飞行时间。而 dToF 的像素则集成了单光子雪崩二极管(SPAD)和计时电路,能直接记录单个光子到达的那个时刻。这也是为什么 dToF 传感器的像素尺寸通常偏大、分辨率做不高。
2.3 核心差异:iToF 与 dToF,到底怎么选
很多刚接触 ToF 的朋友,第一个纠结的问题就是 iToF 和 dToF 怎么选。我直接用一句话概括:iToF 看相位,dToF 数光子。
iToF 发射的是经过调制的连续波(通常是正弦波或方波),传感器在曝光期间对反射回来的光进行相位测量。因为相位差只在 0~360 度内有意义,所以 iToF 天然存在一个模糊距离,模糊距离之外的距离信息都需要额外处理。比如调制频率 100MHz 时,模糊距离是 c/(2f),约 1.5 米,超过这个范围就会产生"距离卷绕",必须有第二个甚至第三个调制频率参与解算。iToF 的优势是分辨率可以做高、像素尺寸可以做得比较小、成本相对低,但劣势也很明显:对多路径干扰敏感,在强反光、拐角、凹面这些场景容易出错。
dToF 的思路直接得多:发出一个光脉冲,用 SPAD 像素检测反射回来的单光子,配合时间数字转换器记录下光子飞行的时间。为了对抗噪声,dToF 会重复积累大量脉冲,把光子到达时间的统计直方图画出来,第一个明显的峰值就是目标距离。因为它是直接测时间,所以不受模糊距离限制,测距可以做得比较远,而且天然对多路径干扰有一定免疫——直射路径的光子先到,反射路径的光子后到,只要直方图的峰分得开就能区分。缺点是 SPAD 像素尺寸大,分辨率做不高,成本也更高,所以目前 dToF 主要用在手机激光雷达扫描仪、AR 设备、扫地机避障这类场景,而对精度要求高的近距离工业测量,iToF 相对更常见。
从我选型经验来看,室内桌面级尺寸测量、人脸识别、手势交互这类 0.2~3 米的应用,iToF 是主流;需要户外抗阳光、需要测 5 米以上距离、或者场景里有大量玻璃和金属反射物,我优先建议 dToF。
3. 驱动与固件:让激光和传感器严丝合缝地配合
3.1 寄存器、曝光与调制频率
硬件层聊完,紧接着是驱动层。ToF 相机的驱动和普通相机最大的区别是:激光器必须和传感器严格同步。普通相机开机、设曝光、读图就行,而 ToF 相机如果激光器和传感器的解调时钟不同步,出来的深度图就是花屏一样的一片混乱。
在实际开发中,你需要通过寄存器去配置的通常包括这几类:调制频率(决定测距量程和模糊距离)、曝光时间(或者叫积分时间,决定信噪比)、激光器功率、ROI 窗口、帧率、工作模式等。曝光时间越长,收集到的光信号越多,信噪比越好,但帧率会下降,运动物体也更容易出现运动模糊。比如一个 640x480 的 iToF 传感器,单次曝光 1ms 左右可以跑 30fps,当你想把距离测准一点、把曝光拉到 8ms,帧率基本就掉到 10fps 左右了。所以很多 ToF 方案里都引入了多积分时间合成(HDR)模式:短曝光捕获近处强反射目标,长曝光捕获远处弱反射目标,再合成一帧高动态范围的深度图。
固件这一层还有一个容易被忽略的职责:温度补偿。激光器在工作时会发热,传感器近旁的电子器件也会热漂移,温度变化直接影响 VCSEL 的发光强度和相位延迟。多数商用 ToF 模组的固件里会内置温度传感器和补偿表,根据当前温度动态修正深度值。这也是很多开源的裸驱动深度图不稳定的核心原因——不是算法不对,而是缺少了固件层的温度补偿。
3.2 数据接口与帧率
驱动层最后要考虑的是数据传输。ToF 相机产出的数据量比普通 RGB 相机大得多:一帧深度图通常用 16bit 存储,640x480 分辨率一帧就有约 600KB,如果再带上幅度图、置信图,数据量直接翻倍。手机和平板上的 ToF 模组一般走 MIPI CSI-2,直接进 ISP 或者 NPU;USB 相机则走 USB3 Vision 或者 UVC 扩展协议;工业级 ToF 相机更多走 GigE Vision 接口,毕竟工业现场布线长、需要 PoE 供电。
走 GigE 接口时有个坑:默认 MTU 是 1500,高分辨率高帧率下特别容易丢包、图像撕裂。解决办法是把网卡的巨型帧(Jumbo Frame)打开,MTU 调整到 9000,同时保证交换机和相机端都支持并且两侧配置一致,否则反而会出问题。我之前接工业相机就遇到过"相机图像一片黑+报错",排查了半天发现自己网卡开了巨型帧但相机端没开,两边 MTU 协商不上,丢包丢得乱七八糟。
4. 标定:ToF 相机的"出厂体检"与交付前校准
4.1 内参标定与常规相机有何不同
不管相机用什么原理测距,只要它成像,就会出现镜头畸变。ToF 相机也需要做内参标定,标定方法和普通相机基本一致:用棋盘格或者二维码板,在多个角度、多个距离采集图像,用张正友标定法或者 OpenCV 的 calibrateCamera 解出焦距、主点和畸变系数。
但 ToF 相机的内参标定有两个要注意的差异点。第一,深度图本身是有噪声的,对棋盘格的角点位置会产生毫米级扰动,建议在一帧内多采集并做时间平均;第二,棋盘格在 ToF 相机下通常不是纯平面,因为深度噪声会让平面看起来"凹凸不平",如果标定板反射率太低、距离太远,角点提取还会失败。我的经验是先拍 RGB 图(很多 ToF 模组带一个 RGB 辅助摄像头)来提取角点,再映射回深度图做对齐。
4.2 ToF 特有的误差源
内参标定只是第一步。ToF 相机最麻烦的是各种系统性误差,这些误差普通相机完全没有概念:
第一个是距离相关误差(也常叫 wiggle 误差)。因为 iToF 解调信号不是完美的正弦波,相位和距离的关系会有周期性偏差,导致测出来的距离随着目标距离呈周期性波动。工程上通常会在出厂前用高精度直线导轨配合反射靶标,在不同距离下采集大量样本,拟合出一条误差补偿曲线,在固件或者算法层做修正。
第二个是反射率误差。同样距离下,白墙反射的光强,黑色吸光物体反射的光弱,iToF 会因为收到的信号幅度不同而产生测距偏差。工程做法是分白、灰、黑几种标准反射率靶标标定补偿系数。
第三个是温度漂移。前面提过的温度补偿,不仅仅是固件的活,很多时候需要在标定环节就记录不同温度下的偏差,生成一张三维补偿表。
第四个是多路径干扰。光在拐角、凹面、镜面上会发生多次反射,最后进入传感器的光会叠加"多绕了一段路"的信号。现代 ToF 芯片越来越多的内置多路径抑制算法,但完全消除做不到,必须在应用层面尽可能规避反射物。
还有一个是"飞点"(flying pixel)。当一个光斑同时照射到前景和背景两个深度差异巨大的物体边界时,传感器会测出一个处于两者之间的不真实距离,表现为深度图边缘出现漂浮的点。这种情况在后处理阶段需要专门过滤。
4.3 多相机系统与手眼标定
当项目里用到多个相机,或者要配合机械臂做引导定位时,只做单相机内参就不够了。
多相机外参标定的任务是计算出不同相机坐标系之间的旋转和平移关系。ToF 相机做多相机外参标定,比较好的做法是把两个深度相机同时对准同一个标定板,分别在各自的重建点云中提取标定板平面和角点,然后求两组坐标系之间的刚体变换。记得采集场景要保证标定板在两边都能被完整看到,不要在广角边缘区域留死角。
手眼标定则分两种:眼在手上(eye-in-hand)和眼在手外(eye-to-hand)。前者的相机装在机械臂末端,跟着机械臂一起动;后者相机固定在外界位置。核心思想都是解 AX=XB 这个方程,用 OpenCV 的 calibrateHandEye 可以直接算。但注意手眼标定对机械臂的运动方式有要求,如果你只是让它随便走几个位置,解算结果会非常不稳定,最好像"先绕固定点旋转、再平移"这样有规划地采集 10~15 组姿态。平面引导项目里经常提到的 9 点标定,本质上是在相机图像坐标和机器人世界坐标之间建立一个仿射映射,适合平面贴合引导这类"够用就好"的工程场景。
5. 数据处理:从裸深度图到干净的点云
5.1 深度图、置信图、幅度图
驱动把原始数据送出来之后,你拿到的通常不只是"一帧深度图",而是同时包含深度图、幅度图/置信图的组合数据。
深度图的每个像素存的是距离值,但不同厂商对 16bit 数据的编码方式不一样。有的直接存毫米值,有的存 1/4 毫米,有的浮点转成了自定义定点格式。如果你直接按 16bit 打印出来看,会发现数值看起来杂乱无章,先搞清楚编码方式非常重要。
幅度图(Amplitude Map)表示每个像素收到的反射光强度。这个图非常有用:它可以帮助你判断哪个像素可信。光强太低的像素(比如黑色物体、远处物体)深度值大概率不可信;光强饱和的像素(比如镜面高光、反光材料)深度结果也不可信。所以我会建议所有 ToF 的上层应用在拿深度值之前,先看一眼幅度图,再做一个基于幅度的置信度掩码。
5.2 点云生成与多路径抑制
深度图本质上是"以相机为原点的距离图像",要变成三维空间中的点,还需要借助内参。对于每个像素 (u, v),已知内参 fx, fy, cx, cy 和深度值 z,反投影公式很简单:
x = (u - cx) * z / fx y = (v - cy) * z / fy
这一组 (x, y, z) 就是相机坐标系下的三维点。补齐全图所有像素,就得到一帧点云。
点云生成不难,难点在预处理。我个人的处理管线是:先做置信度掩码过滤,把幅度过低和过高的像素直接置为零;然后做空域滤波,中值滤波对飞点特别有效;再针对深度突变区域做边缘检测,防止前景和背景之间产生模糊过渡带;最后才把深度图转成点云。如果你的 ToF 芯片支持多路径抑制或者多频率融合,一定要在驱动层把对应开关打开,后处理永远没有在源头纠偏来得干净。
5.3 深度与彩色图像的对齐融合
很多应用场景需要把深度图和 RGB 图融合,比如人脸识别、背景虚化、目标分割。对齐的思路是:已知 RGB 相机和深度相机之间的外参(旋转 R、平移 t)以及各自的内参,把深度图反投影成三维点,再通过外参转换到 RGB 相机坐标系,最后用 RGB 相机内参重投影到彩色图像平面上。这一步看起来简单,实际操作时由于两个相机视差的存在,近距离物体在深度图和彩色图上总会有边缘错位,远近不同的物体错位量还不一样。最好在标定后做一次局部的视差校正,尤其在近距离使用场景,否则人脸轮廓和深度边缘很容易"穿帮"。
6. 上层应用集成:手机、ROS、工业现场的落地
6.1 Android 平台集成
手机和平板上的 ToF 集成,大多数人会用两个途径:系统 Camera2 API 和厂商私有 SDK。
Camera2 API 在 Android 11 以上对深度相机有一些标准支持,比如 DEPTH 输出,但真正好用的还是传感器厂商直接提供的 SDK。以奥比中光、PMD、英飞凌的官方方案为例,一般会提供底层的设备发现、流开启、图像回调、时间戳同步等接口,有的还内嵌了完整的深度后处理算法。实际项目里我会建议直接基于 SDK 的数据流接口做一层自己的包装,把帧同步、曝光控制和后处理管线统一管理起来。
还有一个场景是系统相机自动对焦辅助。今天很多旗舰手机的前置相机之所以能实现快速对焦、背景虚化,就是因为有 CoF 或者接近光传感器帮忙。当你开发这类系统级集成时,需要考虑的不只是拍照效果,还有功耗控制——ToF 传感器和激光器常开会发热,最好设计成按需启动的策略,需要测距时才开。
6.2 ROS 集成
机器人领域用 ToF 相机,基本都是基于 ROS 或者 ROS2。厂商驱动一般会发布深度图话题和点云话题,类型可能是 sensor_msgs/PointCloud2、sensor_msgs/Image。有了点云话题之后,很多导航方案会直接把深度图投影成 2D 激光扫描数据,用 depthimage_to_laserscan 这类工具,让只支持 2D 激光的导航算法也能用上深度相机。
如果你想做视觉惯性里程计或者更精确的位姿估计,IMU 和相机的联合标定是绕不开的一步。Kalibr 是目前最常用的标定工具之一,用 AprilGrid 标定板,同时采集 IMU 数据和图像数据,离线解算出相机内参、IMU 内参以及两者之间的外参和时间延迟。这个标定流程的坑在于:如果你用的是双目或者 ToF 相机,图像同步很关键,时间戳错位超过几毫秒都会让标定结果非常糟糕。
6.3 工业场景与相机选型
工业场景里 ToF 相机目前主要用在机器人引导、物料定位、体积测量、堆叠取放这类"不需要亚毫米精度但需要三维信息"的地方。比如 openpnp 这类贴片机项目里,底部相机识别芯片方向,用普通 2D 工业相机加底光就够了;但如果要识别元件的三维姿态或者高度,才需要考虑引入深度信息。
工业相机选型有一个特别实用的计算公式。已知工作距离 L 和视场宽度 W,可以估算需要的镜头焦距:f = 传感器宽度 * L / W。比如你用的传感器宽度是 6.4mm(1/2.5 英寸级别),工作距离 300mm,想拍到 200mm 宽的视场,焦距就是 6.4 * 300 / 200 = 9.6mm,选 10mm 左右的镜头就对了。反过来,已知焦距也能估算视场角。很多新手选型只盯着分辨率,忽略了传感器尺寸和工作距离,结果镜头视场角根本不够,装上去拍不全目标。
在工业现场接线和配置层面,海康、Basler 这类国产或者进口相机都提供了自己的 SDK 和配置软件。软触发模式下,相机通过软件指令控制拍照;硬触发模式下,用 IO 信号控制。很多"未收到触发信号"的报错,排查顺序一般是:检查触发线接线和电平极性,检查相机触发源设置(上升沿还是下降沿),用示波器确认信号实际上有没有进来,最后再看 SDK 日志。很多时候不是相机坏了,而是信号极性配错了。
7. 实际项目中最容易踩的坑
最后把我这些年做 ToF 项目整理的问题速查表直接放出来,遇到类似情况可以直接按表排查。
| 症状 | 常见原因 | 解决思路 |
|---|---|---|
| 深度图大面积黑色/无信号 | VCSEL 没点亮、曝光太短、目标距离超过量程、滤光片装反 | 先看幅度图;确认激光器状态;延长曝光或增大激光功率 |
| 深度图闪烁、跳变 | 目标反射率太低、曝光不足、环境光过强 | 开 HDR 或多积分时间;检查滤光片;做置信度过滤 |
| 距离整体偏大或偏小 | 标定补偿失效、温度漂移、wiggle 误差未校正 | 重新做距离标定;触发温度补偿表;检查固件版本 |
| 边缘出现大量飞点 | 运动模糊、深度突变、反射率突变 | 加中值/双边滤波;降低帧率中的运动速度;做飞点剔除 |
| 深度图与 RGB 对不上 | 外参标定不准、镜头畸变未校正、视差未补偿 | 重新做多相机标定;检查畸变系数是否更新 |
| GigE 相机丢帧 | 网络带宽不够、巨型帧没开、数据包过大 | 开巨型帧(9000);换千兆网卡;降低分辨率或帧率 |
| 户外强光下效果崩溃 | 环境光太强、滤光片带宽太大 | 换 940nm 激光器;用更窄带宽滤光片;选择抗阳光性能更好的 dToF |
| 物体边缘深度严重偏移 | 多路径干扰、目标形状复杂 | 打开芯片多路径抑制;调整相机角度;在算法层过滤低置信区域 |
| 镜头起雾/激光器衰减 | 模组散热不好、激光器过热 | 增加散热片;检查电流是否超规格;用温度传感器做保护 |
这里我想重点强调一个反直觉的经验:很多深度图质量问题,最后查出来都不是算法的问题,而是光学和物理的问题。比如一个抽屉上方安装的 ToF 相机,深度图上靠近抽屉边缘的地方老是出现一条"凹陷"或"悬浮"带,很多人去调滤波参数调了一周,其实那是抽屉内壁和侧板构成的凹角产生了多路径反射。把相机角度稍微倾斜一点,让反射光不直接回打镜头,问题瞬间就没了。
另外,ESD(静电)问题也值得单独说一句。VCSEL 激光器对静电非常敏感,很多早期项目的返修就是激光器"莫名其妙"不亮了。后来一查全是产线装配时没有做好防静电防护,或者工装没有良好接地。这个在实验室里往往发现不了,但一到量产和小批量交付就会大面积暴露。建议所有硬件联调的工序都做好静电手环和防静电桌面,这一点成本极低,收益却很大。
最后再分享一个更实际的小技巧:无论你用什么品牌的 ToF 相机,开发阶段都尽量同时把深度图、幅度图和 RGB 图(如果有)一起录下来,做成能回放的原始数据包。遇到效果问题,先拿原始数据在电脑上慢慢分析,而不是对着现场反复调参数。很多脏数据或者偶发故障,只有在回放时才看得清楚是驱动丢帧、温度漂移,还是场景光照变化导致的。我吃过的亏告诉我:没有回放数据,你永远是在猜,不是在查。