Robotics - Calibrartion - Realsense D435 as example
2026-08-26 · 随笔 · 371798712f24
相机内参、D435 双目深度与针孔模型
- 内参:描述相机自己“如何把三维光线投到二维像素上”。
- 外参:描述一个坐标系相对于另一个坐标系“在哪里、朝哪个方向”。
- 主点: 主点 (cx,cy)(c_x,c_y),可以直接理解成:
- cx:主点的横坐标
- cyc_y:主点的纵坐标
相机正前方,也就是相机 ZZ 轴指向的方向,投影到图像上的那个像素点。
更严格地说,它是:
相机光轴与等效成像平面的交点,在像素坐标系中的坐标。
语义的 debug
内参是相机属性的一部分,但不是所有相机属性都叫内参。
例如,物理焦距 ff、Sensor 的 pixel pitch、分辨率、曝光时间、快门类型都是相机或成像系统的属性,但狭义的相机内参通常指:
fx,fy,cx,cy
f_x,\quad f_y,\quad c_x,\quad c_y
以及有时单独列出的 skew 和畸变参数。
像素与 D435 内部的多个相机
D435 内部有多个成像单元:
- 左红外相机;
- 右红外相机;
- RGB 彩色相机;
- 另外还有红外投影器,但它不是相机。
面对 D435 正面看,深度模组大致排列为:
右红外相机→红外投影器→左红外相机→RGB 相机
\text{右红外相机}
\rightarrow
\text{红外投影器}
\rightarrow
\text{左红外相机}
\rightarrow
\text{RGB 相机}
这里的 Left/Right 是按照相机模组朝外观察的视角命名的;人面对相机时,左右视觉上会反过来。
每个相机都可以有自己的一套内参,两个相机之间还会有外参。因此不能把 RGB 相机的内参直接当成左、右红外相机的内参。
D435 如何得到深度
D435 的工作方式是:
- 红外投影器向物体表面投射人眼不可见的红外点阵。
- 左、右红外相机同时拍摄场景。
- D4 芯片对两幅图像进行校正并寻找对应点,计算视差 dd。
- 根据双目几何计算深度。
对于已经极线校正的数字图像,常用公式是:
Z=dfxB
Z=\frac{f_xB}{d}
其中:
- ZZ:深度,单位与 BB 相同;
- fxf_x:校正后深度图水平方向的像素焦距,单位 pixel;
- BB:左右红外相机光心之间的 baseline,单位可以是 mm 或 m;
- dd:左右图像对应点的水平视差,单位 pixel。
因为 fxf_x 和 dd 都以 pixel 为单位,它们的像素单位会相消,所以 ZZ 与 BB 使用相同的物理长度单位。
需要注意:D435 本质上仍然是双目立体视觉。投影器只是给白墙、无纹理零件等表面人工增加纹理,并不是像 ToF 那样直接测量光的飞行时间。关掉投影器以后,只要环境本身纹理足够,仍然可以计算深度。
Pinhole model
主平面
真实镜头可能包含多块透镜:
外界光线→透镜 1→透镜 2→透镜 3→Sensor
\text{外界光线}
\rightarrow
\text{透镜 1}
\rightarrow
\text{透镜 2}
\rightarrow
\text{透镜 3}
\rightarrow
\text{Sensor}
光线在每块透镜上都会发生折射,因此很难用一块真实玻璃的位置代表整个镜组。光学上会把复杂镜组等效为一个简化系统:
复杂镜组⟹等效主平面与焦距
\text{复杂镜组}
\Longrightarrow
\text{等效主平面与焦距}
主平面不是一块真实存在的玻璃,而是数学上的参考平面。
严格来说,厚透镜或复杂镜组通常有前、后两个主平面;这里为了理解相机投影,先使用简化的等效薄透镜或针孔模型。
焦距
焦距的理论定义:
当来自无限远物体的平行光经过镜头后,会聚到焦点;相应主平面到焦点的距离就是有效焦距。
f=主平面到焦点的物理距离
\boxed{f=\text{主平面到焦点的物理距离}}
对已经组装好的 RealSense,计算机视觉中通常不执着于单独测量物理焦距 ff,而是直接标定:
fx,fy,cx,cy
f_x,\quad f_y,\quad c_x,\quad c_y
真实复杂镜头可以近似理解为:
理想针孔相机+畸变模型
\boxed{\text{理想针孔相机}+\text{畸变模型}}
Pixel pitch
单个 Sensor 像素是 Sensor 表面的一个感光格子,内部通常包含光电二极管等微型结构。
例如:
pixel pitch=3 μm
\text{pixel pitch}=3\ \mu\text{m}
这种 Sensor 可以想象成一面铺满相同瓷砖的墙。
定义:
- sxs_x:Sensor 上一个像素格子在 xx 方向的物理宽度;
- sys_y:Sensor 上一个像素格子在 yy 方向的物理高度;
- ff:物理焦距;
- (cx,cy)(c_x,c_y):主点的像素坐标。
如果原始 Sensor 像素与输出图像像素一一对应,sx,sys_x,s_y 就是物理 pixel pitch。实际系统还可能进行 binning、裁剪、去畸变或缩放,因此 Sensor 像素和输出图片像素不一定一一对应。
在这种情况下,公式中的 sx,sys_x,s_y 更准确地理解为:
一个输出图像像素所对应的有效 Sensor 物理尺寸。
主点 (cx,cy)(c_x,c_y)
(cx,cy)(c_x,c_y) 是像素坐标系中的一个点,表示相机光轴与成像平面的交点,也叫主点。
理想装配下,它应该接近图像正中央。按照“整数坐标位于像素中心”的约定,更严格地写是:
cx≈2W−1,cy≈2H−1
c_x\approx\frac{W-1}{2},\qquad
c_y\approx\frac{H-1}{2}
很多资料会简写成 W/2,H/2W/2,H/2;两种写法相差半个像素,来源是像素中心与图像边界的坐标约定不同。
但真实相机中通常会有偏差,原因包括:
- 镜头和 Sensor 没有完全对准;
- Sensor 安装存在微小偏移或倾斜;
- 图像经过裁剪、缩放或校正;
- 实际光学系统与理想针孔模型存在差异。
所以需要通过标定得到更准确的 (cx,cy)(c_x,c_y)。相机标定一般同时估计:
fx,fy,cx,cy
f_x,\quad f_y,\quad c_x,\quad c_y
以及畸变参数。
在 RealSense SDK 的 `rs2_intrinsics` 中:
- `ppx` 对应 cxc_x;
- `ppy` 对应 cyc_y;
- `fx` 对应 fxf_x;
- `fy` 对应 fyf_y。
从物理成像平面到像素坐标
1. 在相机坐标系中建立坐标
将相机坐标系原点设在相机的等效光心:
- ZZ 轴:沿相机正前方;
- XX 轴:相机看到的右方;
- YY 轴:相机看到的下方。
一个相机坐标系中的三维点写成:
Pc=(X,Y,Z)
\mathbf P_c=(X,Y,Z)
计算机视觉通常使用位于光心前方的虚拟成像平面,这样可以避免真实 Sensor 位于镜头后方所带来的图像倒置符号。针孔投影得到等效成像平面上的物理位置:
xsensor=fZX,ysensor=fZY
x_{\mathrm{sensor}}=f\frac{X}{Z},\qquad
y_{\mathrm{sensor}}=f\frac{Y}{Z}
这里全部使用相同的物理长度单位,例如 mm:
- X,Y,ZX,Y,Z:mm;
- ff:mm;
- xsensor,ysensorx_{\mathrm{sensor}},y_{\mathrm{sensor}}:mm。
这是相似三角形直接得到的:
fxsensor=ZX
\frac{x_{\mathrm{sensor}}}{f}=\frac{X}{Z}
这一阶段使用的是物理焦距 ff。
2. 但计算机图像不用 mm 表示位置
计算机看到的坐标是:
(u,v)=(420,250)
(u,v)=(420,250)
单位是 pixel,而不是:
(x,y)=(1.26 mm,0.75 mm)
(x,y)=(1.26\ \text{mm},0.75\ \text{mm})
假设一个输出像素对应的有效物理宽度是:
sx=0.003 mm/pixel
s_x=0.003\ \text{mm/pixel}
那么成像平面上的物理横坐标与像素横坐标满足:
xsensor=(u−cx)sx
x_{\mathrm{sensor}}=(u-c_x)s_x
所以:
u−cx=sxxsensor
u-c_x=\frac{x_{\mathrm{sensor}}}{s_x}
再代入针孔投影:
xsensor=fZX
x_{\mathrm{sensor}}=f\frac{X}{Z}
得到:
u−cx=sxfZX
u-c_x=\frac{f}{s_x}\frac{X}{Z}
为了简化书写,定义:
fx=sxf
\boxed{f_x=\frac{f}{s_x}}
于是:
u=fxZX+cx
\boxed{u=f_x\frac{X}{Z}+c_x}
同理:
fy=syf
\boxed{f_y=\frac{f}{s_y}}
v=fyZY+cy
\boxed{v=f_y\frac{Y}{Z}+c_y}
所以除以 sx,sys_x,s_y 的原因非常简单:
把 Sensor 上以毫米表示的位置换算成以像素表示的位置。
u−cxu-c_x 表示什么?
u−cxu-c_x 表示成像点相对于主点的水平像素偏移量。
- uu:成像点在图片中的横向像素坐标;
- cxc_x:主点在图片中的横向像素坐标;
- u−cxu-c_x:成像点相对于主点,向左或向右偏了多少像素。
xsensor=fX/Zx_{\mathrm{sensor}}=fX/Z 是 fxf_x 吗?
不是。
xsensor=fZX
x_{\mathrm{sensor}}=f\frac{X}{Z}
这里:
- xsensorx_{\mathrm{sensor}}:成像点相对于主点的等效物理偏移,单位 mm;
- ff:物理焦距,单位 mm;
- X/ZX/Z:三维点相对相机的方向比例,无量纲。
而 fxf_x 是:
fx=sxf
\boxed{f_x=\frac{f}{s_x}}
单位是 pixel。
两层关系是:
xsensor=fZX单位:mm
x_{\mathrm{sensor}}=f\frac{X}{Z}
\qquad\text{单位:mm}
然后除以单个像素对应的有效物理宽度:
u−cx=sxxsensor=sxfZX=fxZX单位:pixel
u-c_x
=\frac{x_{\mathrm{sensor}}}{s_x}
=\frac{f}{s_x}\frac{X}{Z}
=f_x\frac{X}{Z}
\qquad\text{单位:pixel}
所以对应关系是:
f⟷fxxsensor⟷u−cx
\boxed{f\longleftrightarrow f_x}
\qquad
\boxed{x_{\mathrm{sensor}}\longleftrightarrow u-c_x}
不是:
xsensor=fx
x_{\mathrm{sensor}}=f_x
一句话记忆:
fX/ZfX/Z 算出成像平面上偏了多少毫米;fxX/Zf_xX/Z 算出图像上偏了多少像素。
为什么 fxf_x 只是一个系数,却叫内参?
数学上:
fx=sxf
f_x=\frac{f}{s_x}
确实可以看成一个合并后的系数。
但内参不是指相机内部真实存在的零件,而是:
描述这台相机几何成像行为的模型参数。
fxf_x 虽然只是一个系数,却决定了三维方向在图像水平方向上会被展开成多少像素。
fxf_x 实际描述什么?
投影公式是:
u−cx=fxZX
u-c_x=f_x\frac{X}{Z}
其中:
ZX
\frac{X}{Z}
描述三维点相对于光轴的水平方向,也可以写成:
ZX=tanθx
\frac{X}{Z}=\tan\theta_x
于是:
u−cx=fxtanθx
u-c_x=f_x\tan\theta_x
因此 fxf_x 表示:
三维观察方向发生一定变化时,图像坐标会变化多少像素。
例如,同一个三维方向:
ZX=0.1
\frac{X}{Z}=0.1
相机 A:
fx=600
f_x=600
得到:
u−cx=60 pixels
u-c_x=60\ \text{pixels}
相机 B:
fx=1000
f_x=1000
得到:
u−cx=100 pixels
u-c_x=100\ \text{pixels}
相机 B 会把同样的视角偏移展开成更多像素,看起来更加“放大”,视场角也更窄。
所以 fxf_x 可以理解为:
水平方向的角度/方向⟶像素位移的缩放比例
\boxed{
\text{水平方向的角度/方向}
\longrightarrow
\text{像素位移的缩放比例}
}
为什么不直接把 ff 和 sxs_x 分开放进内参?
因为计算机视觉最终观察到的是数字图像中的像素位置,投影公式里总是以这个组合出现:
sxf
\frac{f}{s_x}
相机仅根据标定图片通常可以可靠估计:
fx=sxf
f_x=\frac{f}{s_x}
但不能仅凭图片唯一分解出:
f=多少 mm
f=\text{多少 mm}
以及:
sx=多少 mm/pixel
s_x=\text{多少 mm/pixel}
例如:
0.003 mm/pixel2 mm=666.7 pixels
\frac{2\ \text{mm}}{0.003\ \text{mm/pixel}}
=666.7\ \text{pixels}
下面这组参数也会产生相同的 fxf_x:
0.006 mm/pixel4 mm=666.7 pixels
\frac{4\ \text{mm}}{0.006\ \text{mm/pixel}}
=666.7\ \text{pixels}
对针孔投影公式来说,这两种组合的结果相同。算法真正需要、也真正能从图像几何中识别的是它们的比值 fxf_x。
如果已经从 Sensor 规格表知道真实 pixel pitch,并且确认输出图像没有额外缩放或裁剪,那么可以用 f≈fxsxf\approx f_xs_x 反推出物理焦距;但这使用了图片以外的额外硬件信息。
uu 与 cxc_x 属于同一个坐标空间
图像宽度为 W=1280W=1280 时,通常:
u∈[0,1279]
u\in[0,1279]
cxc_x 也是横向像素坐标,例如:
cx=638.7
c_x=638.7
- uu:不同成像点的横坐标,是变量,可以遍布整张图;
- cxc_x:光轴与成像平面交点的横坐标,是标定得到的固定参数。
例如:
u=700,cx=638.7
u=700,\qquad c_x=638.7
则:
u−cx=61.3 pixels
u-c_x=61.3\ \text{pixels}
表示目标点位于主点右侧 61.361.3 个像素。像素坐标可以是小数,因为标定和特征检测可以达到亚像素精度。
因此:
uu 和 cxc_x 属于同一个坐标空间,但 uu 是变量,cxc_x 是固定内参。
“只是系数”为什么也可以是参数?
“参数”本来就是模型中控制行为的系数。
例如:
y=ax+b
y=ax+b
其中:
- aa 只是乘法系数,但决定直线斜率;
- bb 只是加法系数,但决定直线位置。
在相机模型中:
u=fxZX+cx
u=f_x\frac{X}{Z}+c_x
- fxf_x:缩放系数;
- cxc_x:平移或偏移系数。
它们共同决定相机如何把三维方向映射到像素。
为什么属于“内”参?
判断标准不是它是不是物理零件,而是它描述的是相机自身的成像关系,还是相机相对于外界的位置。
如果只是把 RealSense 从桌子左边移到右边,同时不改变成像 profile:
- fxf_x:不变;
- fyf_y:不变;
- (cx,cy)(c_x,c_y):不变;
- 相机相对于机械臂的外参:改变。
而如果更换镜头、Sensor,或者改变图像分辨率、裁剪和缩放方式:
- fx,fy,cx,cyf_x,f_y,c_x,c_y 可能改变。
所以它们描述的是相机自身在当前成像模式下的几何映射,而不是相机在世界中的位置,因此属于内参。
狭义的内参矩阵
一般形式是:
K=[fxγcx 0fycy 001]
K=
\begin{bmatrix}
f_x&\gamma&c_x\
0&f_y&c_y\
0&0&1
\end{bmatrix}
其中 γ\gamma 是像素坐标轴的 skew。现代数字相机通常近似有 γ=0\gamma=0,于是:
K=[fx0cx 0fycy 001]
K=
\begin{bmatrix}
f_x&0&c_x\
0&f_y&c_y\
0&0&1
\end{bmatrix}
这里要避免混淆:
- sx,sys_x,s_y:有效 pixel pitch,单位 mm/pixel;
- γ\gamma:内参矩阵中的坐标轴倾斜参数,单位 pixel。
两者不是同一个量。
畸变参数
此外还有畸变参数。例如 OpenCV 常见的 Brown–Conrady 参数:
D=(k1,k2,p1,p2,k3)
D=(k_1,k_2,p_1,p_2,k_3)
其中:
- k1,k2,k3k_1,k_2,k_3:径向畸变参数;
- p1,p2p_1,p_2:切向畸变参数。
RealSense 的具体 distortion model 需要以对应 stream profile 返回的模型为准,不能只看到五个系数就默认所有 stream 都使用完全相同的公式方向。
完整投影过程
完整投影过程可以理解为:
(X,Y,Z)⟶(ZX,ZY)⟶(xd,yd)⟶(u,v)
(X,Y,Z)
\longrightarrow
\left(\frac{X}{Z},\frac{Y}{Z}\right)
\longrightarrow
(x_d,y_d)
\longrightarrow
(u,v)
| 表示 | 所在空间/坐标 | 单位 | 含义 |
| (X,Y,Z)(X,Y,Z) | 相机三维坐标系 | m 或 mm | 点相对于相机光心的位置 |
| (xn,yn)=(X/Z,Y/Z)(x_n,y_n)=(X/Z,Y/Z) | 理想归一化图像坐标 | 无量纲 | 理想针孔模型中观察射线与虚拟 Z=1Z=1 平面的交点 |
| (xd,yd)(x_d,y_d) | 畸变后的归一化图像坐标 | 无量纲 | 真实镜头畸变后,该方向在归一化平面上的等效位置 |
| (u,v)(u,v) | 图像像素坐标系 | pixel | 最终落在数字图片中的位置 |
这里的 (xn,yn)(x_n,y_n) 与 (xd,yd)(x_d,y_d) 都是投影模型中的中间坐标,不是直接拿尺子在外界测到的点。
内参矩阵本质上就是缩放和偏移
先得到归一化图像坐标:
xn=ZX,yn=ZY
x_n=\frac{X}{Z},\qquad
y_n=\frac{Y}{Z}
经过畸变模型后得到 (xd,yd)(x_d,y_d),再由内参转换为像素坐标:
u=fx,xd+cx,v=fy,yd+cy
u=f_x,x_d+c_x,\qquad
v=f_y,y_d+c_y
如果暂时忽略畸变,则:
u=fxZX+cx,v=fyZY+cy
u=f_x\frac{X}{Z}+c_x,\qquad
v=f_y\frac{Y}{Z}+c_y
矩阵形式:
[u v 1]=[fx0cx 0fycy 001][X/Z Y/Z 1]
\begin{bmatrix}
u\
v\
1
\end{bmatrix}
=
\begin{bmatrix}
f_x&0&c_x\
0&f_y&c_y\
0&0&1
\end{bmatrix}
\begin{bmatrix}
X/Z\
Y/Z\
1
\end{bmatrix}
所以内参矩阵 KK 做的事情非常朴素:
- 用 fx,fyf_x,f_y 缩放;
- 用 cx,cyc_x,c_y 移动坐标原点。
可以这样理解:
fxf_x 虽然是 f/sxf/s_x 的合并系数,但它是数字相机真正可观测、真正用于投影的焦距参数。
回到 D435 的内参
首先只看 Right IR Camera。它在某个具体 stream profile 下有自己的一套:
fx,fy,cx,cy,D
f_x,\quad f_y,\quad c_x,\quad c_y,\quad D
Left IR Camera 和 RGB Camera 也分别有自己的内参。改变分辨率、裁剪或缩放模式后,要读取对应 profile 的内参,不能无条件复用另一个 profile 的数值。
最后再次回答:
xsensor=fX/Zx_{\mathrm{sensor}}=fX/Z 不是 fxf_x。左边是一个以 mm 表示的位置;fxf_x 是一个以 pixel 表示的投影尺度参数。正确的像素关系是 u−cx=fxX/Zu-c_x=f_xX/Z。