前一阵给移动底盘做视觉传感器选型,在 Intel RealSense D435i、MYNT EYE S2、ZED Mini 三台双目相机之间来回折腾了将近一个月。三台机器都买了,也都写出了能跑的原型,最后留下来的主力方案是用 D435i。这篇就把三者在传感器原理、SDK、深度质量、标定细节上的差距讲透。你如果正准备做双目相机标定、机械臂抓取或者视觉 SLAM,里面很多坑我已经替你踩完了,照着做能省下不少无效调试时间。
1. 双目相机的核心原理与选型逻辑
1.1 同样是“双目”,技术路线分三种
很多人看产品页以为双目相机都是“两个摄像头做三角测量”,其实市面上常见的双目相机可以分成三类,理解这个区别比对比参数表重要得多。
第一类是主动双目,典型代表是 RealSense D400 系列和 MYNT EYE 各版本。它在两颗灰度相机之间加了一个红外点阵投射器,相当于先给物体表面“盖一层特征”,左右眼再去匹配这些特征点,就能解决白墙、桌面这类低纹理表面匹配不到特征的问题。第二类是被动双目,典型代表是 ZED 系列。它完全依赖环境本身的纹理做立体匹配,不加任何主动光源,功耗低,但弱纹理环境里深度图容易出大面积空洞。第三类是结构光或 ToF,比如老款 Kinect、Orbbec 的一些型号,这类方案虽然也输出深度图,但原理和双目三角测量不一样,通常更怕外界光源干扰,在户外基本很难用。
这三条路线没有绝对优劣,关键看场景。主动双目在室内白墙、桌面这类低纹理表面明显占优,红外点阵一打上去,左右图就能匹配出密集深度;代价是红外投射器会发热、耗电,强阳光下投影基本失效,而且拍标定板时点阵会干扰角点提取。被动双目没有主动光源,能耗低,户外表现稳定,但遇到纯色墙面、镜面、黑乎乎的区域,深度图会直接缺块。结构光和 ToF 短距离精度不错,但多设备互相干扰、室外太阳光淹没信号的问题很常见。所以如果你做的是室内抓取、移动机器人避障,优先考虑主动双目;做室外无人机或自动驾驶,再认真评估被动方案。
1.2 四个选型指标,比参数表更重要
我选型时会列一张打分表,主要看四个维度。
第一是深度范围与精度的匹配度。D435i 官方标称 0.28m 到 10m,MYNT EYE S2 号称可以到 30m,ZED Mini 推荐范围是 0.2m 到 15m 左右。但实际精度都达不到参数表给你的心理预期,尤其是远距离,误差成倍增长。我自己的经验是,在 3m 以内做抓取和避障,这三台机器都够用,超过 5m 就别只看深度相机了,还是激光雷达更可靠。
第二是 SDK 与开发资料的完整度。RealSense 的 librealsense 是开源跨平台的,ROS 包、OpenCV 例子、机械臂案例非常多;MYNT 有自己的 SDK,也有 ROS 1/2 接口,但代码质量和版本迭代速度时快时慢;ZED 的 SDK 功能最强,但闭源且高度依赖 NVIDIA GPU,部署时要多考虑一步。如果你是一个学生或者刚入门,RealSense 的生态会让你少掉很多头发。
第三是 IMU 的同步质量。做 VIO 或 SLAM 时这一点会卡死很多人。三款其实都带 IMU,D435i 用的是 BMI055,MYNT 对 IMU 硬件时间戳的宣传最猛,ZED Mini 也有 IMU,但实际使用体验差异很大。你如果打算做视觉惯性里程计,必须在入手前测试 IMU 数据能不能和图像帧做精确时间戳对齐,而不是简单地各读各的。
第四是价格和供货。RealSense 和 MYNT 在国内都比较好拿,ZED 在国内价格和售后效率有时会让人头疼,而且停产换代的节奏比较随性。买之前还要确认配件能不能买到,后面我会专门说线材和支架的问题。
1.3 价格、配件和长期维护成本
价格方面我只能说个大致的市场行情,因为渠道和汇率变化很快。D435i 一般两千元以内能拿到,MYNT EYE S2 大概在千元到两千元之间,ZED Mini 通常比前两者更贵,接近三千元甚至更高。但买的时候别只盯着机身价格,USB 3.0 高速线、固定支架、散热、供电都要算进预算。
RealSense 原装线比较硬,弯折几次容易出现接触不良;ZED Mini 是 USB-C 接口,转接头质量直接决定带宽是否稳定;MYNT 的线材相对常规,但部分批次存在松动问题。我在实际项目里会额外准备两根高质量的数据线,一根固定使用,一根备用。视觉工程调试时线材断裂或接触不良是最容易被误判成“SDK 问题”的情况,真出了奇怪 bug,先换线往往比翻代码更快。
2. 三款设备逐台拆解:硬件、生态、底层逻辑
2.1 Intel RealSense D435i:主动立体视觉的标准答案
D435i 是 D435 加 IMU 的版本,左右两个红外相机负责深度,中间有一个红外点阵投射器,右侧还有一个 RGB 相机。它的深度流最高支持 1280×720@30fps,也可以跑 640×480@90fps,近距能力不错,最近大概能到 0.28m 左右,配合高分辨率模式可以做桌面级机械臂抓取。
它用的是 UVC 标准接口,在 Linux 下能被识别成标准摄像头设备,因此很多通用工具也认识它。OpenCV 调起 RealSense 的方式很多,可以用rs2::pipeline拿对齐后的彩色加深度流,也可以把左右 IR 图单独拉出来做原始双目实验。它的标定参数出厂时已经写在相机 flash 里,SDK 读取后直接可用,对非专业用户来说体验最友好。网上很多 d435 双目相机指南都会建议新手从这台机器开始,原因就是这个生态太完整了,遇到问题几乎都能搜到现成答案。
但 D435i 也不是没毛病。首先它对 USB 带宽非常敏感,如果把 RGB、深度、IMU 全开,很多 USB 3.0 控制器会直接带宽枯竭,帧率掉到惨不忍睹。解决方法是降低分辨率,或者关闭不需要的流。其次是红外投射器会在某些材质表面反射成条纹状噪声,比如黑色塑料壳、金属拉丝面,深度图会像水波纹一样闪烁。第三是固件升级要谨慎,不要一看到新固件就升级,有时候新固件会改变输出格式或校准参数,导致之前的 ROS 包和上位机代码崩溃。我在项目里一般会锁一个验证过的固件版本,除非有明确功能需求,否则绝不动它。
2.2 MYNT EYE S2:带自研标定的性价比之选
MYNT EYE 是国内公司做的,主打“即插即用”和“硬件级双目加 IMU 融合”。S2 这一代在 S 的基础上升级了传感器,支持 1280×480@40fps 的宽幅深度输出,官方宣称深度范围 0.15m 到 30m。这个数据要打个折扣,但近距离的深度稳定性确实不错。它有主动红外补光,在室内低纹理环境下深度覆盖比被动方案好很多。
MYNT 的调校工作做得比较细,官方提供出厂双目标定和 IMU 标定,SDK 里能直接读出来内外参和时间戳信息。做 VIO 或 ORB-SLAM 这类算法时,想要让图像和 IMU 做紧耦合,最好先用它自带的标定接口重新校准 IMU 零偏和重力对齐。它的 SDK 支持 Windows、Linux 和 ROS 1/2,但版本维护的节奏不算快,在较新的 Ubuntu 版本上,自带的 .deb 包可能装不上,需要手动从源码编译,编译时还会因为 OpenCV 版本冲突报错。遇到这种问题,我的建议是优先查官方 GitHub 的 Issue,不要自己盲目换 OpenCV 版本,因为底层很多接口是按照特定版本写的。
还有一点要注意,MYNT 的 API 更新时会改掉一些回调函数的签名,如果你是从网上抄的旧代码,很可能会因为一个参数类型对不上而编译失败。我的做法是每次拿到新版本 SDK,先编译它的示例代码,确认能过,再往自己的工程里迁。
2.3 ZED Mini:被动立体视觉的“吃配置”选手
ZED Mini 是 Stereolabs 的被动双目相机,双 720p 传感器,视场大概在 85°×54° 左右,标称深度范围 0.2m 到 15m 以上。它没有主动红外投射,功耗很低,发热也小,适合电池敏感的设备,比如无人机或 AR 眼镜。它的 SDK 是最大卖点,能直接输出深度图、点云、3D 网格甚至人体骨架,还能跑物体检测和空间定位,功能集成度非常高。
但这也意味着它对计算资源有硬性要求,Linux 下 ZED SDK 依赖 CUDA 和 NVIDIA GPU,虽然也有 CPU 模式,但实测跑 720p 深度时 CPU 占用和延迟都很大。我曾在 Jetson 上部署过,帧率和深度质量明显缩水,需要花不少时间调模型配置。ZED 的被动方案在室内低纹理表面确实薄弱,我用它在白墙前做测试,深度图直接缺了一块,只能靠周围平面拟合补洞。如果你要做产品级抓取或避障,优先考虑主动光方案会更省心。
另外它的 SDK 升级频繁,每次升级都可能改变 API 接口和模型格式。项目中期升级 SDK 是一件风险很高的事情,我就遇到过升级后已有的检测模型加载失败、参数全部要重调的情况。比较好的做法是从一开始就锁定一个 LTS 版本,把依赖版本记清楚,没有必须需求不要动。
2.4 三款相机规格横向对照表
| 项目 | RealSense D435i | MYNT EYE S2 | ZED Mini |
|---|---|---|---|
| 深度原理 | 主动红外双目 | 主动红外双目 | 被动可见光双目 |
| 核心分辨率 | 1280×720@30fps | 1280×480@40fps | 720p 双传感器 |
| 最近深度 | 约 0.28m | 约 0.15m | 约 0.2m |
| 可信深度范围(经验值) | 0.3m-6m | 0.2m-8m | 0.5m-8m |
| RGB 相机 | 有 | 有 | 有 |
| IMU | 有 | 有 | 有 |
| SDK 开放度 | 开源 | 部分开源 | 闭源 |
| GPU 强依赖 | 否 | 否 | 强依赖 CUDA |
| 出厂标定 | 有,可读 | 有,接口丰富 | 有 |
| 价格区间 | 中 | 较低 | 较高 |
| 适合场景 | 室内/抓取/ROS | 室内外/教学 | 高端应用/GPU平台 |
这张表把官方标称值和我个人的实测体验放在一起了。注意“可信深度范围”是把误差控制在可接受范围内的保守估计,小于官方极限值。实际使用会受光照、材质、曝光参数影响,只能当参考基线。
3. 实测对比:透镜前的物理世界比参数表更诚实
3.1 室内正常光照下的深度质量
我在室内把一个 0.6m 高的物体放在距离相机 1m、2m、3m 的位置,分别用三台相机采集深度,观察物体表面的深度连续性和边缘毛刺情况。结果是 D435i 和 MYNT 在 1m 到 2m 范围内表现非常接近,主动红外让物体表面基本被覆盖,深度边缘略有锯齿,但整体可用。ZED Mini 在纹理丰富的桌面、键盘、纸箱上表现也不错,但到了纯色纸袋上会出现成片“黑洞”,边缘伴随明显的错误深度块。
如果要做机械臂抓取,我更愿意用主动双目方案,因为抓取前需要给物体一个完整的点云轮廓,空洞太多会严重影响位姿估计。我还对比了 640×480 分辨率下的最大帧率,RealSense 能到 90fps,ZED Mini 能到 100fps,MYNT S2 的帧率上限相对低一些。高帧率对高速运动的机械臂反馈很有用,但普通抓取场景 30fps 已经绰绰有余,帧率太高反而会拖垮点云生成和位姿解算的 CPU 占用。
3.2 户外强光与长距离下的表现反转
户外是主动双目最头疼的场合。D435i 的红外投影在太阳底下基本是“隐形”的,深度质量会下降到和被动方案几乎一样,甚至因为自动曝光问题产生更多噪声。MYNT 也是这样,毕竟都是主动红外方案,强光会把投射器的点阵信号淹没。这时候被动双目 ZED Mini 反而更稳定,只要有足够的自然纹理,它在 3m 到 8m 范围内的深度图都比较扎实。所以做室外无人机、室外移动机器人的人,如果预算允许,优先考虑被动双目,或者直接融合激光雷达。
不过 ZED 在户外也怕逆光。大逆光下两个传感器一起过曝,暗部细节全部丢失,深度图一样崩溃。解决办法是开启自动曝光并锁定合理范围,或者调整安装角度避免镜头正对太阳。不管哪台相机,户外测试前先把手动曝光和自动曝光切换各跑一遍,因为有些固件在自动曝光时会缓慢漂移,导致深度值周期性抖动,这种问题在软件后处理阶段很难消除。
3.3 RealSense D435i 机械臂实战:从深度图到抓取坐标
我搭的机械臂抓取项目流程是:相机固定在机械臂正上方的支架上,目标物体放在工作台固定区域。代码侧先用 RealSense 的rs2::align把深度图对齐到彩色图,然后用 OpenCV 做颜色阈值分割或者跑一个轻量级 YOLO 模型检测目标,拿到目标框后取中心区域的深度值,再结合相机内参反投影出三维坐标。公式很简单,就是经典的针孔模型:
x = (u - cx) * depth / fx y = (v - cy) * depth / fy z = depth接着把坐标从相机坐标系变换到机械臂基座坐标系,这一步靠手眼标定得到的外参矩阵完成,我用的是easy_handeye套件。整体流程跑通后,机械臂能稳定抓取不同尺寸的积木块,定位误差在 1cm 以内。
这里有个关键经验:不要直接拿深度图中心像素的原始值作为抓取点,因为物体边缘、高光、阴影都会让单个像素深度值突变。我会对目标框内 5×5 邻域做中值滤波,再计算标准差,如果标准差超过阈值就认为是可疑区域,放弃当前点,等机械臂换个角度重新检测。这个“深度置信度过滤”的思路比单纯调参数实用得多,也是我在多台双目相机上验证过的经验。
3.4 白墙与弱纹理场景:谁是真正的“瞎子”
白墙测试能直接暴露相机的本质。D435i 和 MYNT 打开红外补光后,白墙表面被点阵覆盖,深度图能完整出墙,虽然点间距偏大,但整体连续。ZED Mini 在白墙前基本绝望,左右图没有任何可匹配的特征,深度图全是默认值。有人会尝试调低置信度阈值强行出深度,相信我,出来的全是噪声。如果你需要在白墙、传送带、桌面这类弱纹理环境运行,别买被动双目,哪怕主动双目也有点阵投影器寿命问题,至少它能给出可用数据。
镜面和窗户这类高反光表面,无论主动还是被动双目都很难正确处理,反射会造成视差欺骗,深度值会跳成背景距离。各家的后处理滤波能稍微平滑一下,但本质问题无法解决。项目里遇到透明或高反光物体,我建议别在深度图上死磕,改成 RGB 加先验尺寸或单目检测更靠谱,或者换更高端的结构光方案。
4. 双目相机标定与软件集成的完整实操
4.1 出厂标定到底靠不靠谱
很多新手会问:相机不是出厂标定好了吗,为什么还要自己标?这三款相机出厂确实会写入左右目内参、畸变系数和相对外参,RealSense 和 MYNT 还做了工厂级标定,大多数情况下直接用没问题。但如果你做的项目对深度精度要求高,比如机械臂高精度抓取、三维重建,或者相机受过撞击、换过镜头,出厂值就不一定准了。
另外,出厂标定代表的是“出厂那一刻”的状态,运输振动、温度变化、镜头轻微移位都会影响标定结果。我在每次重要项目开始前会做一次快速校验,方法是拍摄棋盘格,用 OpenCV 标定后对比得到的内参和出厂值,如果焦距偏差超过 1% 左右,就重新标定一遍。对比的方法很简单,用修改过的官方库导出相机内外参,再和自己算的结果放在同一个表格里看差距。
4.2 什么时候需要重新标定
我总结了几种必须重新标定的情况。第一,左右目图像视觉外参漂移,表现是深度图上同一物体的边缘出现“重影”或“彩边”。第二,相机从较高处跌落或者固定支架螺丝松过。第三,更换了镜头型号或镜头保护玻璃。第四,红外补光强度变化导致左右目曝光差异明显,需要重新调整增益。
标定工具方面,RealSense 官方提供动态标定工具rs-calibration,MYNT 也有一套标定工具,ZED 的官方标定工具是闭源的,普通用户很难精确操作。实际操作中我用 OpenCV 配合棋盘格做双目标定最多,因为对硬件平台不挑剔,而且容易和现有 ROS 管线和 Python 工具链集成。
4.3 剔除不合格角点:标定速度和精度的分水岭
双目标定最核心的操作就是“采集标定板图像、提取角点、求解内外参”。很多人拍到几十张图直接喂给cv2.calibrateCamera,发现重投影误差高达几个像素,结果就是深度图发飘。这里分享一个非常实用的经验:在喂给标定函数之前,一定要剔除不合格角点。
什么是不合格角点?第一,被遮住的角点,比如棋盘格边缘有物体挡住,算法会强行补出来;第二,严重失真的角点,棋盘格在图像边缘因为镜头畸变变得扭曲,角点亚像素提取不稳定;第三,亮度不均造成的伪角点,反光、阴影、红外点阵干扰时,findChessboardCorners可能把高光边界误认为角点;第四,同一组图中重投影误差明显大于其他图的帧。
我的做法是写一个筛选脚本,对每张标定图做一次单独标定或者直接全局标定后,打印每一帧的 RMS 误差,把 RMS 超过 0.1px 的帧挑出来删除,再看整体趋势。还有一个更直觉的方法:把检测到的角点画在图像上,人工滚动看几秒。别嫌麻烦,标定图质量直接决定最终内外参精度,省这一步后面要花更多时间填深度图的坑。
采集标定板时不要只拍一个区域的平移版本,要让标定板在画面里不断旋转、倾斜、移动到各个角落,保证每个图像区域都有足够样本。我通常拍 20 到 40 张,如果超过四分之一不合格,就会重拍一轮。角点筛选做得好,重投影误差能从 0.2px 降到 0.05px 以下,在 3D 重建和机械臂抓取里就是几个毫米的误差,非常值。
4.4 三种主流集成方式:ROS、OpenCV、厂商 SDK
ROS 方式是目前最通用的。RealSense 在 ROS 下直接用realsense2_camera包,launch 后就会发布/camera/color/image_raw、/camera/depth/image_rect_raw、/camera/imu等话题。MYNT 有mynt_eye_ros_wrapper,但版本要和 SDK 版本匹配,不然 CMakeLists 要改。ZED 有zed-ros-wrapper,依赖 ZED SDK 和 CUDA,如果机器上已经部署了其他深度学习的 CUDA 环境,要小心版本冲突。一个简化的启动示例如下:
roslaunch realsense2_camera rs_camera.launch rosrun mynt_eye_ros_wrapper mynteye_wrapper_node roslaunch zed_wrapper zed_camera.launchOpenCV 方式适合离线标定或要接入第三方相机。只要能把左右目原始图像读出来,就能自己用cv2.stereoCalibrate或cv2.stereoRectify建一套标定流程。缺点是要自己处理很多细节,效率不如官方 SDK,但灵活性最高。下面是一个常用的角点提取片段,结合前面说的筛选逻辑,效果很好:
import cv2 ret, corners = cv2.findChessboardCorners(gray, (cols, rows), None) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) corners = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)厂商 SDK 方式是整个生态里体验最完整的。RealSense 的 librealsense、MYNT SDK、ZED SDK 都封装好了深度对齐、时间戳同步、后处理滤波等常见功能。我实测下来,RealSense 的 SDK 文档最友好,MYNT 的时间戳接口最直白,ZED 的功能最丰富但闭源可定制性差。你的项目如果对开发效率要求高,用厂商 SDK 是正解;想深度定制算法,再回到底层图像自己搞定。
4.5 手眼标定与坐标变换的注意事项
机械臂抓取里,手眼标定是一个绕不开的坑。如果相机固定在机械臂外部,属于眼在手外;固定在机械臂末端,属于眼在手上。我用的easy_handeye套件,在 ROS 下可以自动采集多组机械臂位姿和标定板位姿,然后求解相机坐标系到机械臂基座坐标系的变换。注意采集时要让机械臂走不同姿态,而不是只在一个位置附近转,否则方程会退化,解出来的外参矩阵特别不稳定。
标定完成后,验证步骤不能省。我会拿一个已知尺寸的物体放在工作台上,通过相机算它的三维坐标,再让机械臂去触碰同一个位置,比较误差。如果误差在可接受范围内,外参基本靠谱;如果差得远,检查标定板角点筛选去掉的帧是不是太多,或者机械臂标定过程中有没有震动。整体流程不复杂,但每一步的细节都会影响最终精度。
5. 常见问题排查与避坑技巧
5.1 RealSense 高频问题:USB 带宽、固件、自动曝光
USB 带宽不足导致帧率掉一半的案例非常多。多流开启后,帧率突然骤降通常就是带宽问题。解决顺序是:关闭 RGB 流,只保留深度和 IMU;把深度分辨率降到 640×480;换一根屏蔽良好的 USB 3.0 线;插在主板的直连接口上,尽量不要走扩展坞或前置面板。我遇到过 USB 延长线导致设备反复掉线的情况,最后换成带供电的工业级 USB Hub 才稳定。
固件方面,升级前一定看 release notes,升级后立刻运行rs-enumerate-devices检查标定参数和序列号。自动曝光导致深度漂移也是常见问题,可以尝试锁定曝光参数,或者设置曝光上限,然后观察深度值是否稳定。对于静止场景,固定曝光是最可靠的选择,动态场景再考虑自动曝光加事后滤波。
5.2 MYNT EYE 高频问题:驱动兼容与时间戳同步
MYNT 的 Linux 驱动有两个常见坑。一是某些内核版本下 UVC 设备枚举不稳定,插上设备后系统识别不到;二是 SDK 里 IMU 回调时间戳的默认单位或坐标轴方向和预期不一致。遇到识别不到先看 dmesg,确认设备是否被系统挂载,再看/dev/video*是否存在。时间戳问题建议写个小测试程序,打点对比图像帧和 IMU 帧的数量与时间间隔,确定是否需要对时。MYNT 官方 FAQ 也提到,ROS 下要配置device_serial_number,避免同时插多台设备时数据串掉。
5.3 ZED Mini 高频问题:GPU 依赖、闪烁、SDK 版本
ZED Mini 在 Linux 上没有 NVIDIA GPU 也能跑 CPU 模式,但深度图和感知功能的帧率会非常难看。如果要在 Jetson 上部署,注意使用和 JetPack 版本匹配的 ZED SDK,否则会出现加载模型失败或 API 不存在的问题。另一个问题是深度图闪烁,尤其自动曝光开启时比较明显,原因是左右目曝光不一致导致匹配不稳定。解决方案是打开zed_config里的自定义曝光,把左右目曝光时间同步固定。
5.4 问题速查总表
| 症状 | 可能原因 | 快速解决 |
|---|---|---|
| 深度图大面积缺失 | 弱纹理或高反光 | 换主动双目或调低置信度阈值 |
| 点云出现“飞点” | 边缘遮挡或噪声 | 开启空间滤波和时间滤波 |
| 帧率骤降 | USB带宽不足 | 关闭 RGB 流、降低分辨率 |
| IMU 频率不对 | 时间戳不同步 | 检查 SDK 版本,设置正确时基 |
| 标定重投影误差大 | 不合格角点未剔除 | 删除异常帧,重新采集 |
| ZED 深度闪烁 | 左右目曝光不一致 | 锁定曝光参数 |
这张表是我把半年多踩坑经历浓缩出来的。很多问题表面上像硬件故障,最后查下来只是带宽、曝光或版本不匹配。遇到相机输出异常,先按这个顺序排查环境,再怀疑硬件,效率最高。
三台相机我最后主力用了 D435i,不是因为它最完美,而是因为它的生态让我能把大部分精力放在算法而不是相机驱动上。ZED Mini 更适合有 GPU 开发板、需要炫酷功能的项目,MYNT EYE 则更适合预算有限但又需要主动光学和 IMU 同步的学生团队。如果你正在纠结选型,我的建议是先确定核心场景是室内还是室外、是否需要主动补光、底层开发量有多大。双目相机的世界里没有万金油,找到那个“够用且顺手”的,比追求最强参数更重要。