相机成像经历三个过程:
1、世界坐标系到相机坐标系。
外参变换,涉及外参参数:
(1)、世界坐标系到相机坐标系的旋转矩阵 R
(2)、世界坐标系到相机坐标系的平移矩阵 T
2、相机归一化坐标系(z=1)平面内坐标投影畸变
畸变矫正, 涉及内参畸变参数:
径向畸变系数:k1, k2, k3
切向畸变系数:p1, p2
3、相机归一化坐标系(z=1)平面投影到像平面
相平面投影,涉及内参畸变参数:
投影焦距:fx, fy
相位平移:cx, cy
下面详细讲解每一个过程:
一、世界坐标到相机坐标系:
世界坐标系到相机坐标系是刚体变换,不会产生形变,只有旋转和平移变换。
用矩阵公式描述如下:
其中 R 属于世界坐标系到相机坐标系的旋转矩阵, t 为世界坐标系原点到相机坐标系原点的平移矩阵。
1、标定过程
外参标定参数也就是标定 R ,t 参数,及从世界坐标到相机坐标的变换矩阵参数
标定按旋转的欧拉角从世界坐标系转换到相机坐标系的过程,按z轴旋转、y轴旋转、x轴旋转的顺序最终得到相机坐标系。
2、坐标变换过程
那么从相机坐标系到世界坐标系的单位旋转矩阵如下:
那么从相机坐标系到世界坐标系的旋转矩阵如下:
那么从世界坐标系到相机坐标系的旋转矩阵如下:
即为相机坐标系到世界坐标系的逆矩阵或转置矩阵
世界坐标系到相机坐标系的平移矩阵如下:
所以从世界坐标系到相机坐标系为, 先旋转后平移:
相机坐标系到世界坐标系为上述逆过程,先平移后旋转:
标定外参参数为:
二、畸变投影成像:
distortion:失真,畸变
相机坐标系中将三维世界中的坐标点映射到二维图像平面的过程能够用一个几何模型进行描述,这个几何模型就是所谓的相机模型。模型有很多种,其中一种最简单有效的模型称为针孔模型。
相机成像前需要将相机坐标系下的点统一到归一化相机平面上,即Z=1平面上。因为是射线投影,归一化不影响成像。
即从世界坐标经过RT变换系映射到相机坐标系后,进行归一化。
1、畸变过程
为了获得好的成像效果,我们在相机的前方加了透镜。透镜的加入对成像过程中光线传播会产生新的影响:
①是透镜自身的形状对光线传播的影响,
②是在机械组装过程中,透镜和成像平面不可能完全平行
径向畸变:
由透镜形状引起的畸变称之为径向畸变。在实际拍摄的照片中,摄像机的透镜往往使得真实环境中的一条直线在图片中变成了曲线。越靠近图像的边缘,这种现象越明显。由于实际加工制作的透镜往往是中心对称的,这使得不规则的畸变通常径向对称。主要分为两大类,桶形畸变和枕形畸变。
切向畸变:
透镜和成像面不平行导致。
重要:
畸变是发生在相机归一化平面上,即相机坐标系中 z=1 平面,所以有关畸变矫正和去畸变过程都是发生在相机归一化平面上。
径向畸变:
切向畸变:
上面的x, y 即为归一化平面上的3D点,,即 (x, y, 1)^T 。切记不是成像平面上的点
经过畸变矫正后的归一化平面投影点为:
即:
内参畸变系数为:
2 、成像过程
从畸变后的归一化平面通过内参参数投影到像平面即可。
即
内参投影参数为:
三、逆向去畸变:
首先我们得到的一幅图像是经过畸变之后的图像。假如我们有以下任务:
1、如何获取去畸变的图像?
2、一个畸变图像上的点(u, v),如何映射到相机坐标系归一化平面上?
因为涉及参数太多,阶次又高,给定畸变后的点(x_d, y_d, 1), 几乎是不可能求得非畸变的点(x, y, 1)的。所以无法通过逆变换求得非畸变点。
1、整张图像去畸变
原理:将去畸变的图像作为目标图像,寻找对应到畸变图像上的像素点。
1、初始化网格矩阵
2、对任意网格点(i,j),反投影到相机坐标系归一化平面上。
得到没有畸变情况下的归一化平面上的点 [x_j, y_i]
3、对 归一化平面上的点 [x_j, y_i] 进行畸变矫正,得到归一化平面上的畸变点 [x_d, y_d] :
4、归一化平面上的畸变点 [x_d, y_d] 按成像过程投影到像平面上,得到对应的畸变图像位置[u_d, v_d]。
5、一般[u_d, v_d] 为浮点数,所以需要经过插值算法获取到对应的像素值。
2、单点迭代去畸变
只有去畸变的归一化平面点,才可以从相机坐标系中映射回世界坐标系。
所以对于一个有畸变的像素点,如何求解的它对应的归一化平面的非畸变点呢?
解决思路:
将畸变变换看成是一个可收敛的单调映射过程。如果非单调,无法用这种方法求解,类似于二分查找。
迭代法去畸变:
1、畸变点 [u_d, v_d] 映射到 归一化平面上,为归一化平面上畸变投影点[x_d, y_d]。
假设 畸变投影点[x_d, y_d] 由 [x_m, y_m] 经过畸变得到。
1、给定 初始化: [x_m, y_m] = [x_d, y_d]
2、迭代,设置迭代最大次数 N, 迭代流程如下,
3、结束条件为 d_x < 1e-6, d_y < 1e-6。
迭代结束后,得到 [x_m, y_m] 即为 非畸变的映射点。
python 代码如下:
x_d = np.array([mx_d, my_d])
x_m = x_d
max_iter = 10
for i in range(0, max_iter):
delta = x_d - self.distortion2(x_m)
x_m = x_m + delta
if (abs(delta) < 1e-6).all():
break