坐标系变换

1. 几个坐标系:

  • 世界坐标系(world coordinate system):
    用户定义的三维世界的坐标系,为了描述目标物在真实世界里的位置而被引入。单位为m。
  • 相机坐标系(camera coordinate system):在相机上建立的坐标系,为了从相机的角度描述物体位置而定义,作为沟通世界坐标系和图像/像素坐标系的中间一环。单位为m。
  • 图像坐标系(image coordinate system):为了描述成像过程中物体从相机坐标系到图像坐标系的投影透射关系而引入,方便进一步得到像素坐标系下的坐标。 单位为m。
  • 像素坐标系(pixel coordinate system):为了描述物体成像后的像点在数字图像上(相片)的坐标而引入,是我们真正从相机内读取到的信息所在的坐标系。单位为个(像素数目)。

2.相机参数

16个单目相机的参数:

  • 4个内部参数(只与相机有关):
    世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数
    实际其世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_02,其中的世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_03就是焦距(上面的世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_04).Sx是像素/每毫米(即上面的世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_05),其是最后面图里的后两个矩阵进行先相乘,得出的,则把它看成整体,就相当于4个内参。把 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_06
  • 5个畸变参数D:
    世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_07 径向畸变系数;
    世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_08 是切向畸变系数;
    径向畸变:产生原因是光线在远离透镜中心的地方比靠近中心的地方更加弯曲,径向畸变主要包含桶形畸变和枕形畸变两种。
    切向畸变:产生的原因透镜不完全平行于图像平面,这种现象发生于成像仪被粘贴在摄像机的时候。
  • 6个外部参数(取决于相机在世界中的位置):
    3个旋转参数世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_09;
    3个平移参数世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_10

3. 坐标系之间的转换

3.1 整体公式

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_11

3.2 世界坐标系->相机坐标系:

刚体变换(regidbody motion):
三维空间中,当物体不发生形变时,对一个几何物体作旋转 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_12, 平移 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_13 的运动,称之为刚体变换。世界坐标系到相机坐标系的变化就是刚体变换,又因为世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_12世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_13与相机无关,所有又称其为相机外参。
首先考虑旋转。我们设某个单位正交基 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_16经过一次旋转,变成了 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_17。那么,对于同一个向量 a(注意该向量并没有随着坐标系的旋转而发生运动),它在两个坐标系下的坐标为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_18世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_19

根据坐标的定义,有

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_20
左右同事乘

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_21
,得到

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_22
中间的矩阵 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_12 由两组基之间的内积组成,刻画了旋转前后同一个向量的坐标变换关系。只要旋转是一样的,那么这个矩阵也是一样的。可以说,矩阵 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_12 描述了旋转本身。因此它又称为旋转矩阵。
旋转矩阵有一些特别的性质:是一个行列式为 1 的正交矩阵
可以把旋转矩阵的集合定义如下:

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_25
世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_26 代表坐标轴个数,比如 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_27 就代表包含 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_28 三个坐标轴的坐标系。
在欧氏变换中,除了旋转之外还有一个平移。考虑世界坐标系中的向量 $ a $,经过一次
旋转 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_12和一次平移 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_30 后,得到了世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_31,那么把旋转和平移合到一起,有:

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_32
其实表示为坐标就是

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_33
上面变换关系不是一个线性关系。假设我们进行了两次变换:世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_34世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_35,满足:
世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_36 合并为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_37,这样当变化次数特别多的时候很复杂。
所以一般在三维向量的末尾添加一个1,表示为齐次坐标的形式

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_38
对于这个四维向量,我们可以把旋转和平移写在一个矩阵里面,使得整个关系变成了线性关系。该式中,矩阵 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_13 称为变换矩阵(Transform Matrix) 。
相机坐标系和世界坐标系的坐标原点之间的距离,受 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_40 三个方向上的分量共同控制,所以具有三个自由度。世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_12 其实是分别绕 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_42三轴旋转的效果之和.

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_43

绕z轴旋转如右图

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_44

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_45
世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_46
世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_47
以上分别为绕 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_48轴旋转的矩阵,所以旋转矩阵为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_49

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_50


世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_51为相机坐标系, 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_52 轴指向相机前方,世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_53为摄像机的光心,也是针孔模型中的针孔。

3.3 相机坐标系->图像坐标系:

现实世界的空间点世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_54,经过小孔 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_53 投影之后,落在物理成像平面 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_56 上,成像点为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_57。设 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_54的坐标为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_59世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_57世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_61,并且设物理成像平面到小孔的距离为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_62(焦距)。

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_63

我们平时处理一般会用归一化成像平面,把成像位置转换到与它对称的红色位置,这样比较容易描述各个坐标系之间关系。

根据三角形相似关系,有 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_64为了方便,一般去掉负号。
整理后:

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_65
世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_66

3.4 图像坐标系->像素坐标系:

因为相机最后得到的是像素,所以在成像平面上对像进行采样和量化,把图像坐标系的点转化到一个像素平面 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_67。像素坐标系与图像坐标系处于同一平面,像素坐标系原点为左上角,图像坐标系原点为中心。

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_68

