相机内参、外参、畸变系数简介

一、相机模型

1、简介

初中物理我们就学过小孔成像问题,这也是我们对相机的最初认识。
仅靠一个小孔进光量太小,拍摄到的照片会很暗,所以实际的相机会使用凸透镜来聚光。但是凸透镜的光学模型过于复杂,通常会简化成针孔相机模型来解释成像过程并进行建模。
这时出现了一个疑问,小孔成像成倒立的像,而照片的方向却是正常的?原因在于相机内部会对所成的像再进行一次镜像,所以用户看到的图像就跟人眼看到的方向一致了,我们可以把这一过程等效成把成像平面放到相机前方,示意图如下(之后为了直观,本文所说的成像平面均为镜像过后的等效成像平面)。
在这里插入图片描述

列出几个重要名词,通过下图可以简单建立下概念,后边再细品
在这里插入图片描述

  • 世界坐标系 o w − x w − y w − z w o_w-x_w-y_w-z_w owxwywzw:世界坐标系不是一个有明确定义的坐标系,你可以任意指定一个在当前场景下固定不变的坐标系作为世界坐标系。
  • 相机坐标系 o c − x c − y c − z c o_c-x_c-y_c-z_c ocxcyczc:相机坐标系习惯上这样定义:以相机光心为坐标系原点;假设你在手持相机,那么你的右手边是x轴正方向,下边是y轴正方向,相机前方是z轴正方向,也就是说,拍摄的远处物体距离为正。
  • 图像坐标系 o i − x i − y i o_i-x_i-y_i oixiyi:图像坐标系的原点就位于感光芯片的中心(感光芯片是位于镜头背后的用于成像的小板子),x、y轴方向和相机坐标系x、y相同,不同的是图像坐标系是二维坐标系没有z轴
  • 像素坐标系 o p − x p − y p o_p-x_p-y_p opxpyp:像素坐标系也位于成像平面上,是图像坐标系通过平移和缩放的到的。值得注意的是不同软件或者库对于像素坐标 ( u , v ) (u,v) (u,v)的定义不一样,比如OpenCV中把 u u u定义为行坐标, v v v定义为列坐标,与我们这里的定义就不太一样。所以使用前需要统一像素坐标的定义

2、针孔相机模型

P c P_c Pc点是相机坐标系下坐标, P i P_i Pi是图像坐标系下坐标, Z c Z_c Zc P c P_c Pc点距离光心的距离, f f f是镜头的焦距, X c X_c Xc X i X_i Xi是点在 x x x轴投影距离原点的距离,是正值。
根据相似三角形原理可得:

Z c f = − X c X i = − Y c Y i ( 1 ) \frac{Z_{c}}{f}=-\frac{X_{c}}{X_i}=-\frac{Y_{c}}{Y_i} (1) fZc=XiXc=YiYc1
回忆前文提到的等效成像平面,我们这里再强化一下这个概念,将 P ′ P' P镜像到镜头前方

于是可以将(1)式中的负号去掉
Z c f = X c X i = Y c Y i ( 2 ) \frac{Z_{c}}{f}=\frac{X_{c}}{X_i}=\frac{Y_{c}}{Y_i} (2) fZc=XiXc=YiYc2

二、相机内参

内参矩阵描述的是相机坐标系下的坐标到像素坐标的变换关系

1.相机坐标-图像坐标

