相机成像与校正原理:将外部世界进行降维
简 介: 本文根据 相机标定(三)-相机成像模型 中的内容整理而成,初步介绍了相机的成像模型。最后介绍了利用OpenCV中的 calibrateCamera函数进行相机参数校正的过程。
关键词
: 相机参数校正,棋盘格,内参,外参
§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物体之间,形成虚拟像平面,可以简化分析成像过程。
假设相机的投影中心位于一个欧式坐标系的原点 O O O,相机面向z轴正方向,并且成像平面(或者说焦平面)在当前坐标系下的表达为 Z = f Z = f Z=f,这个数值也成为相机的焦距。那么,在小孔成像模型的作用下,如下图所示,3D空间中的一个点会被投影为成像平面上的一个2D点,也即连接相机投影中心和3D点的直线与成像平面的交点。
▲ 图2.1.2 将成像平面放置在小孔与物体之间
通过相似三角形,可以很容易看出3D点 ( X , Y , Z ) T \left( {X,Y,Z} \right)^T (X,Y,Z)T被投影成为成像平面上的 ( f X / Z , f Y / 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,二维点其次坐标为 ( f X / Z , f Y / Z , 1 ) T \left( {fX/Z,fY/Z,1} \right)^T (fX/Z,fY/Z,1)T,也等价为 ( f X , f Y , Z ) T \left( {fX,fY,Z} \right)^T (fX,fY,Z)T。小孔成像转换可以表示为:
2.2 正交投影
正交投影适用于:
- 3D场景距离相机无限远;
- 所有投影线均平行于光轴。
▲ 图2.2.1 正交投影示意图
2.3 缩放正交投影
缩放正交投影适用于:
- 场景深度 ≪ \ll ≪到相机的距离;
- 场景中所有点的Z值均相同,如 Z 0 Z_0 Z0。
▲ 图2.3.1 缩放正交投影示意图
2.4 透视投影
▲ 图2.3.2 透视投影示意图
2.5 相机外参
相机外参反映了相机在世界坐标空间中的位姿,可通过一个刚性变换来表示,通常包含平移 T T T和旋转 R R R。
旋转鞠准是正交的,所以:
R
T
⋅
R
=
I
R^T \cdot R = I
RT⋅R=I。
§03 相机内参
3.1 从成像平面到像素平面
相机内的坐标原点往往是图像的左上角,这也是大多数情况下数字图片在内存存储数组起始点的位置。定义光轴与像平面的交点 p p p,成为成像主点,它的位置定为 ( p x , p y ) 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 = K P X = K [ I ∣ 0 ] X x = KPX = K\left[ {I|0} \right]X x=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 = 1 f = 1 f=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。
- 第二个阶段是基于相机内参的变换,即 K K K部分。它将归一化平面坐标系中的点转化为一像素为单位的图像坐标系中。
3.2 从坐标到像素
实际相机记录数据器件都采用(CCD)对图像进行离散化,形成点阵数据。在此过程中,会出现一些记录时的相机参数。
3.2.1 像素不是正方形
当相机传感器的像素不是正方形的时候,则需要在 X , Y X,Y X,Y两个方向上乘以缩放因子,代表了单位距离内的像素。
- x , y x,y x,y : 像素(pixels)坐标;
- k , l k,l k,l :缩放因子(pixels/mm);
- f f f :焦距(mm)
可以使用 f x = k f , f y = l f f_x = kf,f_y = lf fx=kf,fy=lf 代表 X , Y X,Y X,Y两个方向上的不同焦距。
3.2.2 相机主点不在原点
也就是光轴与CCD的中心有偏移。假设主点在图像上的坐标(像素)位置为 p x , p y p_x ,p_y px,py,则:
那么沿着相机的Z轴,有 X = Y = 0 X = Y = 0 X=Y=0, x = p x , y = p y x = p_x ,y = p_y x=px,y=py。
3.2.3 X轴与Y轴不垂直
理想情况下,x轴与y轴是相互垂直的。如果它们之间的夹角 θ \theta θ不是90°,则有:
3.2.4 相机内参矩阵
组合所有参数,可以得到相机的内参矩阵 K K K:
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.48959099937033296
mtx: [[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-05
5.24320869e-01]]
rvecs: [array([[-0.16766571],
[-0.02841835],
[-0.00905039]])]
twecs: [array([[-3.39390322],
[-1.86924141],
[ 6.80979205]])]
※ 总 结 ※
本文根据 相机标定(三)-相机成像模型 中的内容整理而成,初步介绍了相机的成像模型。最后介绍了利用OpenCV中的 calibrateCamera函数进行相机参数校正的过程。
■ 相关文献链接:
● 相关图表链接:
- 图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 cv2
testid = 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
#============================================================
相关文章
- CSS 3D - rotate旋转90度看不到的原理 和 解决方法
- 【生活现场】从诗词大会飞花令到elasticsearch原理解析(转)
- Vue2/3响应式原理实现
- Sql查询原理与Select执行顺序(详细)
- SAP CRM Fiori 标准应用 My Account - search by ID 根据 ID 进行搜索的标准功能实现原理
- SAP ABAP 系统同微软 Office 套件进行 Desktop Integration 的工作原理
- SAP CRM One Order函数CHANGE_OW的设计原理
- Java的Covariance设计原理和SAP ABAP的模拟实现
- SAP C4C url mashup跳转原理 - C4C UI到Mashup的参数传递是如何进行的
- Atitit RSA非对称加密原理与解决方案
- Atitit.木马病毒 webftp 的原理跟个设计
- Atitit.字节数组转字符串 base64 base16 Quoted-printable 编码原理设计 attilax 总结
- 机器学习(三十二):Apriori 算法进行关联规则挖掘(原理与实战)
- springboot源码分析: 请求方式+请求映射原理+获取参数原理
- 支持向量机SVM-对图像进行分类原理讲解和代码示例
- 【Android 热修复】热修复原理 ( 加载 Dex 文件到内存中 | DexClassLoader | PathClassLoader | 反射 Element[] dexElements )
- 100集华为HCIE安全培训视频教材整理 | GRE技术原理
- 计算机网络原理【第六章 应用层】课后习题答案
- 【MySQL数据库原理】MySQL Workbench的功能介绍
- 生存分析原理简明教程 单因素生存分析 Kaplan-Meier、LogRank 只能针对单一的变量进行 多因素cox回归分析
- [SSD综述 1.4] SSD固态硬盘的结构和原理导论