像素坐标系‹通常的定义方式是:原点 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_69 位于图像的左上角, 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_70轴向右与 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_71轴平行,世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_72
轴向下与世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_73轴平行。像素坐标系与成像平面之间,相差了一个缩放和一个原点的平移。
设像素坐标在世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_70轴上缩放了世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_75倍,在 v世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_76β$ 倍。同时,原点平移了世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_77。那么, 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_57的坐标与像素坐标世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_79的关系为:
世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_80

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_81, 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_82分别为在世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_71, 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_73方向上每个像素的物理尺寸,把 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_85 合并为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_86世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_87 合并为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_88 得到:
世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_89
$f $ 的单位为米, 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_90 的单位为像素每米,所以 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_91的单位为像 素。

把该式写成矩阵形式,会更加简洁,不过左侧需要用到齐次坐标, 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_92世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_93不垂直时的扭曲系数,一般为0:

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_94
习惯把Z移动到左面:

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_95

把中间的量组成的矩阵称为相机的内参数矩阵(Camera Intrinsics) 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_96

除了内参之外,自然还有相对的外参。考虑到上式中,我们使用的是 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_54在相机坐标系下的坐标。由于相机在运动,所以 $P $的相机坐标应该是它的世界坐标(记为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_98),根据相机的当前位姿,变换到相机坐标系下的结果。相机的位姿由它的旋转矩阵 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_12 和平移向量 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_30来描述。那么有:
世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_101
相机的位姿 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_102又称为相机的外参数(Camera Extrinsics) 。相比于不变的内参,外参会随着相机运动发生改变,同时也是 SLAM中待估计的目标,代表着机器人的轨迹.

3.5 畸变:

  • 畸变形成的原因:
    为了获得好的成像效果,相机的前方一般都加了透镜。对成像时光线的传播会产生新的影响: 一是透镜自身的形状对光线传播的影响,二是在机械组装过程中,透镜和成像平面不可能完全平行,光线穿过透镜投影到成像面时的位置发生变化。

由透镜形状引起的畸变称之为径向畸变。在针孔模型中,一条直线投影到像素平面上还是一条直线。可是,在实际拍摄的照片中,摄像机的透镜往往使得真实环境中的一条直线在图片中变成了曲线‹。越靠近图像的边缘,这种现象越明显。由于实际加工制作的透镜往往是中心对称的,这使得不规则的畸变通常径向对称。它们主要分为两大类, 桶形畸变和枕形畸变。

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_103

桶形畸变是由于图像放大率随着离光轴的距离增加而减小,而枕形畸变却恰好相反。
在这两种畸变中,穿过图像中心和光轴有交点的直线还能保持形状不变。

除了透镜的形状会引入径向畸变外,在相机的组装过程中由于不能使得透镜和成像面严格平行也会引入切向畸变。

平面上的任意一点 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_104可以用笛卡尔坐标表示为 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_105 , 也可以把它写成极坐标的形式
世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_106,其中 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_107 表示点 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_104 离坐标系原点的距离, 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_109 表示和水平轴的夹角。径向畸变可看成坐标点沿着长度方向发生了变化 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_110, 也就是其距离原点的长度发生了变化。切向畸变可以
看成坐标点沿着切线方向发生了变化,也就是水平夹角发生了变化 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_111

对于径向畸变,无论是桶形畸变还是枕形畸变,由于它们都是随着离中心的距离增加
而增加。我们可以用一个多项式函数来描述畸变前后的坐标变化:这类畸变可以用和距中
心距离有关的二次及高次多项式函数进行纠正:

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_112

其中 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_105 是未纠正的点的坐标,世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_114 是纠正后的点的坐标,注意它们都是归一化平面上的点,而不是像素平面上的点。在上式中,对于畸变较小的图像中心区域,畸变纠正主要是 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_115 起作用。而对于畸变较大的边缘区域主要是 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_116 起作用。普通摄像头用这两个系数就能很好的纠正径向畸变。对畸变很大的摄像头,比如鱼眼镜头,可以加入 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_117

另一方面,对于切向畸变,可以使用另外的两个参数 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_118来进行纠正:

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_119

对于相机坐标系中的一点 世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_图像坐标系_120,我们能够通过五个畸变系数找到这个点在像素平面上的正确位置:

1. 将三维空间点投影到归一化图像平面。设它的归一化坐标为 [x; y]T。
2. 对归一化平面上的点进行径向畸变和切向畸变纠正。
3. 将纠正后的点通过内参数矩阵投影到像素平面,得到该点在图像上的正确位置。
1. 首先,世界坐标系下有一个固定的点 P_w;
2. 由于相机在运动,它的运动由 R; t 或变换矩阵描述。 P 的相机坐标为:
P_c= R * P_w + t。
3. 这时的 P_c 仍有 X; Y; Z 三个量,把它们投影到归一化平面 Z = 1 上,得到 P 的归
一化相机坐标: Pc = [X/Z; Y /Z; 1]T 。
4. 最后, P 的归一化坐标经过内参后,对应到它的像素坐标: P_uv = K * P_c。

双目坐标

1.理想情况的双目相机模型

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_世界坐标系_121

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_122, 因为世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_相机参数_123,
所以最后世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_slam_124

2. 真实的双目相机模型

世界坐标系到相机坐标系 python实现 世界坐标和相机坐标_像素坐标系_125

真实场景的双目摄像机其实不是严格平行向前。所以需要双目标定得到两个相机之间的平移和旋转矩阵
参考:《视觉slam十四讲》