草庐IT

深度科普:一文搞懂相机标定

智星崛起 2023-07-25 原文

相机标定,是图像测量和机器视觉应用时,绕不过去的关键步骤。通过标定,可以获得相机成像几何模型的参数,也就是三维空间中点与二维图像中点的对应关系。本文通过拆解相机成像的原理、过程及相机畸变,探讨相机标定的重要性,并介绍分析了几种常见的相机标定方法。 

01 相机成像的原理

相机成像,实际上是一个光学成像过程。

我们将相机的镜头看作一个凸透镜,光线通过透镜在感光元件(CCD/CMOS)上成像,感光元件将光电信号转换为数字信号,再经数字信息处理(DSP)成数字图像,存储到存储介质当中。

透镜成像原理,凸透镜的中心为光心,光线平行于主光轴(虚线)穿过透镜时,会汇聚到焦点,然后折射成像。其中,机器人a为实物,u为物距;机器人a1为成像,v为相距;f为焦距,表示焦点到光心的距离。

当相机感光元件位于凸透镜焦点附近,焦距与光心到感光元件距离无限接近时,即,相机成像模型就成了我们熟悉的「小孔成像」。

小孔成像模型

在相机成像过程中,一共涉及4个坐标系:

  • 世界坐标系:由用户定义的三维世界坐标系,描述物体和相机在真实世界中的位置,原点可以任意选择。

  • 相机坐标系:以相机的光心为坐标原点,x轴和y轴平行于图像坐标系的x轴和y轴,z轴为相机的光轴。

  • 图像坐标系:与成像平面重合,以成像平面的中心(光轴与成像平面的交点)为坐标原点,x 轴和 y轴分别平行于成像平面的两条边。

  • 像素坐标系:与成像平面重合,以成像平面的左上角顶点为原点,x 轴和 y 轴分别平行于图像坐标系的x轴和y轴。

举个例子,世界坐标系下的点 ,在相机坐标系中的坐标为,投影到图像坐标系后坐标为,对应在像素坐标系中的坐标为

为了便于计算,我们将成像平面和物体放到了同一侧:​

相机成像模型

02 用数学语言拆解相机成像

相机成像过程可以理解为坐标系间的三次变换。在理想情况下(不考虑畸变),变换过程如图:

相机成像过程

首先,世界坐标系→相机坐标系

世界坐标系到相机坐标系的转换属于刚体变换,通过旋转和平移即可获得,其中旋转矩阵为 ,平移矩阵为

然后,相机坐标系→图像坐标系

从相机坐标系到图像坐标系满足透视投影关系:

最后,图像坐标系→像素坐标系

像素坐标系的单位为pixel,其中  为成像平面中心点在像素坐标系下的坐标, 和  分别表示在像素坐标系下,  轴和  轴方向每个像素的物理尺寸。

综合公式,我们就可以直接得到,从世界坐标系到像素坐标系的转换关系式:

 ​其中, 

内参矩阵取决于相机内部参数,外参矩阵取决于相机坐标系和世界坐标系的位置。而相机标定,就可以帮我们求解出内参矩阵和外参矩阵。

 03 相机畸变又该如何矫正

大家有没有觉得,平时用手机拍出来的照片,靠边的人通常会「脸变形」?

这其实是因为相机畸变。真实的镜头在成像时,会有畸变存在。由透镜形状引起的畸变是径向畸变,而由透镜安装与成像平面不平行引起的畸变是切向畸变。

径向畸变主要分为桶形畸变和枕型畸变。

在小孔成像模型中,一条直线投影到像素平面还是一条直线。但实际上,相机的透镜往往使真实环境中的一条直线在图片中变成了曲线,并且越靠近图像边缘越明显。由于透镜往往是中心对称的,不规则畸变也通常径向对称。

另外,如果是在相机组装过程中,透镜和感光元件CCD/CMOS的安装位置存在误差,导致透镜和成像平面没有严格平行,就会引起切向畸变。

这时,我们把一个矩形投影到成像平面,很可能就变成了一个梯形。

不过这些都问题不大,有相应的公式来进行矫正。对于径向畸变,可以用泰勒级数展开式,其中 为畸变后的实际坐标, 为矫正后坐标, 为该点距成像中心的距离:

对于切向畸变,也有矫正公式:

总的来说,相机畸变由 5个参数描述,而这些参数都可以使用相机标定来求解。质量较好的相机,切向畸变小到可忽略,径向畸变系数  也可忽略,只计算  两个参数就可以了。

04 常用的相机标定方法

一般来说,相机标定方法有传统相机标定法、主动视觉相机标定方法、相机自标定法以及零失真相机标定法这4种。

  • 传统相机标定法

需要使用尺寸已知的标定物,通过建立标定物上坐标已知的点与其图像点之间的对应,利用一定的算法获得相机模型的内外参数。

可使用于任意相机模型,精度高,但标定时始终需要标定物,必须采用两幅或两幅以上的图像,且标定物的制作精度会影响标定结果。常见的有Tsai两步法、张氏标定法等。

  • 主动视觉相机标定方法

基于主动视觉的相机标定法,是指已知相机的某些运动信息对相机进行标定。通过控制相机做某些特定运动并拍摄多组图像,依据图像信息和已知位移变化来求解相机内外参数。

这种方法不需要标定物,算法简单、鲁棒性高,缺点是成本高、设备昂贵。

  • 相机自标定法

自标定算法主要利用相机运动的约束,灵活性强,可对相机进行在线定标。

但它是基于绝对二次曲线或曲面的方法,算法鲁棒性差,由于相机的运动约束条件太强,在实际生活中并不实用。常见的有分层逐步标定、基于Kruppa方程等。

  • 零失真相机标定法

是以LCD显示屏为参考基准,以相移光栅为媒介,建立LCD像素与相机传感器像素之间的映射关系,确定每个相机像素点在LCD上的视点位置。

​几种常见相机标定方法对比

这4种标定方法各有优劣,可以根据自己的情况来选用。其中最常用的就是的张正友标定法(张氏标定法),操作简单、精度较高,可以满足大部分场合。

张正友标定法,是利用棋盘格标定板进行标定,将世界坐标系固定在棋盘格上。棋盘格上的每个格子大小都是已知的,即棋盘格每一个角点在世界坐标系下的坐标都可以计算得到。

棋盘标定格

当相机拍摄标定板的图像时,通过相应的图像检测算法,就可以获得每一个角点在像素坐标系下的坐标,进而获得相机的内外参矩阵和畸变参数。需要注意的是,张正友标定法只考虑了径向畸变,没有考虑切向畸变。

以上就是本期的全部分享。至于张正友标定法如何推导等更多内容,记得持续关注「智星崛起」!