利用 ( 2 ) (2) (2)式,很容易可以得出二者的转换关系。
{ X i = f Z c X c Y i = f Z c Y c ( 3 ) \left\{ \begin{aligned} X_i=\frac{f}{Z_{c}}X_{c}\\ Y_i=\frac{f}{Z_{c}}Y_{c} \end{aligned} \right. (3) Xi=ZcfXcYi=ZcfYc3

2.图像坐标-像素坐标

图像坐标是实连续值,而像素坐标是离散的正值,经过简单的平移和尺度缩放,很容易得到二者之间的转换关系如下:
{ u = α X i + c x v = β Y i + c y ( 4 ) \left\{ \begin{aligned} u=\alpha X_i+c_x\\ v=\beta Y_i+c_y \end{aligned} \right. (4) {u=αXi+cxv=βYi+cy(4)

α \alpha α β \beta β与实际传感器的物理尺寸有关,单位为 p i x e l / m pixel/m pixel/m X i X_i Xi Y i Y_i Yi单位为 m m m c x c_x cx c y c_y cy单位为 p i x e l pixel pixel

3.相机坐标-像素坐标

( 3 ) (3) (3)式,将 X i , Y i X_i,Y_i Xi,Yi X , Y , Z X,Y,Z X,Y,Z替换,得到像素坐标与相机坐标系下坐标的关系
{ u = f x X c Z c + c x v = f y Y c Z c + c y ( 5 ) \left\{ \begin{aligned} u=f_x \frac{X_{c}}{Z_{c}}+c_x\\ v=f_y \frac{Y_{c}}{Z_{c}}+c_y \end{aligned} \right.(5)\\ u=fxZcXc+cxv=fyZcYc+cy5
为了表达更加漂亮,引入齐次坐标
( u v 1 ) = 1 Z c ( f x 0 c x 0 f y c y 0 0 1 ) ( X c Y c Z c ) ( 6 ) \left( \begin{matrix} u\\ v\\ 1 \end{matrix} \right) =\frac{1}{Z_c} \left( \begin{matrix} f_x&0&c_x\\ 0&f_y&c_y\\ 0&0&1\\ \end{matrix} \right) \left( \begin{matrix} X_{c}\\ Y_{c}\\ Z_{c} \end{matrix} \right)(6) uv1 =Zc1 fx000fy0cxcy1 XcYcZc 6
Z c ( u v 1 ) = K P c ( 7 ) Z_c \left( \begin{matrix} u\\ v\\ 1 \end{matrix} \right)=KP_{c}(7) Zc uv1 =KPc7
为了避免混淆,一些参考材料会使用 s s s来代替 Z c Z_c Zc,注意他们意思是一样的

思考:

  • 观察(6)式可以发现,由于 1 Z c \displaystyle\frac{1}{Z_c} Zc1的存在,对相机坐标同时乘一个常数后的到的像素坐标是相同的。也就是说从光心发出的射线上的点,在图片里对应的像素坐标是相同的,即点的深度在投影过程中被丢失了。不用特殊手段,单目相机无法得到深度值。但如果给定距离,像素点对应的 P c P_{c} Pc就可唯一确定。
  • 再重新处理一下(6)式
    ( u v 1 ) = ( f x 0 c x 0 f y c y 0 0 1 ) ( X c / Z c Y c / Z c 1 ) ( 8 ) \left( \begin{matrix} u\\ v\\ 1 \end{matrix} \right)= \left( \begin{matrix} f_x&0&c_x\\ 0&f_y&c_y\\ 0&0&1\\ \end{matrix} \right) \left( \begin{matrix} X_c/Z_c\\ Y_c/Z_c\\ 1 \end{matrix} \right)(8) uv1 = fx000fy0cxcy1 Xc/ZcYc/Zc1 8)
    可以认为像素坐标是对相机前方1处平面上的点采样和量化的过程,这个平面称为归一化平面,平面上点的坐标称为归一化坐标

至此,我们推出了想要的结果!这个只和相机内部参数有关的矩阵 K K K即为相机的内参矩阵
K = ( f x 0 c x 0 f y c y 0 0 1 ) ( 7 ) K=\left( \begin{matrix} f_x&0&c_x\\ 0&f_y&c_y\\ 0&0&1\\ \end{matrix} \right)(7) K= fx000fy0cxcy1 (7)
有的时候还会引入一个 λ \lambda λ参数,来描述交轴误差(感光芯片的 X , Y X,Y X,Y轴没有完全垂直)
( f x λ c x 0 f y c y 0 0 1 ) \left( \begin{matrix} f_x&\lambda&c_x\\ 0&f_y&c_y\\ 0&0&1\\ \end{matrix} \right) fx00λfy0cxcy1

注意:

  • 感光芯片的最小单元一般不是严格的正方形,所以得到的 f x f_x fx f y f_y fy不一定相等。
  • K一般会由相机生产商提供,如果没有提供则可以通过单目棋盘格张正友标定法确定,这个过程被称作内参标定
  • 实际使用中交轴误差不需要考虑
  • 再次指出,这个内参矩阵是根据小孔成像模型推导出来的,但是实际的相机镜头组远远比这复杂,如果需要更高精度,应该探索使用其他工具进行标定。

三、外参矩阵

外参矩阵描述的是世界坐标系下坐标与相机坐标系下坐标的转换关系,众所周知,两个坐标系之间的刚体变换可以通过旋转和平移描述,这里其实也没啥好说的。

1.世界坐标-相机坐标

( X c Y c Z c ) = [ R     t ] ( X w Y w Z w 1 )   ( 8 ) \left( \begin{matrix} X_{c}\\ Y_{c}\\ Z_{c} \end{matrix} \right)=[R \ \ \ t] \left( \begin{matrix} X_{w}\\ Y_{w}\\ Z_{w}\\ 1 \end{matrix} \right) \ (8) XcYcZc =[R   t] XwYwZw1  (8)
P c = [ R     t ] P w ~ P_c=[R \ \ \ t]\tilde{P_w} Pc=[R   t]Pw~
这里的 P w ~ \tilde{P_w} Pw~是齐次坐标, P w ~ = [ P w    1 ] T \tilde{P_w}=[P_w \ \ 1]^T Pw~=[Pw  1]T R R R 3 × 3 3\times3 3×3的旋转矩阵, t t t 3 × 1 3\times1 3×1的平移向量, R R R t t t称为相机的外参数。

这个地方如果不理解的,可以去搜索刚体变换,我这里就不写了

2.世界坐标-像素坐标

Z c P u v = Z c ( u v 1 ) = K [ R    t ] P w ~ ( 9 ) Z_cP_{uv}=Z_c \left( \begin{matrix} u\\ v\\ 1 \end{matrix} \right)= K[R\ \ t]\tilde{P_w}(9) ZcPuv=Zc uv1 =K[R  t]Pw~9

四、畸变系数

实际的镜头由于屈光度与光阑位置的不同会导致成像出现径向畸变,透镜与成像平面不平行还会引起切向畸变。径向畸变最为常见,尤其是在照片的边缘上(这提醒我们,拍合照不要坐在边上:),一般鱼眼镜头容易出现桶形畸变,长焦镜头容易出现枕形畸变,效果如下:

如果相机畸变比较明显,那么用内外参获得像素坐标后,还需要再作用畸变系数,径向畸变模型:
u d i s t o r t e d = u ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) v d i s t o r t e d = v ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) u_{distorted}=u(1+k_1r^2+k_2r^4+k_3r^6)\\ v_{distorted}=v(1+k_1r^2+k_2r^4+k_3r^6) udistorted=u(1+k1r2+k2r4+k3r6)vdistorted=v(1+k1r2+k2r4+k3r6)
镜像畸变其实很容易记住,其实就是 f ( r 2 ) f(r^2) f(r2)的泰勒展开,一般情况下只计算 k 1 k_1 k1 k 2 k_2 k2
切向就不记录了,如果有切向畸变那是厂家生产的问题,建议直接换一个,别自己校正了。。。。

不同镜头畸变模型不太一样,比如鱼眼镜头和广角镜头都有,这个地方我平时用不到,引用一篇比较完整的总结常用相机投影及畸变模型(针孔|广角|鱼眼),感兴趣的可以去学习。

  • 25
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我可以为您解答这个问题。下面是将四路相机标定得到的内参外参畸变系数保存为yaml文件的步骤: 1. 首先,您需要将内参外参畸变系数分别存储在独立的Mat对象中。可以使用OpenCV的函数来计算它们。 2. 然后,您需要将这些Mat对象转换为YAML格式的文件。可以使用OpenCV的FileStorage类来实现。 3. 最后,您需要将每个相机内参外参畸变系数分别保存为不同的YAML文件。可以使用FileStorage类的write()函数来完成。 下面是一个示例代码,可以将四路相机标定结果保存为YAML文件: ```cpp // 定义文件名 std::string filename1 = "camera1.yaml"; std::string filename2 = "camera2.yaml"; std::string filename3 = "camera3.yaml"; std::string filename4 = "camera4.yaml"; // 将内参外参畸变系数保存到YAML文件 cv::FileStorage fs1(filename1, cv::FileStorage::WRITE); cv::FileStorage fs2(filename2, cv::FileStorage::WRITE); cv::FileStorage fs3(filename3, cv::FileStorage::WRITE); cv::FileStorage fs4(filename4, cv::FileStorage::WRITE); fs1 << "camera_matrix" << cameraMatrix1; fs1 << "distortion_coefficients" << distCoeffs1; fs1 << "rotation_vector" << rvec1; fs1 << "translation_vector" << tvec1; fs2 << "camera_matrix" << cameraMatrix2; fs2 << "distortion_coefficients" << distCoeffs2; fs2 << "rotation_vector" << rvec2; fs2 << "translation_vector" << tvec2; fs3 << "camera_matrix" << cameraMatrix3; fs3 << "distortion_coefficients" << distCoeffs3; fs3 << "rotation_vector" << rvec3; fs3 << "translation_vector" << tvec3; fs4 << "camera_matrix" << cameraMatrix4; fs4 << "distortion_coefficients" << distCoeffs4; fs4 << "rotation_vector" << rvec4; fs4 << "translation_vector" << tvec4; fs1.release(); fs2.release(); fs3.release(); fs4.release(); ``` 在上面的代码中,cameraMatrix1-4、distCoeffs1-4、rvec1-4和tvec1-4分别是四个相机内参畸变系数、旋转向量和平移向量。利用FileStorage类的write()函数可以将它们保存为YAML文件。最后别忘了使用release()函数释放资源。 希望这可以帮助到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

糊烟乱雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值