世界坐标系是为了描述相机的位置而被引入的,平移向量T是第一个坐标原点与第二个坐标原点的偏移量;
世界坐标系(Ow,以空间一点为原点)
世界坐标系(world coordinate)(xw,yw,zw),也称为测量坐标系,是一个三维直角坐标系,以其为基准可以描述相机和待测物体的空间位置。世界坐标系的位置可以根据实际情况自由确定。
相机坐标系(Oc以小孔即光心为原点) (Xc,Yc,Zc)至图像坐标系(x,y)
根据小孔成像原理,图像坐标系应在相机坐标系的另一边,为倒立反向成像,但为方便理解和计算,故投影至同侧。
相机坐标系(camera coordinate)(xc,yc,zc),也是一个三维直角坐标系,原点位于镜头光心处,x、y轴分别与相面的两边平行,z轴为镜头光轴,与像平面垂直。
成像平面坐标系(x,y):像素坐标系不利于坐标变换,因此需要建立图像坐标系XOY,其坐标轴的单位通常为毫米(mm),原点是相机光轴与相面的交点(称为主点),即图像的中心点,X轴、Y轴分别与u轴、v轴平行。故两个坐标系实际是平移关系,即可以通过平移就可得到。
图像物理坐标系(O1以像平面中心为原点)
像素坐标系uov是一个二维直角坐标系,反映了相机CCD/CMOS芯片中像素的排列情况。原点o位于图像的左上角,u轴、v轴分别于像面的两边平行。像素坐标系中坐标轴的单位是像素(整数)。
图像像素坐标系(O以像平面左下角为原点)
像素坐标系和图像坐标系都在成像平面上,只是各自的原点和度量单位不一样。图像坐标系的原点为相机光轴与成像平面的交点,通常情况下是成像平面的中点或者叫principal point。图像坐标系的单位是mm,属于物理单位,而像素坐标系的单位是pixel,我们平常描述一个像素点都是几行几列。所以这二者之间的转换如下:其中dx和dy表示每一列和每一行分别代表多少mm,即1pixel=dx mm
重点就是u0和v0的值是在像素坐标系下的中心像素,比如600*400,那坐标就是(300,200)
所以才可以有下面的加法
伸缩变换及平移变换
四个坐标系之间存在着下述关系 ( 矩阵依次左乘 )
一个三维中的坐标点,的确可以在图像中找到一个对应的像素点,但是反过来,通过图像中的一个点找到它在三维中对应的点就很成了一个问题,因为我们并不知道等式左边的Zc的值。
可以把凸透镜的几何中心近似看作是光心,因为实际上两者不重合,所以才径向和切向畸变。
是成像平面或者像素平面和光心之间的距离,焦距越大,人细节越清楚,视角越小;焦距越小,视野越广,但细节越看不清。
按照十四讲的顺序我们首先接触的是像素坐标系、图像坐标系、相机坐标系、相机归一化坐标系、世界坐标系,这里学着学着就蒙了,所以我建议先学习投影模型,我认为二者可以理解为互逆过程,总结一下就是世界坐标和相机坐标之间要借助外参就是Rt进行转换,相机和相机归一化之间要有一个尺度的转换,这里默认尺度是Z
,这里正是三维变为二维的过程,就像(10,4,2)和(5,2,1)一样忽略第三个维度,前两个维度是一样的。相机坐标系的原点是光心,图像坐标系的原点是焦点,焦点和关心之间的距离是焦距,两个相机光心之间的距离值是基线,基线乘fx除Z=视差,像素平面的原点是左上角和OpenCV的坐标系一样,像素平面和成像平面之间相差的是平移和缩放通过内参fx,fy,cx,cy
实现。
根据三角形相似原理得出下面的公式:
Z f \frac{Z}{f} fZ = X X ′ \frac{X}{X'} X′X = Y Y ′ \frac{Y}{Y'} Y′Y
整理一下得到成像平面点和现实世界空间点之间的关系:
X ′ X' X′ = f ∗ X Z f*\frac{X}{Z} f∗ZX
Y ′ Y' Y′ = f ∗ Y Z f*\frac{Y}{Z} f∗ZY
假设 P ′ P' P′的像素坐标为: [ u , v ] T [u, v]^T [u,v]T
像素坐标系通常的定义方式是:
原点 o ′ o' o′位于图像的左上角,
u u u轴向右与 x x x轴平行,
v v v轴向下与 y y y轴平行。
像素坐标系与成像平面之间相差了一个缩放和一个原点的平移。
设像素坐标在 u u u轴上缩放了 α α α倍,在 v v v上缩放了 β β β倍。
同时原点平移了 [ c x , c y ] T [c_x, c_y]^T [cx,cy]T
那么 P ′ P' P′的坐标与像素坐标 [ u , v ] T [u, v]^T [u,v]T的关系为:
u u u = α ∗ X ′ + c x α*X' + c_x α∗X′+cx
v v v = β ∗ Y ′ + c y β*Y' + c_y β∗Y′+cy
X ′ X' X′ = u − c x α \frac{u - c_x}{α} αu−cx
Y ′ Y' Y′ = v − c y β \frac{v - c_y}{β} βv−cy
并把 α f αf αf合并成 f x f_x fx,把 β f βf βf合并成 f y f_y fy
结合上面成像平面点和现实世界空间点之间的关系
X ′ X' X′ = f ∗ X Z f*\frac{X}{Z} f∗ZX
Y ′ Y' Y′ = f ∗ Y Z f*\frac{Y}{Z} f∗ZY
得到下面的像素点和空间点之间的关系
u u u = f x ∗ X Z + c x f_x*\frac{X}{Z} + c_x fx∗ZX+cx
v v v = f y ∗ Y Z + c y f_y*\frac{Y}{Z} + c_y fy∗ZY+cy
u − c x f x ∗ Z \frac{u-c_x}{f_x} * Z fxu−cx∗Z = X X X
v − c y f y ∗ Z \frac{v- c_y}{f_y} * Z fyv−cy∗Z = Y Y Y
f f f的单位为米,
α α α, β β β的单位为像素每米,
所以 f x f_x fx, f y f_y fy的单位为像素。
把该式写成矩阵形式,会更加简洁,不过左侧需要用到齐次坐标:
≜ \triangleq ≜ 表示定义为,读作德尔塔等于或 Delta Equal To。
( u v 1 ) \begin{pmatrix} u \\ v \\ 1 \end{pmatrix} ⎝⎛uv1⎠⎞ = ( f x 0 c x 0 f y c y 0 0 1 ) \begin{pmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{pmatrix} ⎝⎛fx000fy0cxcy1⎠⎞ ( X Y Z ) \begin{pmatrix} X \\ Y \\ Z \end{pmatrix} ⎝⎛XYZ⎠⎞ ≜ \triangleq ≜ 1 Z × K P \frac{1}{Z}×KP Z1×KP
换一种写法
( u v 1 ) \begin{pmatrix} u \\ v \\ 1 \end{pmatrix} ⎝⎛uv1⎠⎞ = Z × ( f x 0 c x 0 f x c y 0 0 1 ) Z×\begin{pmatrix} f_x & 0 & c_x \\ 0 & f_x & c_y \\ 0 & 0 & 1 \end{pmatrix} Z×⎝⎛fx000fx0cxcy1⎠⎞ ( X Y Z ) \begin{pmatrix} X \\ Y \\ Z \end{pmatrix} ⎝⎛XYZ⎠⎞ ≜ \triangleq ≜ K P KP KP
中间的量组成的矩阵称为相机的内参数矩阵(Camera Intrinsics)K
上面我们使用的 P P P是在相机坐标系下的坐标
由于相机在运动,所以 P P P的相机坐标应该是它的世界坐标(记为 P w P_w Pw ),
根据相机的当前位姿,变换到相机坐标系下的结果。
相机的位姿由它的旋转矩阵 R R R和平移向量 t t t来描述。
则有下面关系式:
Z P u v ZP_{uv} ZPuv= Z [ u v 1 ] Z\begin{bmatrix} u \\ v \\ 1 \end{bmatrix} Z⎣⎡uv1⎦⎤ = K ( R P w + t ) K(RP_w + t) K(RPw+t)= K T P w KTP_w KTPw
终于把理论部分说明白了。
这个是归一化平面的点(Z = 1)转化为像素坐标。
Vector2d Camera::camera2pixel ( const Vector3d& p_c )
{
return Vector2d (
fx_ * p_c ( 0,0 ) / p_c ( 2,0 ) + cx_,
fy_ * p_c ( 1,0 ) / p_c ( 2,0 ) + cy_
);
}
p_c ( 0,0 ) = u u u
p_c ( 1,0 ) = v v v
p_c ( 2,0 ) = 1
因为我们归一化左边用列向量表示了,所以是这样的
默认向量都用列向量表示,
所以书面写的时候才会加上一个装置的符号"T"
这个是上面公式的直接应用
成像平面点和现实世界空间点之间的关系:
X ′ X' X′ = f ∗ X Z f*\frac{X}{Z} f∗ZX
Y ′ Y' Y′ = f ∗ Y Z f*\frac{Y}{Z} f∗ZY
成像平面的 p ′ p' p′的坐标与像素坐标 [ u , v ] T [u,v]^T [u,v]T的关系为:
u u u = α ∗ X ′ + c x α*X' + c_x α∗X′+cx
v v v = β ∗ Y ′ + c y β*Y' + c_y β∗Y′+cy
推导出
u u u = α ∗ f ∗ X Z + c x α*f*\frac{X}{Z} + c_x α∗f∗ZX+cx
v v v = β ∗ f ∗ Y Z + c y β*f*\frac{Y}{Z} + c_y β∗f∗ZY+cy
把 α f αf αf合并成 f x f_x fx,把 β f βf βf合并成 f y f_y fy
u u u = f x ∗ X Z + c x f_x*\frac{X}{Z} + c_x fx∗ZX+cx
v v v = f y ∗ Y Z + c y f_y*\frac{Y}{Z} + c_y fy∗ZY+cy
这个是像素点转换到相机坐标系下面的点
Vector3d Camera::pixel2camera ( const Vector2d& p_p, double depth )
{
return Vector3d (
( p_p ( 0,0 )-cx_ ) *depth/fx_,
( p_p ( 1,0 )-cy_ ) *depth/fy_,
depth
);
}
理解:
p_p ( 0,0 ) = u u u
p_p ( 1,0 ) = v v v
那么 P ′ P' P′的坐标与像素坐标 [ u , v ] T [u, v]^T [u,v]T的关系为:
u u u = α ∗ X ′ + c x α*X' + c_x α∗X′+cx
v v v = β ∗ Y ′ + c y β*Y' + c_y β∗Y′+cy
首先推导出
u − c x u - c_x u−cx = α ∗ X ′ α*X' α∗X′
v − c y v - c_y v−cy = β ∗ Y ′ β*Y' β∗Y′
然后推导出
u − c x α \frac{u - c_x}{α} αu−cx = X ′ X' X′
v − c y β \frac{v - c_y}{β} βv−cy = Y ′ Y' Y′
成像平面点和现实世界空间点之间的关系:
X ′ X' X′ = f ∗ X Z f*\frac{X}{Z} f∗ZX
Y ′ Y' Y′ = f ∗ Y Z f*\frac{Y}{Z} f∗ZY
推导出
u − c x α \frac{u - c_x}{α} αu−cx = f ∗ X Z f*\frac{X}{Z} f∗ZX
v − c y β \frac{v - c_y}{β} βv−cy = f ∗ Y Z f*\frac{Y}{Z} f∗ZY
u − c x u - c_x u−cx = α ∗ f ∗ X Z α*f*\frac{X}{Z} α∗f∗ZX
v − c y v - c_y v−cy = β ∗ f ∗ Y Z β*f*\frac{Y}{Z} β∗f∗ZY
把 α f αf αf合并成 f x f_x fx
把 β f βf βf合并成 f y f_y fy
u − c x u - c_x u−cx = f x ∗ X Z f_x*\frac{X}{Z} fx∗ZX
v − c y v - c_y v−cy = f y ∗ Y Z f_y*\frac{Y}{Z} fy∗ZY
u − c x f x \frac{u - c_x}{f_x} fxu−cx = X Z \frac{X}{Z} ZX
v − c y f y \frac{v - c_y}{f_y} fyv−cy = Y Z \frac{Y}{Z} ZY
u − c x f x \frac{u - c_x}{f_x} fxu−cx = X ′ X' X′
v − c y f y \frac{v - c_y}{f_y} fyv−cy = Y ′ Y' Y′
乘上depth的原因,应该是因为下面这个公式
( u v 1 ) \begin{pmatrix} u \\ v \\ 1 \end{pmatrix} ⎝⎛uv1⎠⎞ = Z × ( f x 0 c x 0 f y c y 0 0 1 ) Z×\begin{pmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{pmatrix} Z×⎝⎛fx000fy0cxcy1⎠⎞ ( X Y Z ) \begin{pmatrix} X \\ Y \\ Z \end{pmatrix} ⎝⎛XYZ⎠⎞ ≜ \triangleq ≜ K P KP KP
就不太懂那个频繁用到的函数像素坐标转相机归一化坐标
Point2d pixel2cam(const Point2d &p, const Mat &K);
Vector3d Camera::pixel2camera ( const Vector2d& p_p, double depth )
对比一下
Point2d pixel2cam(const Point2d &p, const Mat &K) {
cout << K.at<double>(0, 2) << endl;
return Point2d
(
(p.x - K.at<double>(0, 2)) / K.at<double>(0, 0),
(p.y - K.at<double>(1, 2)) / K.at<double>(1, 1)
);
}
首先相机内参数是这样的:
( f x 0 c x 0 f y c y 0 0 1 ) \begin{pmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{pmatrix} ⎝⎛fx000fy0cxcy1⎠⎞
K.at(0, 2) = c x c_x cx
K.at(0, 0) = f x f_x fx
K.at(1, 2) = c y c_y cy
K.at(1, 1) = f y f_y fy
(p.x - c x c_x cx) / f x f_x fx
(p.y - c y c_y cy) / f y f_y fy
这刚好是上面代码推导出来的公式
u − c x f x \frac{u - c_x}{f_x} fxu−cx = X ′ X' X′
v − c y f y \frac{v - c_y}{f_y} fyv−cy = Y ′ Y' Y′
所以这个代买求的是成像平面的坐标 可能是省略了 Z=1 所以就是归一化平面坐标了
P w P_w Pw = [ X Y Z ] \begin{bmatrix}X \\Y\\Z\\\end{bmatrix} ⎣⎡XYZ⎦⎤
P c P_c Pc = [ X ′ Y ′ Z ′ ] \begin{bmatrix}X'\\Y'\\Z'\\\end{bmatrix} ⎣⎡X′Y′Z′⎦⎤
R ∗ P w + t R*P_w+t R∗Pw+t = P c P_c Pc
R ∗ [ X Y Z ] + t R*\begin{bmatrix}X \\Y\\Z\\\end{bmatrix}+t R∗⎣⎡XYZ⎦⎤+t = [ X ′ Y ′ Z ′ ] \begin{bmatrix}X'\\Y'\\Z'\\\end{bmatrix} ⎣⎡X′Y′Z′⎦⎤
P c P_c Pc = [ X ′ Z ′ Y ′ Z ′ Z ′ Z ′ ] \begin{bmatrix}\frac{X'}{Z'}\\\frac{Y'}{Z'}\\\frac{Z'}{Z'}\\\end{bmatrix} ⎣⎢⎡Z′X′Z′Y′Z′Z′⎦⎥⎤
假设 P c P_c Pc的像素坐标为: [ u v ] \begin{bmatrix}u\\v\\\end{bmatrix} [uv]
相机模型:相机坐标系下的三维点与成像平面之间通过三角形相似建立关系
u u u = f x ∗ X ′ Z ′ + c x f_x*\frac{X'}{Z'} + c_x fx∗Z′X′+cx
v v v = f y ∗ Y ′ Z ′ + c y f_y*\frac{Y'}{Z'} + c_y fy∗Z′Y′+cy
上述1、2、3、过程称为投影模型
Vector3d Camera::world2camera ( const Vector3d& p_w, const SE3& T_c_w )
{
return T_c_w*p_w;
}
Vector3d Camera::camera2world ( const Vector3d& p_c, const SE3& T_c_w )
{
return T_c_w.inverse() *p_c;
}
Vector2d Camera::camera2pixel ( const Vector3d& p_c ){
return Vector2d (
fx_ * p_c ( 0,0 ) / p_c ( 2,0 ) + cx_,
fy_ * p_c ( 1,0 ) / p_c ( 2,0 ) + cy_
);
}
注意这里隐含了相机到相机归一化平面的过程p_c ( 0,0 ) / p_c ( 2,0 )
和p_c ( 1,0 ) / p_c ( 2,0 )
先把像机坐标系下的点转化到归一化平面
P c P_c Pc = [ X ′ Y ′ Z ′ ] \begin{bmatrix}X'\\Y'\\Z'\\\end{bmatrix} ⎣⎡X′Y′Z′⎦⎤
归一化之后
[ X ′ Z ′ Y ′ Z ′ Z ′ Z ′ ] \begin{bmatrix}\frac{X'}{Z'}\\\frac{Y'}{Z'}\\\frac{Z'}{Z'}\\\end{bmatrix} ⎣⎢⎡Z′X′Z′Y′Z′Z′⎦⎥⎤
归一化后转换成像素坐标(忽略畸变)
fx_ * p_c ( 0,0 ) / p_c ( 2,0 ) + cx_,
fy_ * p_c ( 1,0 ) / p_c ( 2,0 ) + cy_
u u u = f x ∗ X ′ Z ′ + c x f_x*\frac{X'}{Z'} + c_x fx∗Z′X′+cx
v v v = f y ∗ Y ′ Z ′ + c y f_y*\frac{Y'}{Z'} + c_y fy∗Z′Y′+cy
Vector3d Camera::pixel2camera ( const Vector2d& p_p, double depth )
{
return Vector3d (
( p_p ( 0,0 )-cx_ ) *depth/fx_,
( p_p ( 1,0 )-cy_ ) *depth/fy_,
depth
);
}
实际上有一个中间过程,就是先转化为归一化平面的点
这里的depth就是归一化的 X ′ Z ′ \frac{X'}{Z'} Z′X′ Y ′ Z ′ \frac{Y'}{Z'} Z′Y′
u − c x f x \frac{u-c_x}{f_x} fxu−cx = X ′ Z ′ \frac{X'}{Z'} Z′X′
v − c y f y \frac{v- c_y}{f_y} fyv−cy = Y ′ Z ′ \frac{Y'}{Z'} Z′Y′
[ u − c x f x v − c y f y 1 ] \begin{bmatrix}\frac{u-c_x}{f_x}\\\frac{v- c_y}{f_y}\\1\\\end{bmatrix} ⎣⎡fxu−cxfyv−cy1⎦⎤ = [ X ′ Z ′ Y ′ Z ′ Z ′ Z ′ ] \begin{bmatrix}\frac{X'}{Z'}\\\frac{Y'}{Z'}\\\frac{Z'}{Z'}\\\end{bmatrix} ⎣⎢⎡Z′X′Z′Y′Z′Z′⎦⎥⎤
Vector2d Camera::world2pixel ( const Vector3d& p_w, const SE3& T_c_w )
{
return camera2pixel ( world2camera(p_w, T_c_w) );
}
X ∗ f x + c x X*f_x +c_x X∗fx+cx = u u u
Y ∗ f y + c y Y*f_y + c_y Y∗fy+cy = v v v
Vector3d Camera::pixel2world ( const Vector2d& p_p, const SE3& T_c_w, double depth )
{
return camera2world ( pixel2camera ( p_p, depth ), T_c_w );
}
u − c x f x \frac{u-c_x}{f_x} fxu−cx = X X X
v − c y f y \frac{v- c_y}{f_y} fyv−cy = Y Y Y
上面是针孔模型可以对比看看鱼眼EUCM模型
首先,在三维空间中,对于一个质点有三个自由度,需要三个坐标来确定它的位置,这一点应该无可争议。而对于一个刚体,它在三维方向有几何尺度,那么我们需要知道它的摆放方式,这种摆放方式的确定需要另外三个坐标。而为什么是三个坐标呢,因为我们需要三个夹角,刚体中的任意一条线与xyz轴的夹角,就是这三个坐标。
1.相机外参数矩阵。告诉你现实世界点(世界坐标)是怎样经过旋转和平移,然后落到另一个现实世界点(摄像机坐标)上。
2.相机内参数矩阵。内参数矩阵M:将空间三维点投影到像平面上的二维点(注意顺序关系)的矩阵。
3.单应性矩阵H:一个平面上的点到另一个平面上的点的投影映射矩阵。多视场中会用到。
4.本征矩阵E:(以双目视觉为例)将真实世界中的点P在左摄像机观测到的(左摄像机坐标系的)三维坐标Pl与右摄像机观测到的点P的(右摄像机坐标系中的)三维坐标Pl关联起来的矩阵。
5.基础矩阵F:(以双目视觉为例)将点P投影到左摄像机图像坐标系中的二维坐标和右摄像机图像坐标系中的二维坐标点关联起来的矩阵。
等距变换就是对图像的旋转+平移 —图像相对原图大小不变。
相似变换对图像的旋转+平移+缩放 —图像相对原图变小了一些。
仿射变换就是对图像的旋转+平移+缩放+切变(shear),相比前两种变换图像的形状发生了改变,但是原图中的平行线仍然保持平行。
射影变换就是对图像的旋转+平移+缩放+切变+射影,相比前三种变换图像的形变更为自由,原图中的平行线经过变换之后已经不在平行,而可能相交于一点,射影变换就是把理想点(平行直线在无穷远处相交)变换到图像上。应用示例是相机成像原理。