有关深度科普:一文搞懂相机标定的更多相关文章

  1. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  2. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

  3. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

  4. ruby Hash 包括另一个哈希,深度检查 - 2

    进行这种深度检查的最佳方法是什么:{:a=>1,:b=>{:c=>2,:f=>3,:d=>4}}.include?({:b=>{:c=>2,:f=>3}})#=>true谢谢 最佳答案 我想我从那个例子中明白了你的意思(不知何故)。我们检查子哈希中的每个键是否在超哈希中,然后检查这些键的对应值是否以某种方式匹配:如果值是哈希,则执行另一次深度检查,否则,检查值是否相等:classHashdefdeep_include?(sub_hash)sub_hash.keys.all?do|key|self.has_key?(key)&&ifs

  5. ruby-on-rails - Ruby 获取深度嵌套的 JSON API 数据 - 2

    我有一个Rails应用程序,它从WorldWeatherOnlineAPI获取响应。我正在使用rest-clientgem,响应采用JSON格式。我使用以下方法解析响应:parsed_response=JSON.parse(response)parsed_response显然是一个散列。我需要的数据是哈希内的字符串,数组内的哈希,另一个数组内的哈希,另一个哈希内的另一个哈希内的字符串。最内层的嵌套散列在["hourly"]中,这是一个由8个散列组成的数组,每个散列有20个键,拥有各种天气参数的字符串值。数组中的每个哈希值都是一天中的不同时间(预测是每三小时一次,3*8=24小时)。因此

  6. 一文解决关于VLAN所有的疑惑 - 2

    一文解决关于VLAN所有的疑惑VLAN基本概念为什么需要VLAN?怎么在交换机上划分VLAN,VLAN的工作原理有了子网,已经隔离了广播,还需要VLAN干啥?只进行子网划分,不进行VLAN划分VLAN划分与子网划分附加VLAN信息的方法VLAN划分交换机的端口类型(Access和Trunk)一、访问链接二、汇聚链接汇聚链接VLAN间通信为什么要进行VLAN间通信?路由器实现VLAN间通信路由器和交换机的连接方式通信细节三层交换机实现VLAN间通信加速VLAN间通信三层交换机与路由器三层交换机路由器路由器和交换机配合构建LAN的实例使用VLAN设计局域网的特点VLAN增加网络的灵活性不使用VLA

  7. ruby-on-rails - 在 Rails 中实现具有灵活深度的类别和子类别的最佳方法? - 2

    我的项目中有一个类别和子类别模型。我想以灵活的方式拥有许多子级别。我想制作一个self引用的“父”外键,但我不太确定该怎么做。有任何想法吗?谢谢!Cat1Sub1SubSub1SubSub2Sub2Cat2Sub1Cat3Sub1Sub2SubSub1 最佳答案 试试acts_as_tree插件 关于ruby-on-rails-在Rails中实现具有灵活深度的类别和子类别的最佳方法?,我们在StackOverflow上找到一个类似的问题: https://st

  8. ruby - 将 OpenStruct 深度转换为 JSON - 2

    我有一个OpenStruct,它嵌套在许多其他OpenStructs中。将它们全部深度转换为JSON的最佳方法是什么?理想情况下:x=OpenStruct.newx.y=OpenStruct.newx.y.z=OpenStruct.newz='hello'x.to_json//{y:z:'hello'}现实{} 最佳答案 没有默认方法来完成这样的任务,因为内置的#to_hash返回哈希表示,但它不会深度转换值。如果值是OpenStruct,它会原样返回,不会转换成Hash。然而,这并不难解决。您可以创建一个遍历OpenStruct实

  9. 相机校准—外参矩阵 - 2

    在本文中,我们将探讨摄影机的外参,并通过Python中的一个实践示例来加强我们的理解。相机外参摄像头可以位于世界任何地方,并且可以指向任何方向。我们想从摄像机的角度来观察世界上的物体,这种从世界坐标系到摄像机坐标系的转换被称为摄像机外参。那么,我们怎样才能找到相机外参呢?一旦我们弄清楚相机是如何变换的,我们就可以找到从世界坐标系到相机坐标系的基变换的变化。我们将详细探讨这个想法。具体来说,我们需要知道相机是如何定位的,以及它在世界空间中的位置,有两种转换可以帮助我们:有助于确定摄影机方向的旋转变换。有助于移动相机的平移变换。让我们详细看看每一个。旋转通过旋转改变坐标让我们看一下将点旋转一个角度

  10. 一文让你彻底掌握操作符(超详细教程) - 2

    ✅作者简介:大家好,我是小杨📃个人主页:「小杨」的csdn博客🔥系列专栏:小杨带你玩转C语言【初阶】🐳希望大家多多支持🥰一起进步呀!大家好呀!我是小杨。小杨花几天的时间将C语言中的操作符这部分知识做了一个大总结,在方便自己复习的同时也能够帮助到大家。通篇字数在一万字左右,可以算作是非常详细了,一文就可以带领大家彻底掌握操作符这部分内容,文章很长建议先收藏再看,防止下次想看就找不到啦。文章目录✍1,算术操作符✍2,移位操作符    🔍2.1,左移操作符    🔍2.2,右移操作符       ✨2.2.1,算术移位       ✨2.2.2,逻辑移位✍3,位操作符    🔍3.1,按位与&   

随机推荐