棋盘格,我们通常拿来做标定用,但如果可以有这样的效果,是不是感觉高级那么一点点?
在这之前,我们还是先了解几个基本概念:
一、几何畸变
1)几何畸变模型通常定义在归一化的的图像平面上
2)多项式畸变模型(又名Brown-Conrady模型)
- 径向畸变(枕形、桶形):光线在远离透镜中心的地方比靠近中心的地方更加弯曲,用数学表达式表示为:k_1,k_2,…
- 切向畸变:透镜不完全平行于图像平面,即sensor装配时与镜头间的角度不准。用数学表达式表示为:p_1,p_2,…(通常可以忽略不计)。
上述两种畸变如下图所示:
其中,k_1r^2+k_2r^4 为补偿系数,补偿系数服从二次函数。对于该畸变模型我的理解是以图像中心点为圆心相同半径的点补偿量相同,不同半径的补偿量有服从二次函数。如图所示相同半径的圆周上补偿量相同。
3)FOV模型
- 径向畸变通过正切函数建模(对于严重畸变很有效,比如鱼眼镜头)
4)深度相机畸变模型
- 深度相机畸变有两种,第一种是与RGB相机相同的畸变,如上面2中介绍的畸变一样,矫正的是二维平面的畸变,矫正方法可以使用棋盘格。第二种畸变是深度畸变,如果使用深度相机在一个平面上采集图像,理论上深度图像每一个像素值大小都相等,采集的是一个平面,深度图的像素值大小代表深度,但实际采集的深度图不平整,此外深度图边缘畸变较大。
二、几何畸变校正
1)输入:原始图像
2)输出:矫正后的图像
3)已知:相机矩阵和畸变系数
4)多项式畸变模型的解决方法:
- OpenCV cv::undistort() 和 cv::undistortPoints()(包含在imgproc模块中)
cv::projectPoints() (包含在calib3d模块中)。其中而undistort()可以直接对图形去畸变,而undistortPoints()是只针对像素点去畸变。projectPoints()用于计算原2d点和重投影2d点的距离作为重投影误差。
- 相机畸变校正:理论和实践
三、相机标定 #1
1)未知:内参和外参(5* + 6DoF)
- 内参*数量根据用户偏好会有所不同
2)已知:3D点 X_1,X_2,…,X_n,对应的投影点x_1,x_2,…,x_n, 3)限制条件:n x 投影矩阵x_i = K[R|t]X_i
四、相机标定 #2
1)未知:内参 + m x 外参(5* + m x 6DoF) 2)已知:3D点 X_1,X_2,…,X_n,及从第j个相机x_i^jp拍摄对应的投影点 3)限制条件:n x m x 投影矩阵x_i = K[R|t]X_i
4)解决方法:
- OpenCV cv::calibrateCamera() 和 cv::initCameraMatrix2D()
- MATLAB中相机标定工具箱
- GML C++相机标定工具箱
具体的相机标定示例如下:
最后,我们给出相机的绝对位姿估计(Perspective-n-Point,也就是PnP) 1)未知:相机位姿(六自由度) 2)已知:3D点 X_1,X_2,…,X_n,对应的投影点x_1,x_2,…,x_n,和相机矩阵K 3)限制条件:n x 投影矩阵 x_i = K[R|t]X_i 4)解决方法(n≥3)→ 3特征点算法
- OpenCV cv::solvePnP() 和 cv::solvePnPRansac()
- 高效的PnP(EPnP)
部分代码及执行效果如下图所示: