简 介: 本文根据 相机标定(三)-相机成像模型 中的内容整理而成,初步介绍了相机的成像模型。最后介绍了利用OpenCV中的 calibrateCamera函数进行相机参数校正的过程。

关键词相机参数校正棋盘格内参外参

#mermaid-svg-DPngnXyTj6k78gJW {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-DPngnXyTj6k78gJW .error-icon{fill:#552222;}#mermaid-svg-DPngnXyTj6k78gJW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DPngnXyTj6k78gJW .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-DPngnXyTj6k78gJW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DPngnXyTj6k78gJW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DPngnXyTj6k78gJW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DPngnXyTj6k78gJW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DPngnXyTj6k78gJW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DPngnXyTj6k78gJW .marker.cross{stroke:#333333;}#mermaid-svg-DPngnXyTj6k78gJW svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DPngnXyTj6k78gJW .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DPngnXyTj6k78gJW .cluster-label text{fill:#333;}#mermaid-svg-DPngnXyTj6k78gJW .cluster-label span{color:#333;}#mermaid-svg-DPngnXyTj6k78gJW .label text,#mermaid-svg-DPngnXyTj6k78gJW span{fill:#333;color:#333;}#mermaid-svg-DPngnXyTj6k78gJW .node rect,#mermaid-svg-DPngnXyTj6k78gJW .node circle,#mermaid-svg-DPngnXyTj6k78gJW .node ellipse,#mermaid-svg-DPngnXyTj6k78gJW .node polygon,#mermaid-svg-DPngnXyTj6k78gJW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DPngnXyTj6k78gJW .node .label{text-align:center;}#mermaid-svg-DPngnXyTj6k78gJW .node.clickable{cursor:pointer;}#mermaid-svg-DPngnXyTj6k78gJW .arrowheadPath{fill:#333333;}#mermaid-svg-DPngnXyTj6k78gJW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DPngnXyTj6k78gJW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DPngnXyTj6k78gJW .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-DPngnXyTj6k78gJW .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-DPngnXyTj6k78gJW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DPngnXyTj6k78gJW .cluster text{fill:#333;}#mermaid-svg-DPngnXyTj6k78gJW .cluster span{color:#333;}#mermaid-svg-DPngnXyTj6k78gJW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DPngnXyTj6k78gJW :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

相机结构
目 录
Contents
相机是人眼的延伸
什么是成像?
成像模型
小孔成像模型
正交投影
缩放正交投影
透视投影
相机外参
相机内参
从成像平面
到像素平面
从坐标到像素
相机畸变
相机标定
用于标定的棋盘格
相机校正过程
总 结

§01 相机结构


1.1 相机是人眼的延伸

  信息社会中,相机是大众媒体、视觉艺术、将瞬间变成可以回忆的永恒的技术。现在各类图片都是有形形色色的相机拍摄的。人类对于照相机的原理最早可以追溯到 小孔成像 。早在战国初期的 墨子 就利用光直线传播原理介绍了小孔成像原理。直道近代使用透镜成像才开启照相设备的革命。利用透镜成像与我们的眼睛观察世界方式是相同的。

▲ 图1.1.1 人类眼睛构造示意图

  使用了数字技术的单反相机可以获得更加真实的外部世界影像,配合后期计算机图像处理还可以进一步修复图片中的不足。

▲ 图1.1.2 相机镜头 与人眼结构之间对应关系

▲ 图1.1.3 相机镜头 与人眼结构之间对应关系

1.2 什么是成像?

  本质上来说,图像是真实世界场景中在二维平面(成像平面)的投影,它记录了两类信息:

  • 几何信息:位置、点、线等;
  • 光度信息:强度、色彩。

  所以从另外一个角度来看,相机是对三维世界的降维记录的设备。虽然可以 计算机图像处理算法回复3D ,但这也仅仅是计算机利用常见到的场景最大似然重新渲染的结果。

  比如下面就是利用NERF(神经辐射场)让照片动起来的效果。

▲ 图1.2.1 利用NERF(神经辐射场)让照片动起来:

