
为什么需要进行双目标定?
双目测距中有一个常用公式:
Z = f * B / d
其中:
Z:深度
f:焦距
B:双目基线
d:视差
这个公式建立在理想平行双目模型上,也就是:
左右相机光轴平行
左右成像平面共面
对应点位于同一行
但实际安装时,两台相机之间一定存在旋转和平移。
所以双目标定的目的就是:
求出左右相机之间真实的旋转关系
R和平移关系T,再利用它们把左右图像校正成理想平行双目。
一、双目标定到底求什么
左右相机先分别完成单目标定,得到:
左相机:KL、DL
右相机:KR、DR
其中:
K:相机内参
D:畸变参数
双目标定主要计算:
R
T
使同一个空间点满足:
PR = R * PL + T
其中:
PL:点在左相机坐标系中的坐标
PR:点在右相机坐标系中的坐标
所以可以简单理解为:
内参标定:
相机自己是什么样
双目标定:
两个相机之间怎么摆
二、为什么要同时拍标定板
双目标定时,让左右相机同时看到同一块标定板。
假设标定板上的一个角点为:
Pw = (Xw, Yw, 0)
左相机检测到:
pL = (uL, vL)
右相机检测到:
pR = (uR, vR)
于是就建立了:
同一个真实空间点 Pw
↓
左图像素 pL
↓
右图像素 pR
一张标定板上有很多角点,拍很多组不同姿态的标定板,就能得到大量这样的对应关系。
三、R和T是怎么来的
对于同一张标定板:
PL = RL * Pw + TL
PR = RR * Pw + TR
从左相机公式得到:
Pw = RL^-1 * (PL - TL)
旋转矩阵满足:
RL^-1 = RL^T
所以:
Pw = RL^T * (PL - TL)
代入右相机:
PR = RR * RL^T * (PL - TL) + TR
展开:
PR
=
RR * RL^T * PL
-
RR * RL^T * TL
+
TR
和:
PR = R * PL + T
比较得到:
R = RR * RL^T
T = TR - R * TL
也就是说,同一块标定板同时被两个相机看到后,就可以通过:
标定板 -> 左相机
标定板 -> 右相机
的关系,推出:
左相机 -> 右相机
的 R、T。
四、为什么要拍很多张图片
理论上一组姿态就可以算出一次 R、T,但实际角点位置存在:
角点检测误差
图像噪声
畸变模型误差
标定板制造误差
所以单组图片算出的 R、T 会有偏差。
实际会拍很多组:
第1组:左图1 + 右图1
第2组:左图2 + 右图2
第3组:左图3 + 右图3
...
然后不是把每组算出的 R、T 简单求平均,而是:
让所有图片中的所有角点共同约束同一组固定的
R、T。
假设当前参数预测某个角点应该出现在:
左图:pL'
右图:pR'
实际检测结果是:
左图:pL
右图:pR
那么误差就是:
eL = pL - pL'
eR = pR - pR'
优化器不断调整参数,使所有图片、所有角点的总体误差:
Σ ||pL - pL'||²
+
Σ ||pR - pR'||²
尽可能小。
所以多拍图片的本质就是:
大量不同姿态的数据
↓
共同约束同一个R、T
↓
降低单张图片随机误差的影响
↓
得到更加稳定的R、T
工程中通常先分别标定好两个相机的内参,然后双目标定时固定:
KL
KR
DL
DR
只优化:
R
T
OpenCV中常使用:
CALIB_FIX_INTRINSIC
五、T和基线B是什么关系
例如双目标定得到:
T = (-120, 0.5, 1.2)mm
说明两个相机光心之间主要相差约 120 mm。
双目基线就是两个相机光心之间的距离:
B = ||T||
也就是:
B = sqrt(Tx² + Ty² + Tz²)
这个 B 就是:
Z = f * B / d
中的基线。
六、双目标定后为什么还要双目校正
虽然已经知道了 R、T,但原始左右相机仍然可能是:
左相机 右相机
↑ZL ↗ZR
| /
O --------------- O
所以同一个空间点可能出现在:
左图:(800, 420)
右图:(650, 416)
此时:
vL != vR
说明对应点既有横向差,也有纵向差,不方便做匹配。
因此需要根据 R、T 对左右图像进行双目校正。
校正后得到两个新的虚拟相机:
校正后左相机 校正后右相机
↑Z ↑Z
| |
O ----------------- O
B
使得:
成像平面共面
光轴平行
极线水平
最终同一个空间点满足:
左图:(uL, v)
右图:(uR, v)
也就是:
vL ≈ vR
OpenCV进行双目校正后通常得到:
R1
R2
P1
P2
Q
其中:
R1、R2:左右相机校正旋转
P1、P2:校正后的投影矩阵
Q:视差转3D矩阵
七、极线、E和F是什么
左图确定一个点 pL 后,它在右图中的对应点并不是任意位置,而一定落在一条特定的线上,这条线叫:
极线。
所以双目匹配本来是:
左图一个点
↓
去右图的一条极线上寻找对应点
双目校正以后,极线被变成水平线,因此:
左图第400行
↓
只需要搜索右图第400行
极线约束可以写成:
xR^T * E * xL = 0
其中:
E = [T]x * R
E 是本质矩阵,描述归一化相机坐标下的极线关系,本质上由 R、T 决定。
如果直接使用像素坐标:
pR^T * F * pL = 0
其中:
F = KR^-T * E * KL^-1
所以简单记:
E:R、T对应的极线约束
F:加入左右相机内参后的像素极线约束
八、双目是怎么得到3D的
双目校正以后,同一个空间点为:
左图:(uL, v)
右图:(uR, v)
视差:
d = uL - uR
对于理想平行双目:
Z = f * B / d
得到深度以后:
X = (uL - Cx) * Z / fx
Y = (v - Cy) * Z / fy
最终得到三维坐标:
P = (X, Y, Z)
因为:
d = f * B / Z
所以:
物体越近 -> Z越小 -> 视差越大
物体越远 -> Z越大 -> 视差越小
因此不同深度的空间点,视差通常不同。
OpenCV中的 Q 矩阵已经组合了焦距、主点和基线等关系,可以直接实现:
(u, v, d)
↓
Q
↓
(X, Y, Z)
例如:
reprojectImageTo3D
就是利用这个关系把视差图转换成点云。
九、怎么判断双目标定好不好
双目标定不能只看程序有没有成功,还要看最终三维效果。
主要检查:
1. 重投影误差是否足够小
2. 校正后左右对应点行差:
|vL - vR|
是否接近0
3. 校正后的极线是否水平
4. 拍摄真实平面,看点云是否:
弯曲
波浪
重影
变形
5. 测量已知距离,看3D误差
例如真实距离:
500 mm
重建结果:
503 mm
那么深度误差就是:
3 mm
重投影误差反映的是:
当前数学模型是否能够解释标定图片。
而真实平面和已知距离测试反映的是:
最终三维重建到底准不准。
所以二者都需要检查。
十、完整双目标定流程
左相机单目标定
↓
得到KL、DL
右相机单目标定
↓
得到KR、DR
左右相机同时拍摄多组标定板
↓
检测左右角点
↓
大量3D角点与左右2D像素建立对应
↓
优化得到左右相机R、T
↓
根据R、T进行Stereo Rectify
↓
得到R1、R2、P1、P2、Q
↓
左右图去畸变 + 校正
↓
对应点基本同行
↓
计算视差d
↓
Z = fB/d
↓
得到X、Y、Z
↓
生成3D点云
所以整个双目系统最核心的关系可以浓缩成:
单目标定
↓
知道每个相机自己怎么成像
双目标定
↓
知道两个相机之间怎么摆
双目校正
↓
把两个相机变成理想平行双目
左右匹配
↓
得到视差d
Z = fB/d
↓
得到三维坐标
一句话理解双目标定:
双目标定就是让左右相机同时观察大量相同的空间点,通过这些点在左右图像中的位置,共同优化出两个相机坐标系之间固定的旋转
R和平移T,再利用它们完成图像校正和三维重建。