1. 相机的参数
参考:Step1:模型 16个相机参数(内参、外参、畸变参数)
摄像机标定(Camera calibration)是从空间点及其对应的像素点,获得相机的位置信息和内部参数信息的过程。
- 相机外参:从世界坐标坐标系到相机坐标系
- 相机内参:从相机坐标系到图像坐标系
简要总结:单目相机共有 16 个参数:
- 10个相机内参(只与相机有关):
- 5个内部矩阵参数
K
K
K:
f
,
d
x
,
d
y
,
u
0
,
v
0
f,d_x,d_y,u_0,v_0
f,dx,dy,u0,v0 。(焦距,素点的长宽,主点在图像坐标系中的坐标)
(也可视作4个参数 f x , f y , u 0 , v 0 f_x, f_y ,u_0,v_0 fx,fy,u0,v0,其中, f x = f / d x f_x=f/d_x fx=f/dx, f y = f / d y f_y=f/d_y fy=f/dy) - 5个畸变参数 D D D: k 1 , k 2 , k 3 , p 1 , p 2 k_1 , k_2 , k_3 , p_1 , p_2 k1,k2,k3,p1,p2 (径向畸变系数,切向畸变系数)
- 5个内部矩阵参数
K
K
K:
f
,
d
x
,
d
y
,
u
0
,
v
0
f,d_x,d_y,u_0,v_0
f,dx,dy,u0,v0 。(焦距,素点的长宽,主点在图像坐标系中的坐标)
- 6个相机外参(相机在{world}的位置):
3个旋转参数 R R R
3个平移参数 T T T
补充知识:齐次坐标
参考:相机标定详细讲解
齐次坐标系:能够明显的区分点与向量,并且便于计算机做图形处理时进行仿射变换的坐标系。例如,在欧式空间,表示一个三维的点和一个三维的向量可以采用如下的方法:
点坐标:
P
=
(
x
,
y
,
z
)
P=(x,y,z)
P=(x,y,z)
向量:
A
⃗
=
x
i
⃗
+
y
j
⃗
+
z
k
⃗
\vec{A}=x \vec{i}+y \vec{j}+z \vec{k}
A=xi+yj+zk
由于向量只有方向和大小,如果只给出
(
x
,
y
,
z
)
(x,y,z)
(x,y,z), 如何确定这是向量还是点呢?
P
P
P可以看做是一个相对于原点的位移,那么
P
−
O
⃗
=
x
i
⃗
+
y
j
⃗
+
z
k
⃗
P-\vec{O}=x \vec{i}+y \vec{j}+z \vec{k}
P−O=xi+yj+zk
P
=
O
⃗
+
x
i
⃗
+
y
j
⃗
+
z
k
⃗
P=\vec{O} + x \vec{i}+y \vec{j}+z \vec{k}
P=O+xi+yj+zk
写成矩阵的形式:
p
=
[
i
⃗
j
⃗
k
⃗
O
⃗
]
[
x
y
z
1
]
p=\left[\begin{array}{llll}\vec{i} & \vec{j} & \vec{k} & \vec{O}\end{array}\right]\left[\begin{array}{l}x \\ y \\ z \\ 1\end{array}\right]
p=[ijkO]⎣⎢⎢⎡xyz1⎦⎥⎥⎤
A
⃗
=
[
i
⃗
j
⃗
k
⃗
O
⃗
]
[
x
y
z
0
]
\vec{A}=\left[\begin{array}{llll}\vec{i} & \vec{j} & \vec{k} & \vec{O}\end{array}\right]\left[\begin{array}{l}x \\ y \\ z \\ 0\end{array}\right]
A=[ijkO]⎣⎢⎢⎡xyz0⎦⎥⎥⎤
可以看到,点和向量区分的方式是最后一个数值是否为1。
从普通坐标系变换到齐次坐标系,如果是点 ( x , y , z ) (x,y,z) (x,y,z)则变换为 ( x , y , z , 1 ) (x,y,z,1) (x,y,z,1),如果是向量 ( x , y , z ) (x,y,z) (x,y,z)则变换为 ( x , y , z , 0 ) (x,y,z,0) (x,y,z,0)。
1.1 小孔成像原理
相机中有四个坐标系,分别为{world},{camera},{image},{pixel}
- 世界坐标系{World},可以任意指定 X w X_w Xw轴和 Y w Y_w Yw轴。
- 相机坐标系{Camera},原点位于小孔, X c X_c Xc轴与光轴重合, X c X_c Xc和 Y c Y_c Yc轴平行于投影面。
- 图像坐标系{Image},原点位于光轴和投影面的交点, X X X和 Y Y Y轴平行投影面。
- 像素坐标系{Pixel},从小孔向投影面方向看,投影面的左上角为原点 O p O_p Op, u , v u, v u,v 轴和投影面两边重合。
{camera}:相机坐标系,
O
c
−
X
c
Y
c
Z
c
O_c-X_c Y_c Z_c
Oc−XcYcZc;
O
c
O_c
Oc 相机中心点,即镜头的光心 ,
{Image}:像平面
π
\pi
π,
O
−
X
Y
O -XY
O−XY。
焦距:
f
f
f。
主轴:从
O
c
O_c
Oc出发,垂直于像平面的射线 。
主点:主轴与像平面的交点
p
p
p。
1.2 相机外参
从{world}到{camera}坐标系变换
设某点
P
P
P 在 {world} 中的坐标为
P
w
=
(
x
w
,
y
w
,
z
w
)
′
P_w =(x_w,y_w,z_w)'
Pw=(xw,yw,zw)′,在 {camera} 中的坐标为
P
c
=
(
x
c
,
y
c
,
z
c
)
′
P_c =(x_c,y_c,z_c)'
Pc=(xc,yc,zc)′,则:
P
c
=
[
R
T
0
1
]
P
w
P_{c}=\left[\begin{array}{cc}R & T \\ 0 & 1\end{array}\right] P_{w}
Pc=[R0T1]Pw
其中,
R
R
R为正交旋转矩阵:
R
=
[
r
11
r
12
r
13
r
21
r
22
r
23
r
31
r
32
r
33
]
R=\left[\begin{array}{lll}r_{11} & r_{12} & r_{13} \\ r_{21} & r_{22} & r_{23} \\ r_{31} & r_{32} & r_{33}\end{array}\right]
R=⎣⎡r11r21r31r12r22r32r13r23r33⎦⎤
T为平移矩阵,
T
=
[
t
x
t
y
t
z
]
T
T=\left[\begin{array}{lll}t_{x} & t_{y} & t_{z}\end{array}\right]^{T}
T=[txtytz]T
[
R
T
0
1
]
\left[\begin{array}{cc}R & T \\ 0 & 1\end{array}\right]
[R0T1]即为外参矩阵。
1.3 相机内参
从{camera}到{image} 坐标系变换
P
c
=
(
x
c
,
y
c
,
z
c
)
′
P_c =(x_c,y_c,z_c)'
Pc=(xc,yc,zc)′ 在{image}中的像点m的齐次坐标为
m
=
(
x
p
,
y
p
,
1
)
′
m=(x_p, y_p, 1)'
m=(xp,yp,1)′。由图中相似三角形可得,
{
x
p
=
f
x
c
z
c
y
p
=
f
y
c
z
c
\left\{\begin{array}{l}x_{p}=\frac{f x_{c}}{z_{c}} \\ y_{p}=\frac{f y_{c}}{z_{c}}\end{array}\right.
{xp=zcfxcyp=zcfyc
写成矩阵表示为,
z
c
m
=
[
f
0
0
0
f
0
0
0
1
]
P
c
z_{c} m=\left[\begin{array}{ccc}f & 0 & 0 \\ 0 & f & 0\\ 0 & 0 & 1\end{array}\right] P_{c}
zcm=⎣⎡f000f0001⎦⎤Pc
实际中,主点可能不在图像坐标系原点,若主点在图像坐标系中的坐标为
p
=
(
x
0
,
y
0
,
1
)
′
p=(x_0, y_0, 1)'
p=(x0,y0,1)′。
则
z
c
m
=
[
f
0
x
0
0
f
y
0
0
0
1
]
P
c
z_{c} m=\left[\begin{array}{ccc}f & 0 & x_0 \\ 0 & f & y_0\\ 0 & 0 & 1\end{array}\right] P_{c}
zcm=⎣⎡f000f0x0y01⎦⎤Pc
从{image}到{pixel}的坐标变换
假设一个像素的长宽为
d
x
,
d
y
d_x,d_y
dx,dy,设像素坐标
P
p
i
x
=
(
u
,
v
,
1
)
′
P_{pix}=(u,v,1)'
Ppix=(u,v,1)′,则:
[
u
v
1
]
=
[
1
/
d
x
0
0
0
1
/
d
y
0
0
0
1
]
[
x
p
y
p
1
]
\left[\begin{array}{l}u \\ v \\ 1\end{array}\right]=\left[\begin{array}{ccc}1 / d_{x} & 0 & 0 \\ 0 & 1 / d_{y} & 0 \\ 0 & 0 & 1\end{array}\right]\left[\begin{array}{c}x_{p} \\ y_{p} \\ 1\end{array}\right]
⎣⎡uv1⎦⎤=⎣⎡1/dx0001/dy0001⎦⎤⎣⎡xpyp1⎦⎤
结合{camera}到{image}的变换,则 {camera}到{pixel}的变换矩阵K 为:
K
=
[
1
/
d
x
0
0
0
1
/
d
y
0
0
0
1
]
[
f
0
x
0
0
f
y
0
0
0
1
]
=
[
f
x
0
u
0
0
f
y
v
0
0
0
1
]
K=\left[\begin{array}{ccc}1 / d_{x} & 0 & 0 \\ 0 & 1 / d_{y} & 0 \\ 0 & 0 & 1\end{array}\right]\left[\begin{array}{ccc}f & 0 & x_{0} \\ 0 & f & y_{0} \\ 0 & 0 & 1\end{array}\right]=\left[\begin{array}{ccc}f_{x} & 0 & u_{0} \\ 0 & f_{y} & v_{0} \\ 0 & 0 & 1\end{array}\right]
K=⎣⎡1/dx0001/dy0001⎦⎤⎣⎡f000f0x0y01⎦⎤=⎣⎡fx000fy0u0v01⎦⎤
其中,
f
x
=
f
/
d
x
f_x=f/d_x
fx=f/dx,
f
y
=
f
/
d
y
f_y=f/d_y
fy=f/dy 称为相机在u轴和v轴方向上的尺度因子。
(
u
0
,
v
0
)
′
=
(
x
0
/
d
x
,
y
0
/
d
y
)
′
(u_0, v_0)'=(x_0/d_x, y_0/d_y)'
(u0,v0)′=(x0/dx,y0/dy)′为相机主点。
K K K即为内参矩阵。
1.4 综合:从{world}到{pixel} 的坐标转换
矩阵表示为:
z
c
[
u
v
1
]
=
K
⋅
[
R
T
0
1
]
[
x
w
y
w
z
w
1
]
z_{c}\left[\begin{array}{l}u \\ v \\ 1\end{array}\right]=K \cdot\left[\begin{array}{ll}R & T \\ 0 & 1\end{array}\right]\left[\begin{array}{c}x_{w} \\ y_{w} \\ z_{w} \\ 1\end{array}\right]
zc⎣⎡uv1⎦⎤=K⋅[R0T1]⎣⎢⎢⎡xwywzw1⎦⎥⎥⎤
1.5 畸变参数
径向畸变(桶形畸变和枕形畸变)
径向畸变产生原因:光线在远离透镜中心的地方偏折更大。矫正公式:
x
c
o
r
=
x
(
1
+
k
1
r
2
+
k
2
r
4
+
k
3
r
6
)
y
c
o
r
=
y
(
1
+
k
1
r
2
+
k
2
r
4
+
k
3
r
6
)
\begin{aligned} x_{cor} &=x\left(1+k_{1} r^{2}+k_{2} r^{4}+k_{3} r^{6}\right) \\ y_{cor} &=y\left(1+k_{1} r^{2}+k_{2} r^{4}+k_{3} r^{6}\right) \end{aligned}
xcorycor=x(1+k1r2+k2r4+k3r6)=y(1+k1r2+k2r4+k3r6)
式中,
(
x
,
y
)
(x,y)
(x,y)是畸变后图像像素点的坐标,
(
x
c
o
r
,
y
c
o
r
)
(x_{cor},y_{cor})
(xcor,ycor)是理想的无畸变的坐标(图像坐标系),r是该点距成像中心的距离
切向畸变 (薄透镜畸变和离心畸变)
切向畸变产生原因:透镜制造上的缺陷使得透镜不完全平行于图像平面,这种现象发生于成像仪被粘贴在摄像机的时候。
矫正公式:
x
c
o
r
=
x
+
[
2
p
1
x
y
+
p
2
(
r
2
+
2
x
2
)
]
y
c
o
r
=
y
+
[
p
1
(
r
2
+
2
y
2
)
+
2
p
2
x
y
]
\begin{aligned} x_{cor} &=x+\left[2 p_{1} x y+p_{2}\left(r^{2}+2 x^{2}\right)\right] \\ y_{cor} &=y+\left[p_{1}\left(r^{2}+2 y^{2}\right)+2 p_{2} x y\right] \end{aligned}
xcorycor=x+[2p1xy+p2(r2+2x2)]=y+[p1(r2+2y2)+2p2xy]
由此得到相机的5个畸变参数:
D
(
k
1
,
k
2
,
k
3
,
p
1
,
p
2
)
D(k_1,k_2,k_3,p_1,p_2)
D(k1,k2,k3,p1,p2)。
对于质量比较好的相机来说,切向畸变很小,可忽略,径向畸变系数
k
3
k_3
k3也可忽略,只计算
k
1
,
k
2
k_1,k_2
k1,k2两个参数。张正友标定中就默认
p
1
,
p
2
p_1,p_2
p1,p2为0。
1.6 一个实例:Azure kinect 相机的参数
K4A Calibration Blob:
RGB Camera Format: bgra
RGB Camera Resolution: 720P
Depth Camera Mode: NFOV_UNBINNED
/depth/camera_info
rgb/camera_info
2. 相机内参标定
2.1 相机标定方法
总上所述,单目相机共有 16 个参数:
- 10个相机内参(只与相机有关):
- 5个内部矩阵参数
K
K
K:
f
,
d
x
,
d
y
,
u
0
,
v
0
f,d_x,d_y,u_0,v_0
f,dx,dy,u0,v0 。(焦距,素点的长宽,主点在图像坐标系中的坐标)
(也可视作4个参数 f x , f y , u 0 , v 0 f_x, f_y ,u_0, v_0 fx,fy,u0,v0,其中, f x = f / d x f_x=f/d_x fx=f/dx, f y = f / d y f_y=f/d_y fy=f/dy) - 5个畸变参数 D D D: k 1 , k 2 , k 3 , p 1 , p 2 k_1 , k_2 , k_3 , p_1 , p_2 k1,k2,k3,p1,p2 (径向畸变系数,切向畸变系数)
- 5个内部矩阵参数
K
K
K:
f
,
d
x
,
d
y
,
u
0
,
v
0
f,d_x,d_y,u_0,v_0
f,dx,dy,u0,v0 。(焦距,素点的长宽,主点在图像坐标系中的坐标)
- 6个相机外参(相机在{world}的位置):
3个旋转参数 R R R
3个平移参数 T T T
通常所说的相机标定即标定相机的内参。一般采用张正友标定法。
张正友标定法只考虑了径向畸变,没有考虑切向畸变。标定流程:
-
准备棋盘格
棋盘格黑白间距已知,可采用打印纸或者购买黑白棋盘标定板(精度要求高)。
-
拍摄若干张标定板图片
此处分两种情况
(1) 标定畸变系数和相机内参,拍摄照片需要包含完整棋盘,同时需要不同距离,不同方位,同时需要有棋盘不同倾斜角度。
(2) 标定畸变系数,相机内参和相机外参,图片包含上述要求,同时标定程序生成结果中每张照片会计算一个相机外参数因此根据实际需求,增加几张棋盘在工作位置的照片。(相机外参建议采用solvePnP函数获取) -
检测图片中的棋盘格内角点,提取亚像素角点信息
-
估算理想无畸变的情况下,五个内参和六个外参。
-
应用最小二乘法估算实际存在径向畸变下的畸变系数。
-
极大似然法,优化估计,提升估计精度。
2.2 camera_calibration
ros:camera_calibration
ros:How to Calibrate a Monocular Camera
camera_calibration 是一个ros功能包,可以方便快捷的完成相机标定。标定步骤如下(未亲测):
首先,请下载标定板。教程中使用的是8X6,边长为108mm的棋盘标定板。由于标定过程使用的是棋盘内部的角点进行,所以实际上我们使用的是9格X7格的棋盘标定板。
请确保标定环境拥有一个5m×5m的无遮挡环境。
1.安装 camera_calibration
rosdep install camera_calibration
rosmake camera_calibration
或者下载github:camera_calibration包,放到catkin_ws/src下,编译:
cd catkin_ws
catkin_make
2.启动相机驱动,如 azure kinect 相机为:
roslaunch azure_kinect_ros_driver driver.launch
rostopic list #可以看到相机发布 /rgb/image_raw ,/rgb/camera_info 等话题
3.运行标定结点。
需要加载你要标定的相机的 image topic。
rosrun camera_calibration cameracalibrator.py --size 8x6 --square 0.108 image:=/rgb/image_raw # camera:=?
来运行标定结点的python脚本,其中
- -–size 8x6 为当前标定板的大小。
- -–square 0.108为每个棋盘格的边长,单位为米。
- image:=/rgb/image_raw 标定当前订阅图像来源自名为/rgb/image_raw的topic。
- camera:=/rgb为像机名。
之后,将会出现如下图所示的UI。如果没有打开,请在启动标定节点时添加 --no-service-check 参数,来检查服务结点是否工作。如果没有看到如图所示的彩色点,请确认–size参数是否正确,尤其注意是否将size设置为了棋盘格数而非其标定角点的数目。
4.移动标定板
为了达到良好的标定效果,需要在像机周围移动标定板:
- 移动标定板到画面的最左、右,最上、下方
- 移动标定板到视野的最近和最远处
- 移动标定板使其充满整个画面
- 保持标定板倾斜状态并使其移动到画面的最左、右,最上、下方
当标定板移动到画面的最左、右方时,此时,UI的x会达到最小或满值
同理,y指示标定板的在画面的上下位置,size表示标定板在视野中的距离。
在每个步骤中,保持棋盘格静止,直到图像在标定窗口中高亮显示。
当calibration按钮亮起时,代表你已经有足够的数据进行摄像头的标定,此时请按下calibration并等待一分钟左右。
最后生成到/tmp/calibrationdata.tar.gz一个包,包内如下图.
2.3 查看标定结果
标定完成后,将在终端中看到标定结果,并在标定窗口中看到校准后的图像。如果标定成功,可以看到本来弯曲标定板的边变成了直线。
如果对标定结果满意,点击Save将结果保存到默认文件夹,点击COMMIT,
数据会自动导入下次启动相机驱动节点时,会自动调用保存的.yaml。
使用camera_calibration_parsers可以进行标定文件格式转换。