§02 成像模型


  为了更好从成像数据中获取外部世界信息,需要对相机成像进行数学刻画,也就是建立成像模型。这部分的内容包括有:

  • 小孔成像模型(Pinhole camera model
  • 正交投影(Orthographic projection
  • 缩放正交投影(Scaled orthographic projection
  • 透视投影(Perspective projection

2.1 小孔成像模型

  小孔成像模型,也是针对普通数字相机最为广泛应用的一种相机模型,是透视投影(Perspective Projection)的一种最简单的形式。

▲ 图2.1.1 小孔成像模型示意图

  通过将像平面前置到小孔与3D物体之间,形成虚拟像平面,可以简化分析成像过程。

  假设相机的投影中心位于一个欧式坐标系的原点OOO,相机面向z轴正方向,并且成像平面(或者说焦平面)在当前坐标系下的表达为Z=fZ = fZ=f,这个数值也成为相机的焦距。那么,在小孔成像模型的作用下,如下图所示,3D空间中的一个点会被投影为成像平面上的一个2D点,也即连接相机投影中心和3D点的直线与成像平面的交点。

▲ 图2.1.2 将成像平面放置在小孔与物体之间

  通过相似三角形,可以很容易看出3D点(X,Y,Z)T\left( {X,Y,Z} \right)^T(X,Y,Z)T被投影成为成像平面上的(fX/Z,fY/Z,f)T\left( {fX/Z,fY/Z,f} \right)^T(fX/Z,fY/Z,f)T,可以看出:


  上面的公式就描述了小孔成像模型下,3D点映射到2D成像平面上的关系。

  为了将图像转换中与坐标原点相关的平移合并到乘法运算中,常使用齐次坐标来表示图像。比如上面公式中的三维点的齐次坐标为(X,Y,Z,1)T\left( {X,Y,Z,1} \right)^T(X,Y,Z,1)T,二维点其次坐标为(fX/Z,fY/Z,1)T\left( {fX/Z,fY/Z,1} \right)^T(fX/Z,fY/Z,1)T,也等价为(fX,fY,Z)T\left( {fX,fY,Z} \right)^T(fX,fY,Z)T。小孔成像转换可以表示为:

2.2 正交投影

  正交投影适用于:

  • 3D场景距离相机无限远;
  • 所有投影线均平行于光轴。

▲ 图2.2.1 正交投影示意图

2.3 缩放正交投影

  缩放正交投影适用于:

  • 场景深度≪\ll≪到相机的距离;
  • 场景中所有点的Z值均相同,如Z0Z_0Z0​。

▲ 图2.3.1 缩放正交投影示意图

2.4 透视投影

▲ 图2.3.2 透视投影示意图

2.5 相机外参

  相机外参反映了相机在世界坐标空间中的位姿,可通过一个刚性变换来表示,通常包含平移TTT和旋转RRR。


  旋转鞠准是正交的,所以:RT⋅R=IR^T \cdot R = IRT⋅R=I。

§03 相机内参


3.1 从成像平面到像素平面

  相机内的坐标原点往往是图像的左上角,这也是大多数情况下数字图片在内存存储数组起始点的位置。定义光轴与像平面的交点ppp,成为成像主点,它的位置定为(px,py)T\left( {p_x ,p_y } \right)^T(px​,py​)T。

▲ 图3.1 成像平面坐标系

  那么外部3D点(X,Y,Z)\left( {X,Y,Z} \right)(X,Y,Z)在成像平面的坐标为:

  使用齐次坐标表示为:

  从上面公式可以看到使用齐次坐标的好处。公式中不再出现矩阵加法,只有矩阵 与向量之间的乘法。

  最终公式可以简化表达为:

x=KPX=K[I∣0]Xx = KPX = K\left[ {I|0} \right]Xx=KPX=K[I∣0]X

  • 第一个阶段是标准的透视投影过程,也就是[I∣0]X\left[ {I|0} \right]X[I∣0]X。它将3D点(X,Y,Z)T\left( {X,Y,Z} \right)^T(X,Y,Z)T投影到归一化平面,即焦距f=1f = 1f=1的平面上的2D点(X,Y,Z)T\left( {X,Y,Z} \right)^T(X,Y,Z)T,即(X/Z,Y/Z,1)T\left( {X/Z,Y/Z,1} \right)^T(X/Z,Y/Z,1)T。
  • 第二个阶段是基于相机内参的变换,即KKK部分。它将归一化平面坐标系中的点转化为一像素为单位的图像坐标系中。

3.2 从坐标到像素

  实际相机记录数据器件都采用(CCD)对图像进行离散化,形成点阵数据。在此过程中,会出现一些记录时的相机参数。

3.2.1 像素不是正方形

  当相机传感器的像素不是正方形的时候,则需要在X,YX,YX,Y两个方向上乘以缩放因子,代表了单位距离内的像素。

  • x,yx,yx,y : 像素(pixels)坐标;
  • k,lk,lk,l :缩放因子(pixels/mm);
  • fff :焦距(mm)

  可以使用fx=kf,fy=lff_x = kf,f_y = lffx​=kf,fy​=lf 代表X,YX,YX,Y两个方向上的不同焦距。

3.2.2 相机主点不在原点

  也就是光轴与CCD的中心有偏移。假设主点在图像上的坐标(像素)位置为px,pyp_x ,p_ypx​,py​,则:

  那么沿着相机的Z轴,有X=Y=0X = Y = 0X=Y=0,x=px,y=pyx = p_x ,y = p_yx=px​,y=py​。

3.2.3 X轴与Y轴不垂直

  理想情况下,x轴与y轴是相互垂直的。如果它们之间的夹角θ\thetaθ不是90°,则有:

3.2.4 相机内参矩阵

  组合所有参数,可以得到相机的内参矩阵KKK:

3.3 相机畸变

  畸变是光学透镜固有的透视失真特性,目前所有的镜头都存在畸变,只是程度不同。畸变又分为径向畸变和切向畸变,这里只以径向畸变为例。常见的径向畸变有桶形畸变、枕形畸变等:

▲ 图3.3.1 相机畸变:左:桶型畸变;中:枕形畸变;右:鱼眼

  可以通过多项式来描述上述畸变的参数。

▲ 图3.3.2 畸变模型和对应的参数

§04 相机标定


  相机标定的目的就是获取前文提到的相机内参、外参和畸变系数。通常,标定方法分为两步:

  • 从不同角度捕获棋盘格图像;
  • 检测角点并计算相机参数。

  可使用OpenCV或其他相机标定程序来完成参数计算。

4.1 用于标定的棋盘格

  棋盘格图片中具有丰富的角点,可以方便通过图片处理获得规则排列点的像素位置,从而可以获得一组真实世界中的3D位置点与成像后2D上的像素点的位置。它们之间映射关系参数可以通过最小二乘方法进行计算,也就是可以将上述过程中照相机的内参矩阵,畸变参数,外参矩阵进行计算。

  下面是来自于 旋转Apriltag码 博文中的图片。

▲ 图5.1.1 用于校正的棋盘格

4.2 相机校正过程

4.2.1 提取角点

  • 使用函数:findChessboardCorners(image,(w,h),None);

  第一个参数为图片,第二个为图片横纵角点的个数。

img = cv2.imread(outfile)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
img = cv2.imread(outfile)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
ret, corners = cv2.findChessboardCorners(gray, (11, 8), None)if ret:cv2.drawChessboardCorners(img, (8, 6), corners, ret)plt.clf()
plt.figure(figsize=(15,15))
plt.imshow(img)

▲ 图5.2.1 识别出所有的棋盘格角点

4.2.2 相机参数校正

size = gray.shape[::-1]
ret,mtx,dist,rvecs,twecs = cv2.calibrateCamera(obj_points, img_points, size, None, None)print("ret: {}".format(ret),"mtx: {}".format(mtx),"dist: {}".format(dist),"rvecs: {}".format(rvecs),"twecs: {}".format(twecs))
print("ret:", ret)
print("mtx:\n", mtx) # 内参数矩阵
print("dist:\n", dist)  # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print("rvecs:\n", rvecs)  # 旋转向量  # 外参数
print("tvecs:\n", tvecs ) # 平移向量  # 外参数
ret: 0.48959099937033296mtx: [[643.69459427   0.         570.78090348][  0.         634.76121519 337.46417094][  0.           0.           1.        ]]dist: [[ 1.66966910e-01 -5.52524637e-01 -1.35284932e-03  9.90815870e-055.24320869e-01]]rvecs: [array([[-0.16766571],[-0.02841835],[-0.00905039]])]twecs: [array([[-3.39390322],[-1.86924141],[ 6.80979205]])]

※ 总  结 ※


  本文根据 相机标定(三)-相机成像模型 中的内容整理而成,初步介绍了相机的成像模型。最后介绍了利用OpenCV中的 calibrateCamera函数进行相机参数校正的过程。


■ 相关文献链接:

  • 小孔成像
  • 墨子
  • 计算机图像处理算法回复3D
  • 旋转的Apriltag码
  • 相机标定(三)-相机成像模型

● 相关图表链接:

  • 图1.1.1 人类眼睛构造示意图
  • 图1.1.2 相机镜头 与人眼结构之间对应关系
  • 图1.1.3 相机镜头 与人眼结构之间对应关系
  • 图1.2.1 利用NERF(神经辐射场)让照片动起来:
  • 图2.1.1 小孔成像模型示意图
  • 图2.1.2 将成像平面放置在小孔与物体之间
  • 图2.2.1 正交投影示意图
  • 图2.3.1 缩放正交投影示意图
  • 图2.3.2 透视投影示意图
  • 图3.1 成像平面坐标系
  • 图3.3.1 相机畸变:左:桶型畸变;中:枕形畸变;右:鱼眼
  • 图3.3.2 畸变模型和对应的参数
  • 图5.1.1 用于校正的棋盘格
  • 图5.2.1 识别出所有的棋盘格角点
#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# TEST1.PY                     -- by Dr. ZhuoQing 2021-12-30
#
# Note:
#============================================================from headm import *                 # =
import wget
import cv2testid = 0
#------------------------------------------------------------
if testid == 0:imgurl = 'https://img-blog.csdnimg.cn/fd5b6fa046a242a2bc639031b4377f13.png#pic_center'cornernum = (11,8)
else:imgurl = 'https://img-blog.csdnimg.cn/2019041214582967.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JldHJhcHBlZA==,size_16,color_FFFFFF,t_70'cornernum = (8, 6)
outfile = '/home/aistudio/data/chessbimg1.jpg'if os.path.isfile(outfile):os.remove(outfile)
wget.download(imgurl, outfile)#------------------------------------------------------------
img = cv2.imread(outfile)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)#------------------------------------------------------------
ret, corners = cv2.findChessboardCorners(gray, cornernum, None)#------------------------------------------------------------
if ret:cv2.drawChessboardCorners(img, cornernum, corners, ret)
plt.clf()
plt.figure(figsize=(15,15))
plt.imshow(img)#------------------------------------------------------------
criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)
objp = zeros((cornernum[0]*cornernum[1], 3), float32)
objp[:,:2] = mgrid[0:cornernum[0],0:cornernum[1]].T.reshape(-1,2)
printt("objp: {}".format(objp))
obj_points = []
img_points = []
obj_points.append(objp)
img_points.append(corners)#------------------------------------------------------------
corners2 = cv2.cornerSubPix(gray, corners, (5,5), (-1,-1), criteria)#------------------------------------------------------------
size = gray.shape[::-1]
ret,mtx,dist,rvecs,twecs = cv2.calibrateCamera(obj_points, img_points, size, None, None)
printt("","ret: {}\n".format(ret),"mtx: {}\n".format(mtx),"dist: {}\n".format(dist),"rvecs: {}\n".format(rvecs),"twecs: {}".format(twecs))#------------------------------------------------------------#------------------------------------------------------------
#        END OF FILE : TEST1.PY
#============================================================

相机成像与校正原理:将外部世界进行降维相关推荐

  1. ORB-SLAM2从理论到代码实现(四):相机成像原理、基本矩阵、本质矩阵、单应矩阵、三角测量详解

    由于ORBmatcher.cc中有三角化和重投影等内容,所有我先写相机成像等多视图几何内容. 1. 相机的成像原理 假设空间中有一点P,它在世界坐标系中的坐标为,在相机坐标系中的坐标为,在图片中的像素 ...

  2. 【自动驾驶】16.计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换

    本篇博客为转载,我对其中的细节添加了一些说明. 原文链接:https://blog.csdn.net/chentravelling/article/details/53558096 0.前言 最近整理 ...

  3. 相机成像原理_【科研进展】动态虚拟相机:探索三维视觉成像新方法

    由于微信公众号试行乱序推送,您可能没办法准时收到"爱光学"的文章.为了让您第一时间看到"爱光学"的新鲜推送, 请您: 1. 将"爱光学"点亮 ...

  4. 计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换(转载)

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/chentravelling/article/details/53558096 0.前言 最近整理了& ...

  5. 透视变换原理、相机成像、灭点

    相机成像 设世界坐标为(Xw,Yw,Zw)(X_w,Y_w,Z_w)(Xw​,Yw​,Zw​),相机坐标为(Xc,Yc,Zc)(X_c,Y_c,Z_c)(Xc​,Yc​,Zc​),则世界坐标系和相机坐 ...

  6. 【图像处理】相机成像原理

    这里对于相机成像原理做一个简单的介绍. 如下图所示,在最左端的顶点为相机,它的镜头正对着地面上的点O,横向视场角为a,纵向视场角为θ,它所看到的区域就是就是如下所示的四边形,存在一定的投影变换. 而地 ...

  7. opencv相机标定(1)-畸变校正原理

    理想相机成像模型 看到一篇博客,介绍的十分详细.参考 链接 (为了好理解,个人还是喜欢分四大坐标系,世界坐标系,摄像机坐标系,图像物理坐标系,图像像素坐标系) 1)世界坐标系->摄像机坐标系 R ...

  8. 相机成像模型、相机内参、外参、以及相机标定

    看了一圈各个平台讲解相机模型.相机标定的文章,很多只是简单罗列几个公式,其中的细节都没说明,本着学习的出发点写下这篇文章,希望能给初学者解惑.本文主要讲解相机模型,一步步推导从世界坐标系到图像坐标系的 ...

  9. 几何角度理解相机成像过程

    本笔记从几何角度来理解相机的成像过程,我们生活在三维世界中,相机所捕捉到的画面是2D的,3D空间中的点是如何投影到2D平面的过程是本笔记关注的. 预设场景 本笔记讨论的东西基于以下场景: 在一个房间内 ...

最新文章

  1. Windows Service 2008 R2 远程桌面关闭,自动注销的解决方法
  2. Java 中 StringBuilder 在高性能用法总结
  3. 网站数据分析四:网站用户分析
  4. spring整合hibernate的applicationContext.xml文件配置以及web.xml
  5. Cisco ASA站点间穿越nat互相访问的实验
  6. 邵阳市工业学校计算机29班,邵阳市南门口大祥区沙子坡文明路11号计算机学校...
  7. Spring框架学习[IoC容器高级特性]
  8. 吸烟增加后代患哮喘的风险
  9. 威纶触摸屏使用说明书_PLC变频器触摸屏综合实训
  10. arcgis python 百度网盘 视频_arcgis软件零基础入门视频教程27讲百度网盘链接
  11. Nodejs页面访问加载静态资源
  12. python虚拟变量回归_第二周:python实现线性回归(哑变量回归)的高效方法
  13. c语言.jpg图片转成数组_如何把pdf转成jpg?PDF转jpg过程详解
  14. 【THUSC2017】座位
  15. C# - Entity Framework 对一个或多个实体的验证失败。有关详细信息,请参阅“EntityValidationErrors”属性
  16. vue详细知识,语法和必备知识
  17. uni.uploadFile上传手机内部图片
  18. Python编程:从入门到实践(基础知识)
  19. POI Word表格删除行removeRow()
  20. level 1与level 2的区别

热门文章

  1. Java零拷贝续——DirectByteBuffer内存回收
  2. linux tomcat 绑定域名
  3. linux安装node js的二进制文件安装方式的注意事项
  4. 京东全球购11·11战报:面膜售出430万片,爽肤水销售额是同期7倍
  5. 最好用的嵌入式网络C库、Lua库
  6. lvs keepalived
  7. javascript pattern
  8. webClient 利用代理连接Rss资源
  9. 撩课-Java面试宝典-第五篇
  10. Oracle 中count(1) 和count(*) 的区别