前言
已经是第n次写坐标系转换问题了,但是之前都是零散的写,还是需要系统总结一遍。
转换方法
一共有四个坐标系:世界坐标系、相机坐标系、图像坐标系(忽略)、像素坐标系
世界坐标系&相机坐标系
输入: 相机外参矩阵 TWC(4*4)及其逆矩阵TCW
公式: 相机坐标系下的对应点(xc,yc,zc)到世界坐标系下的任一点(xw,yw,zw)转换方式如下
[
x
w
y
w
z
w
1
]
=
T
W
C
∗
[
x
c
y
c
z
c
1
]
=
[
r
1
,
1
r
1
,
2
r
1
,
3
t
1
r
2
,
1
r
2
,
2
r
2
,
3
t
2
r
3
,
1
r
3
,
2
r
3
,
3
t
3
0
0
0
1
]
∗
[
x
c
y
c
z
c
1
]
\begin{bmatrix} x_w \\ y_w \\ z_w\\ 1 \end{bmatrix}=T_{WC}*\begin{bmatrix} x_c \\ y_c \\ z_c \\ 1 \end{bmatrix}=\begin{bmatrix} r_{1,1} & r_{1,2} &r_{1,3}&t_1 \\ r_{2,1} & r_{2,2} &r_{2,3}&t_2 \\ r_{3,1} & r_{3,2} &r_{3,3}&t_3 \\ 0 &0 &0&1\\ \end{bmatrix}*\begin{bmatrix} x_c \\ y_c \\ z_c \\ 1 \end{bmatrix}
xwywzw1
=TWC∗
xcyczc1
=
r1,1r2,1r3,10r1,2r2,2r3,20r1,3r2,3r3,30t1t2t31
∗
xcyczc1
反过来就是乘上逆矩阵TCW。
相机坐标系&像素坐标系
图像坐标系和像素坐标系的区别: 两者都是以图像左上角为原点,向右为 x 轴正方向,向下为 y 轴正方向,如下图所示:
区别在于,图像坐标系的单位通常是毫米或者英寸等物理单位,与实际图像的大小和分辨率有关。而像素坐标系将图像坐标系上的点转换为整数坐标的坐标系,它将图像坐标系上的每个单位划分为像素,每个像素都对应于图像上的一个点。
p
(
u
,
v
)
=
p
(
x
/
d
x
+
u
0
,
y
/
d
y
+
v
0
)
p(u,v)=p(x/dx+u_0,y/dy+v_0)
p(u,v)=p(x/dx+u0,y/dy+v0)
dx,dy分别表示X,Y方向上的一个像素在相机感光板上的物理长度(即一个像素在感光板上是多少毫米),u0,v0分别表示相机感光板中心在像素坐标系下的坐标。…这里不解释,反正不重要…
通常情况下会忽略相机坐标系到图像坐标系的变换,直接使用如下公式由相机坐标系到像素坐标系:
输入: 相机内参矩阵K(3*3)及其逆矩阵K-1,距离zc(注意这里的距离是相机坐标系的下的距离)
公式: 相机坐标系下的任一点(xc,yc,zc)到像素坐标系下的对应点(u0,v0)转换方式如下:
[
u
0
v
0
1
]
=
K
∗
[
x
c
/
z
c
y
c
/
z
c
1
]
=
[
f
x
0
c
x
0
f
y
c
y
0
0
1
]
∗
[
x
c
/
z
c
y
c
/
z
c
1
]
\begin{bmatrix} u_0 \\ v_0 \\ 1\\ \end{bmatrix}=K*\begin{bmatrix} x_c/z_c \\ y_c/z_c \\ 1 \\ \end{bmatrix}=\begin{bmatrix} f_{x} & 0 &c_x \\ 0 & f_{y} &c_y \\ 0 & 0 &1 \\ \end{bmatrix}*\begin{bmatrix} x_c/z_c \\ y_c/z_c \\ 1 \\ \end{bmatrix}
u0v01
=K∗
xc/zcyc/zc1
=
fx000fy0cxcy1
∗
xc/zcyc/zc1
这里其实包含两步,首先需要除以zc,然后再乘上相机内参,获得像素坐标。
Note: 学着学着就搞混了
- 内参乘上的是相机坐标系,获得的是像素坐标系。
- 除以的是zc是相机坐标系下的距离,即:相机到物体的距离。
- 注意矩阵维度
一些应用场景
RGBD转点云
使用如下公式描述将RGBD转为点云:
X_c = (u - c_x) * d / f_x
Y_c = (v - c_y) * d / f_y
Z_c = d
其实就是相机坐标系转像素坐标系的逆变换,转换获得的是相机坐标系下的点云
SLAM位姿转换
这里就只涉及外参和点在世界坐标系下的变换,相机坐标系(机器人)的坐标原点在世界坐标系下的坐标就是轨迹。轨迹可以有以下几种表示方法:
- 外参矩阵[R|T]4*4
- 时间+七元数(tx, ty, tz, qx,qy,qz,qw)
# 七元数转外参矩阵的代码如下
c2w = pose_matrix_from_quaternion(pose_vecs[k])
def pose_matrix_from_quaternion(pvec):
""" convert 4x4 pose matrix to (t, q) """
from scipy.spatial.transform import Rotation
pose = np.eye(4)
pose[:3, :3] = Rotation.from_quat(pvec[3:]).as_matrix()
pose[:3, 3] = pvec[:3]
return pose
情形1: 一号机器人在某个点看到的坐标p(x1,y1,z1)在二号机器人坐标系下的坐标
[
x
2
y
2
z
2
]
=
T
R
2
_
W
∗
T
W
_
R
1
∗
[
x
1
y
1
z
1
]
\begin{bmatrix} x_2 \\ y_2 \\ z_2\\ \end{bmatrix}=T_{R_2\_W}*T_{W\_R_1}*\begin{bmatrix} x_1 \\ y_1 \\ z_1 \\ \end{bmatrix}
x2y2z2
=TR2_W∗TW_R1∗
x1y1z1
情形2:(情形1的拓展) 可视化点云、mesh(或者绝大部分预处理都有这么一步),这时就要把所有像素点转换到一个坐标系下,通常以为一个轨迹下的坐标系为标准,将其他轨迹下的所有点通过上述变换,变换到第一帧的坐标系下,第一帧坐标系变为单位阵代码如下:
inv_pose = None
for ix in indicies:
c2w = pose_matrix_from_quaternion(pose_vecs[ix]) # 将7元数组转为外参矩阵 4*4
if inv_pose is None:
inv_pose = np.linalg.inv(c2w) # 求逆矩阵
c2w = np.eye(4)
else:
c2w = inv_pose@c2w
# c2w[:3, 1] *= -1
# c2w[:3, 2] *= -1
poses += [c2w]
3D目标检测
在此之前做过3D目标检测,当时一直不理解老师说的外参是随相机位姿改变而发生改变的,(以下是个人理解)在基于kitti的3d目标检测中,外参是不发生改变的,永远以相机为中心建立世界坐标系,寻找相机与物体间的关系。相机坐标系与世界坐标系可以重合,又或者以相机附近的点建立坐标系,该点位置与相机保持相对静止(例如:kitti中的0号相机和彩色相机的关系)。所以如何定义相机外参还是要看你所做的任务是什么吧。