相机畸变矫正原理及代码实现

在视觉工程中,涉及到测量任务时,第一步就是对相机的畸变进行矫正。此篇博文首先对坐标系变换进行简介,之后介绍畸变矫正方法,最后给出OpenCV  C++的实现代码。


目录

一、坐标系简介

1、像素坐标系

2、图像坐标系

3、相机坐标系

4、世界坐标系

二、相机的内参和外参

三、图像的畸变和矫正

四、畸变矫正代码实现

       1、标定板图像采集

       2、角点检测 & 亚像素级校准

       3、完成相机标定

 


一、坐标系简介

在视觉应用中,总共有四个坐标系需要了解,分别是:像素坐标系(p)图像坐标系(i)相机坐标系(c)世界坐标系(w)。我们将会从像素坐标系依次映射到世界坐标系。

1、像素坐标系

像素坐标系对于我们并不陌生,数字图像在计算机内部存储的形式类似于像素坐标系,如下图所示。图像中任意一点的坐标可以表示为:\left ( u_{i},v_{i}}} \right )

2、图像坐标系

将像素坐标系的中心平移到中心,就得到了图像坐标系,此坐标系可以方便地反映出物体地尺寸信息。坐标系如下图所示:

设图像坐标系的中心为O_{i}\left ( u_{0},v_{0}}} \right ),相机中感光器件的尺寸为dx * dy,则两坐标系之间的关系可表示为:

      \large \left\{\begin{matrix} x=udx-u_{0}dx\\ y=vdy-v_{0}dy \end{matrix}\right.

将其写成矩阵形式:

      \large \begin{bmatrix} x\\ y \end{bmatrix}= \begin{bmatrix} dx & 0\\ 0& dy \end{bmatrix} \begin{bmatrix} u\\ v \end{bmatrix}+ \begin{bmatrix} -u_{0}dx\\ -v_{0}dy \end{bmatrix}

将偏移项纳入乘积项,转化为齐次坐标形式:

      \large \begin{bmatrix} x\\ y\\ 1 \end{bmatrix} = \begin{bmatrix} dx &0 &0 \\ 0 & dy &0 \\ 0 & 0 & 0 \end{bmatrix}\begin{bmatrix} u\\ v\\ 0 \end{bmatrix}+ \begin{bmatrix} -u_{0}dx\\ -v_{0}dy\\ 1 \end{bmatrix}=\begin{bmatrix} dx &0 &-u_{0}dx \\ 0 & dy &-v_{0}dy \\ 0 & 0 & 1 \end{bmatrix}\begin{bmatrix} u\\ v\\ 1 \end{bmatrix}

3、相机坐标系

相机坐标系算是比较难理解的一个。相机坐标系中心\large O_{c}与图像坐标系中心\large O_{i}的连线就是Z轴,x和y轴分别平行。并且\large O_{c}\large O_{i}连线的距离就是焦距\large f。一个物体从相机坐标系B\left ( X_{c},Y_{c},Z_{c} \right )成像到图像坐标系P\left ( x,y \right ),过程如图:

根据距离关系有:  

        \large \frac{f}{Z_{c}}=\frac{x}{X_{c}}=\frac{y}{Y_{c}}

即:

      \large X_{c}=\frac{xZ_{c}}{f},Y_{c}=\frac{yZ_{c}}{f}

转化为齐次形式:

      \large \begin{bmatrix} X_{c}\\ Y_{c}\\ Z_{c}\\1 \end{bmatrix}= \begin{bmatrix} \frac{Z_{c}}{f} &0 &0 \\ 0& \frac{Z_{c}}{f} &0 \\ 0 & 0& Z_{c}\\0&0&1 \end{bmatrix}\begin{bmatrix} x\\ y\\ 1 \end{bmatrix}

4、世界坐标系

安装相机时,会分别绕相机坐标系的X、Y、Z轴做平移和旋转操作,最后得到世界坐标系。注意,此时\large X_{w},Y_{z},Z_{w}三个轴与其他坐标系并不平行。

首先考虑平移操作:

         \large \left\{\begin{matrix} X_{w}=X_{c}+t_{x}\\ Y_{w}=Y_{c}+t_{y}\\ Z_{w}=Z_{c}+t_{z} \end{matrix}\right.

其次考虑旋转操作,分别绕X、Y、Z轴旋转有旋转矩阵\large R_{x},R_{y},R_{z}

1.基本旋转矩阵:\large R=\begin{bmatrix} cos\theta &sin\theta \\ -sin\theta & cos\theta \end{bmatrix}

2.基本矩阵:\large \begin{bmatrix} 1 &0 & 0 &0 \\ 0& 1&0 &0 \\ 0& 0&1 &0 \\ 0 & 0 & 0 &1 \end{bmatrix}

故整个相机坐标系到世界坐标系的变换公式为:

      \large \begin{bmatrix} X_{w} & Y_{w} &Z_{w} & 1 \end{bmatrix}= \begin{bmatrix} X_{c} & Y_{c} &Z_{c} & 1 \end{bmatrix} \begin{bmatrix} R &0 \\ T& 1 \end{bmatrix}{\color{DarkBlue} }

其中:\large R=R_{x}R_{y}R_{z},T=\begin{bmatrix} t_{x} & t_{y} & t_{z} \end{bmatrix}


二、相机的内参和外参

通过几个坐标系的转化,我们现在可以直接从像素坐标系变换到世界坐标系

      \large \begin{bmatrix} X_{w}\\ Y_{w}\\ Z_{w}\\ 1 \end{bmatrix}= \begin{bmatrix} R & T\\ 0 & 1 \end{bmatrix}\begin{bmatrix} \frac{Z_{c}}{f}&0 &0 \\ 0 &\frac{Z_{c}}{f} & 0\\ 0 &0 &Z_{c} \\ 0 & 0& 1 \end{bmatrix}\begin{bmatrix} dx &0 &-u_{0}dx\\ 0& dy&-v_{0}dy \\ 0&0 & 1 \end{bmatrix}\begin{bmatrix} u\\ v\\ 1 \end{bmatrix}

         \large \Rightarrow \large \begin{bmatrix} X_{w}\\ Y_{w}\\ Z_{w}\\ 1 \end{bmatrix}= \begin{bmatrix} R & T\\ 0 & 1 \end{bmatrix} \begin{bmatrix} \frac{Z_{c}dx}{f}&0 &\frac{-Z_{c}u_{0}dx}{f} \\ 0 &\frac{Z_{c}dy}{f} &\frac{-Z_{c}v_{0}dy}{f} \\ 0 &0 &Z_{c} \\ 0 & 0& 1 \end{bmatrix} \begin{bmatrix} u\\ v\\ 1 \end{bmatrix}

其中,u和v是像素坐标系中的坐标,XYZ是世界坐标系中的坐标,剩余的两个矩阵分别为:

★ RT01矩阵:相机外参,是相机相对于世界坐标系的旋转和平移变换关系。

★ 4*3矩阵:相机内参,是相机的固有属性,含有焦距、像元尺寸等参数。

相机畸变矫正中,重要的一步就是获取相机的内参。


三、图像的畸变和矫正

图像的畸变主要有两种:径向畸变切向畸变

径向畸变:正中心位置的畸变最小,随着半径的增大,畸变增大。径向畸变可以分为枕形畸变和桶形畸变:

径向畸变矫正公式如下(泰勒级数展开式前3项):

      \large \left\{\begin{matrix} x_{dr}=x(1+k_{1}r^{2}+k_{2}r^{4}+k_{3}r^{6})\\ y_{dr}=y(1+k_{1}r^{2}+k_{2}r^{4}+k_{3}r^{6}) \end{matrix}\right.

其中\left ( x,y \right )是理想坐标,\large x_{dr}\large y_{dr}是畸变后的像素点坐标,且:\large r^{2}=x^{2}+y^{2}

切向畸变:在透镜与成像平面不平行时就会产生,类似于透视变换。

切向畸变的矫正公式如下:

\large \left\{\begin{matrix} x_{dt}=2p_{1}xy +p_2}\left ( r^{2}+2x^{2} \right )+1 \\ y_{dt}=p_2}\left ( r^{2}+2y^{2} \right )+2p_{2}xy +1 \end{matrix}\right.

两种畸变最后都归结到五个参数:\large k_{1},k_{2},k_{3},p_{1},p_{2};知道这五个参数后即可完成畸变的矫正。

 


四、畸变矫正代码实现

畸变矫正在OpenCV中已经做的很成熟了,只需要调用封装好的API就可以。接下来简要地说明一下流程:

1. 完成标定板图像的采集(至少3张)

2. 利用findChessboardCorners()函数检测标定板角点,并利用find4QuadCornerSubpix()函数完成亚像素级校准

3. 利用calibrateCamera()函数进行相机标定,得到内参矩阵和畸变系数

 1、标定板图像采集

 将标定板置于不同的角度进行拍摄,此时采集的图像为畸变图像。

2、角点检测 & 亚像素级校准

主要用到了两个OpenCV内置函数:

1、角点检测函数
bool findChessboardCorners(InputArray image, 
			Size patternSize,
			OutputArray corners, 
			int flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE 
			); 
// image:传入拍摄的棋盘图Mat图像,必须是8位的灰度或者彩色图像
// patternSize:每个棋盘图上内角点的行列数,一般情况下,行列数不要相同,便于后续标定程序识别标定板的方向;
// corners:用于存储检测到的内角点图像坐标位置,一般用元素是Point2f的向量来表示:vector<Point2f> image_points_buf;
// flage:用于定义棋盘图上内角点查找的不同处理方式,有默认值。
2、提取亚像素角点信息
专门用来获取棋盘图上内角点的精确位置,降低相机标定偏差,还可以使用cornerSubPix函数
bool find4QuadCornerSubpix(InputArray img, 
			InputOutputArray corners, 
			Size region_size
                        );
// img:输入的Mat矩阵,最好是8位灰度图像,检测效率更高
// corners:初始的角点坐标向量,同时作为亚像素坐标位置的输出vector<Point2f> iamgePointsBuf;
// region_size:角点搜索窗口的尺寸

角点检测结果可以可视化出来:

 3、完成相机标定

3、相机标定
double calibrateCamera( InputArrayOfArrays objectPoints,
    			InputArrayOfArrays imagePoints,
			Size imageSize,
			CV_OUT InputOutputArray cameraMatrix,
			CV_OUT InputOutputArray distCoeffs,
			OutputArrayOfArrays rvecs, 
			OutputArrayOfArrays tvecs,
			int flags=0, 
			TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, DBL_EPSILON)
			);  
// objectPoints:世界坐标系中的三维点,三维坐标点的向量的向量vector<vector<Point3f>> object_points
// imagePoints:每一个内角点对应的图像坐标点,vector<vector<Point2f>> image_points_seq形式
// imageSize:图像的像素尺寸大小(列数=cols,行数=rows)(宽度=width,高度=height)
// cameraMatrix:相机的3*3内参矩阵,Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0));
// distCoeffs:1*5畸变矩阵,Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0))
// rvecs:旋转向量,输入一个Mat类型的vector,即vector<Mat>rvecs;
// tvecs:位移向量,和rvecs一样,应该为vector<Mat> tvecs;
// flags:标定时所采用的算法
// criteria:最优迭代终止条件设定

具体代码细节请参看:https://blog.csdn.net/piaoxuezhong/article/details/75268535

发布了50 篇原创文章 · 获赞 59 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_36342854/article/details/88933308