- 前言:这篇文章想解决什么问题
- 先用一句话理解深度相机
- D435i 是什么:它不是普通摄像头
- 深度到底是怎么测出来的
- D435i 常用公开规格速查
- FOV 是什么:视场角不是画面大小那么简单
- 裁剪后的 FOV 怎么算
- 深度图、彩色图、点云:它们分别是什么
- 从一个像素恢复三维坐标
- D435i 的 IMU 是干什么的
- 安装与快速上手
- 机器人里常见的使用方式
- D435i 使用中最容易踩的坑
- 如何为机器人项目选择分辨率、帧率和安装位置
- 常用术语表
- 参考资料
前言:这篇文章想解决什么问题
我之前对深度相机也不是很熟,总觉得“深度图”“点云”“FOV”“裁剪后 FOV”“双目”“红外”“IMU”这些词混在一起很容易晕。尤其是 Intel RealSense D435i 这种相机,在机器人上很常见,但是如果只看参数表,其实不太容易建立直觉。
所以这篇文章按零基础来写,目标是:
- 先知道 D435i 是怎么“看见距离”的。
- 知道 FOV 是什么,为什么机器人安装时一定要关心 FOV。
- 会计算裁剪后的 FOV,避免“我把图像裁小了,视场角到底变多少”的困惑。
- 能用 Python / ROS2 读到深度图、彩色图、点云。
- 知道实际使用中哪些地方最容易出问题。
先用一句话理解深度相机
普通相机只能告诉你“这个像素是什么颜色”;深度相机还能告诉你“这个像素对应的物体离相机有多远”。
也就是说,普通 RGB 图像大概是这样:
像素 (u, v) → R、G、B 颜色 |
深度图则是这样:
像素 (u, v) → 距离 Z,例如 1.25 m |
如果再结合相机内参,就能从一个像素恢复出三维坐标:
像素 (u, v) + 深度 Z → 相机坐标系下的 3D 点 (X, Y, Z) |
这就是机器人为什么喜欢用深度相机:它不只是“看见画面”,还可以估计空间结构。
D435i 是什么:它不是普通摄像头
Intel RealSense D435i 是 D400 系列里很常见的一款深度相机。它可以输出:
- 深度图 Depth Image
- 红外图 Infrared Image
- 彩色图 RGB Image
- IMU 数据,也就是加速度计和陀螺仪数据
- 点云 Point Cloud,通常由 SDK 或 ROS 节点根据深度图计算出来
D435i 上面大概有哪些传感器
从功能上理解,可以把 D435i 看成几个模块组合在一起:
| 模块 | 作用 | 直观理解 |
|---|---|---|
| 左红外相机 | 拍红外图 | 左眼 |
| 右红外相机 | 拍红外图 | 右眼 |
| 红外投射器 | 往环境里投射红外纹理 | 给白墙/弱纹理物体“打花纹” |
| RGB 相机 | 拍普通彩色图 | 普通摄像头 |
| IMU | 输出加速度和角速度 | 感知相机自身运动 |
这里最核心的是两个红外相机。D435i 的深度主要靠它们形成的双目系统算出来。
D435i 和普通 RGB 摄像头最大的区别
普通 RGB 摄像头面对一张白墙时,只能看到一整片白色,很难知道墙离自己多远。
D435i 会用红外投射器给环境打出人眼看不见的红外纹理。这样,左红外相机和右红外相机就能在纹理中寻找对应点,再通过左右图像里的位置差计算距离。
这就是“主动双目”的意思:
- 双目:有两个相机,像两只眼睛。
- 主动:主动发射红外纹理,帮助匹配。
深度到底是怎么测出来的
普通双目:模仿人的两只眼睛
我们闭上一只眼睛,再换另一只眼睛看同一个近处物体,会发现物体在视野里的位置发生了变化。物体越近,左右眼看到的位置差越明显;物体越远,位置差越小。
双目深度相机也是类似原理。
左相机看到点 P 在左图的 u_left |
主动双目:D435i 会主动打出红外纹理
纯双目有一个问题:如果场景没有纹理,就不好找对应点。比如白墙、纯色桌面、黑色塑料件,都可能让匹配变难。
D435i 的红外投射器会投射红外纹理,这样左右红外相机就更容易匹配同一个空间点。
需要注意:
- 红外纹理人眼通常看不见。
- 阳光里也有强红外成分,所以户外强光下深度质量可能变差。
- 透明玻璃、镜面、高反光、纯黑吸光材料,仍然可能不好测。
一个极简公式:视差越大,距离越近
双目测距最核心的关系可以简化为:
Z = f × B / d |
其中:
| 符号 | 含义 |
|---|---|
| Z | 深度,也就是距离 |
| f | 焦距,单位通常是像素 |
| B | 左右相机之间的距离,叫 baseline 基线 |
| d | 视差 disparity |
这个公式不需要一开始就死记,只要记住:
视差 d 越大,距离 Z 越小;视差 d 越小,距离 Z 越大。
也就是说,近处物体在左右相机里“错开得更多”,远处物体“错开得更少”。
D435i 不是 ToF 相机
深度相机常见路线有几种:
| 技术路线 | 大概原理 | 代表 |
|---|---|---|
| 双目 Stereo | 两个相机看同一个点,用视差算距离 | RealSense D4xx 系列 |
| 主动双目 Active Stereo | 双目 + 红外投射纹理 | D435i |
| ToF Time-of-Flight | 发光并测光飞行时间/相位差 | 一些 ToF 深度相机 |
| 结构光 Structured Light | 投射已知图案,看图案变形 | 早期 Kinect 类设备 |
D435i 更接近“主动双目”,不是 ToF。这个区别很重要,因为它决定了它的优缺点:
- 优点:近距离、室内、机器人视觉很常用;可以输出较高分辨率深度图。
- 缺点:强阳光、透明/反光/低纹理物体、重复纹理场景可能出问题。
D435i 常用公开规格速查
下面列的是 D435i 常用公开规格,实际项目中建议以 Intel RealSense 官方产品页和 D400 系列 datasheet 为准。
| 项目 | 常见公开规格/说明 |
|---|---|
| 深度技术 | Active IR Stereo,主动红外双目 |
| 深度 FOV | 约 87° × 58°,对角约 95° |
| RGB FOV | 约 69° × 42°,对角约 77° |
| 深度分辨率 | 常见 848×480、640×480、1280×720 等 |
| 深度帧率 | 常见 30 fps;部分模式可到更高帧率 |
| RGB 分辨率 | 常见最高 1920×1080 |
| RGB 帧率 | 常见 30 fps |
| 深度测量范围 | 与模式、光照、目标材质有关;常见机器人应用多在近中距离使用 |
| IMU | 加速度计 + 陀螺仪 |
| 接口 | USB |
这里不要把“最大能测多远”理解成永远可靠。深度相机的距离质量和很多因素有关:
- 目标表面有没有纹理。
- 光照是不是太强。
- 目标是不是透明/反光/纯黑。
- 相机是否稳定安装。
- 分辨率、曝光、激光功率、滤波参数是否合适。
FOV 是什么:视场角不是画面大小那么简单
FOV 是 Field of View,中文通常叫视场角。
可以把 FOV 理解成相机“张开眼睛”的角度。FOV 越大,同样距离下看到的范围越宽;FOV 越小,画面越像长焦镜头,看到的范围更窄。
水平 FOV、垂直 FOV、对角 FOV
| 名称 | 英文 | 含义 |
|---|---|---|
| 水平 FOV | HFOV | 左右方向能看到多宽 |
| 垂直 FOV | VFOV | 上下方向能看到多高 |
| 对角 FOV | DFOV | 对角线方向能看到多大角度 |
机器人上最常用的是水平 FOV 和垂直 FOV:
- 水平 FOV:决定机器人左右能看到多宽。
- 垂直 FOV:决定机器人上下能看到多少地面/障碍物。
D435i 常见 FOV 数值
D435i 深度相机部分常见 FOV 大约是:
深度 HFOV ≈ 87° |
RGB 相机常见 FOV 大约是:
RGB HFOV ≈ 69° |
注意:深度相机和 RGB 相机的 FOV 不一样,所以彩色图和深度图不是天然完全重合的。SDK 里的 align 功能就是用来把深度对齐到彩色,或者把彩色对齐到深度。
FOV 与距离的关系:1 米外能看到多宽
假设水平 FOV 是 87°,物体距离相机 1 米,那么画面在 1 米处能覆盖的宽度大约是:
width = 2 × distance × tan(HFOV / 2) |
代入:
width = 2 × 1.0 × tan(87° / 2) |
也就是说,如果 D435i 对着前方,在 1 米远的平面上,深度画面横向大概能覆盖约 1.9 米宽。
同理,垂直方向:
height = 2 × 1.0 × tan(58° / 2) |
这对机器人安装非常有用。例如你把相机装在机器人胸前,希望看到地面、台阶、前方障碍物,就要估算不同距离下画面能覆盖多大范围。
裁剪后的 FOV 怎么算
这是很多人容易搞错的地方。
假设原始图像是 848×480,水平 FOV 是 87°。如果我只取中间 424 像素宽,也就是宽度裁掉一半,新的水平 FOV 是不是 87° 的一半,也就是 43.5°?
不是。
因为 FOV 是角度,图像宽度和角度之间不是线性关系,而是通过 tan() 联系起来。
为什么不能简单地用比例乘 FOV
相机成像可以近似看成针孔模型:
图像半宽 / 焦距 = tan(水平 FOV / 2) |
如果只取图像中间一部分,变的是“图像半宽”,而不是直接线性缩放角度。
中心裁剪 FOV 公式
如果是中心裁剪,公式是:
FOV_crop = 2 × atan( crop_size / full_size × tan(FOV_full / 2) ) |
水平裁剪用宽度:
HFOV_crop = 2 × atan( crop_width / full_width × tan(HFOV_full / 2) ) |
垂直裁剪用高度:
VFOV_crop = 2 × atan( crop_height / full_height × tan(VFOV_full / 2) ) |
这里的角度计算要注意:很多编程语言的 sin/cos/tan/atan 默认用弧度,不是角度。
例子 1:848×480 裁成 424×240
假设深度原始 FOV 是:
HFOV_full = 87° |
中心裁剪成:
crop_width = 424 |
那么:
HFOV_crop = 2 × atan(424 / 848 × tan(87° / 2)) |
VFOV_crop = 2 × atan(240 / 480 × tan(58° / 2)) |
所以裁剪一半宽度后,水平 FOV 不是 43.5°,而是约 50.9°。
为什么比 43.5° 大?因为 tan() 是非线性的。
例子 2:只裁掉左右边缘,高度不变
如果原始 848×480,只取中间 640×480:
crop_width = 640 |
那么水平 FOV 会变小,垂直 FOV 不变:
HFOV_crop ≈ 71.6° |
这在机器人里很常见:
- 左右边缘畸变大,裁掉一点。
- 只关心前方区域,裁掉左右不可靠区域。
- 为了加速算法,只处理中间 ROI。
Python 小工具:输入分辨率自动算裁剪 FOV
import math |
输出大概类似:
HFOV crop: 50.88 |
深度图、彩色图、点云:它们分别是什么
深度图
深度图看起来像一张灰度图,但它每个像素保存的是距离,而不是颜色。
例如:
depth[240, 424] = 1.23 |
表示图像中 (u=424, v=240) 这个像素对应的空间点距离相机大约 1.23 米。
实际 SDK 里常见单位可能是毫米、米,或者需要乘一个 depth_scale 才能转成米。这个一定要检查。
彩色图
彩色图就是普通 RGB 图像:
color[240, 424] = [R, G, B] |
彩色图可以用来做目标检测、语义分割、二维码识别、物体识别等。
点云
点云是很多三维点的集合:
P1 = (X1, Y1, Z1) |
如果每个点还带颜色,就是彩色点云:
P1 = (X1, Y1, Z1, R1, G1, B1) |
机器人常用点云做:
- 障碍物检测
- 地面拟合
- 体素地图
- SLAM
- 手眼标定
- 目标定位
从一个像素恢复三维坐标
深度相机输出的是每个像素的深度 Z。要得到 X、Y,还需要相机内参:
| 参数 | 含义 |
|---|---|
| fx | x 方向焦距,单位 pixel |
| fy | y 方向焦距,单位 pixel |
| cx | 主点 x 坐标 |
| cy | 主点 y 坐标 |
针孔模型公式:
X = (u - cx) × Z / fx |
Python 示例:
def pixel_to_3d(u, v, depth_m, fx, fy, cx, cy): |
如果 (u, v) 正好是主点 (cx, cy),那么 X 和 Y 就是 0,表示这个点在相机正前方。
D435i 的 IMU 是干什么的
D435i 比 D435 多了 IMU。IMU 一般包括:
- 加速度计 accelerometer
- 陀螺仪 gyroscope
它可以告诉你相机自身的运动趋势,比如:
- 有没有震动
- 有没有旋转
- 朝哪个方向加速
- 相机姿态变化大不大
但是要注意:
IMU 不直接产生深度图。
深度还是双目算出来的。IMU 常用于辅助:
- VIO:视觉惯性里程计
- SLAM:建图定位
- 时间同步
- 机器人运动补偿
- 判断相机是否剧烈抖动
安装与快速上手
方式一:使用 RealSense Viewer
RealSense Viewer 是最适合入门的工具。你可以直接看到:
- 彩色图
- 深度图
- 红外图
- 点云
- 相机内参/外参
- 曝光、激光功率等参数
入门建议:
- 插上 D435i。
- 打开 RealSense Viewer。
- 打开 Stereo Module。
- 打开 RGB Camera。
- 看 Depth 图是否稳定。
- 切换 2D / 3D 点云视图。
- 用手靠近/远离相机,看深度颜色变化。
如果 Viewer 里能正常显示,说明硬件和驱动基本 OK。
方式二:Python 读取深度和彩色图
安装 Python 包通常可以用:
pip install pyrealsense2 opencv-python numpy |
最小示例:读取中心点深度。
import pyrealsense2 as rs |
方式三:ROS2 中使用 D435i
ROS2 中常用 realsense2_camera 驱动。不同系统安装方式可能不同,大致思路是:
sudo apt install ros-humble-realsense2-camera |
启动示例:
ros2 launch realsense2_camera rs_launch.py \ |
查看话题:
ros2 topic list | grep camera |
常见话题可能包括:
/camera/camera/depth/image_rect_raw |
具体话题名会受 namespace、驱动版本、launch 参数影响。
机器人里常见的使用方式
例子 1:前方障碍物距离检测
最简单的避障思路:只看画面中间区域的深度,如果最近距离小于阈值,就认为前方有障碍物。
import numpy as np |
为什么用 5% 分位数,而不是最小值?
因为深度图里偶尔会有噪点。如果直接取最小值,一个坏点就可能让机器人误刹车。
例子 2:只看画面中间一块区域
假设原始深度是 848×480,我们只想看中间 424×240:
def center_crop(img, crop_w, crop_h): |
这时要记得:算法实际看到的 FOV 已经变小了。可以用前面的公式算:
848×480 → 424×240 |
也就是说,你的算法不是在看原来的 87°×58°,而是在看中间约 50.9°×31.0°。
例子 3:把深度图变成点云用于避障
RealSense SDK 可以生成点云。概念上,每个深度像素都可以变成一个 3D 点:
import pyrealsense2 as rs |
点云很直观,但也更吃算力。机器人上常见做法是:
- 降采样,比如体素滤波。
- 只保留前方 ROI。
- 只保留一定高度范围。
- 转成 2D costmap 或 occupancy grid。
D435i 使用中最容易踩的坑
1. USB 带宽不够
高分辨率 + 高帧率 + 彩色 + 深度 + 点云,会占用较大 USB 带宽。如果插到 USB2.0 或 Hub 不稳定,可能出现掉帧、启动失败、图像卡顿。
建议:
- 尽量用 USB3。
- 不要和其他大带宽设备共用不靠谱的 Hub。
- 机器人上用短一点、质量好一点的线。
2. 强光下深度质量变差
D435i 依赖红外图像匹配。户外强阳光可能影响红外图质量。
表现:
- 深度空洞变多。
- 距离跳动。
- 远处深度不稳定。
3. 玻璃、镜面、黑色物体不好测
透明、反光、吸光材料都是深度相机的难点。
例如:
- 玻璃门
- 镜子
- 黑色塑料外壳
- 金属反光面
- 水面
机器人避障时不能完全依赖深度相机,最好和激光雷达、碰撞检测、超声波、结构安全策略一起使用。
4. RGB 和 Depth 没有对齐
RGB 相机和深度相机物理位置不同,FOV 也不同。所以同一个物体在 RGB 图和深度图里不是天然一一对应。
如果你做目标检测,然后想取目标框里的深度,通常需要做 align:
align = rs.align(rs.stream.color) |
这样深度图会对齐到彩色图坐标系,便于“检测框取深度”。
5. 没有理解 depth_scale
很多深度图 raw value 不是直接的米。要用 depth_scale 转换。
depth_m = raw_depth * depth_scale |
如果忘了乘 scale,距离就会完全不对。
6. 边缘区域深度更不稳定
镜头边缘畸变和匹配误差通常更明显。如果算法只关心前方障碍物,可以考虑只用中间区域,并重新计算裁剪后的 FOV。
7. 相机安装角度不合适
装在机器人上时,相机朝向很关键。
如果装得太平:
- 看不到近处地面。
- 台阶/低矮障碍物可能太晚发现。
如果俯仰角太大:
- 远处前方看不到。
- 地面占据画面太多。
建议先画一个侧视图,估算相机高度、俯仰角、垂直 FOV、最近/最远关注距离。
如何为机器人项目选择分辨率、帧率和安装位置
分辨率怎么选
| 需求 | 建议 |
|---|---|
| 快速避障 | 可以先用 640×480 或 848×480 |
| 近距离精细识别 | 可以尝试更高分辨率 |
| 算力紧张 | 降低分辨率,裁剪 ROI |
| 需要点云 | 注意点云点数和 CPU/GPU 负载 |
不要一开始就追求最高分辨率。机器人上更重要的是稳定、低延迟、抗干扰。
帧率怎么选
| 场景 | 建议 |
|---|---|
| 慢速移动机器人 | 15~30 fps 通常够用 |
| 快速运动/机械臂避障 | 尽量提高帧率,降低延迟 |
| 只做静态测量 | 低帧率也可以 |
安装位置怎么想
安装前可以问自己几个问题:
- 我最关心的障碍物距离是 0.3m、1m 还是 3m?
- 机器人速度多快?需要提前多远发现障碍?
- 相机要看地面、前方、还是操作对象?
- 会不会被机器人本体挡住?
- 会不会被震动影响?
- 线缆是否牢固?
- 户外阳光是否很强?
如果是四足/轮足机器人前向避障,常见思路是:
- 相机装在机身前方。
- 轻微向下俯视,兼顾前方和地面。
- 中间 ROI 做快速避障。
- 点云或深度图送入局部地图。
- 与机器人本体碰撞模型一起做安全判断。
常用术语表
| 术语 | 中文 | 解释 |
|---|---|---|
| Depth | 深度 | 物体到相机的距离 |
| Depth Image | 深度图 | 每个像素存一个距离 |
| RGB Image | 彩色图 | 普通相机图像 |
| IR Image | 红外图 | 红外相机看到的图像 |
| Stereo | 双目 | 两个相机通过视差测距 |
| Active Stereo | 主动双目 | 双目 + 主动红外纹理 |
| Disparity | 视差 | 同一点在左右图像中的位置差 |
| Baseline | 基线 | 左右相机之间的距离 |
| FOV | 视场角 | 相机能看到的角度范围 |
| HFOV | 水平视场角 | 左右方向的视场角 |
| VFOV | 垂直视场角 | 上下方向的视场角 |
| ROI | 感兴趣区域 | 只处理图像中的一块区域 |
| Point Cloud | 点云 | 很多三维点组成的数据 |
| Intrinsics | 内参 | fx、fy、cx、cy 等相机内部参数 |
| Extrinsics | 外参 | 两个坐标系之间的位置和姿态关系 |
| IMU | 惯性测量单元 | 加速度计 + 陀螺仪 |
参考资料
- Intel RealSense D435i 产品页:https://www.intelrealsense.com/depth-camera-d435i/
- Intel RealSense D400 Series Product Family Datasheet:https://dev.intelrealsense.com/docs/intel-realsense-d400-series-product-family-datasheet
- Intel RealSense SDK 2.0 GitHub:https://github.com/IntelRealSense/librealsense
- ROS realsense2_camera:https://github.com/IntelRealSense/realsense-ros
- OpenCV 相机模型与标定文档:https://docs.opencv.org/
本文中的 D435i FOV 等数值用于学习和工程估算,实际项目请以你手头设备、固件、SDK 读取到的内参和 Intel 官方 datasheet 为准。对于裁剪后的 FOV,最稳妥的方法是读取真实内参,或者用本文公式根据当前图像尺寸和原始 FOV 计算。