摄像机标定摄像机成像坐标映射世界三维坐标到二维平面坐标映射摄像机镜头畸变的影响摄像机位移旋转影响摄像机标定内外参数矩阵求解前置原理内外参数矩阵摄像机标定代码的执行结果
参照报道
照相机摄影
1、我在物理上学习过小孔成像的原理。 三维空间的物体通过小孔,可以在小孔另一侧的接收屏幕上放映倒立像。 这利用了光沿直线传播的原理
2、现在的相机也利用了这个原理。 针孔型照相机通过投影中心(光心),在二维平面上表现三维空间的物体。 这显然是一个降维的过程。 那么,相机需要解决的问题是如何将三维空间的坐标映射到二维空间的坐标。 要确定此三维到二维的映射关系,请创建相机的几何模型。 这些模型参数是相机的参数:相机的内部参数、外部参数(例如旋转位移)、确定这些相机的内外参数的过程就是相机标定
坐标映射世界三维坐标到二维平面坐标映射1,从侧面看上图,可以得到下图。 如果照相机的投影中心位于c点,p位置的直线是二维平面,则确定三维空间中的物体,二维空间中的y坐标可以从三角形的相似度获得。 其中,x、y、z是物体在世界三维空间中的坐标,f是照相机的焦距,x、y是物体在二维平面上的坐标。 最终得到的二维平面上的坐标x=fX/Z,y=fY/Z。
2、转换上面得到的三维映射到二维的坐标公式,可以得到等价的行列式
3、相机生产过程中,相机与图像的坐标系往往存在偏差。 即,照相机的光心c (有时也称为主点)与图像坐标系的中心稍微偏离。这就是主点偏移两者偏移后,需要考虑这个偏移,所以修改上面得到的矩阵,加上摄像机的位移参数,可以得到以下矩阵。 这里,x0表示x方向的位移,y0表示y方向的位移。 这以x~K[I | 0]X的形式缩写,我把K称为照相机的内部参数矩阵。 照相机内部参数主要是焦距f、失真、主点等内部参数
照相机失真的影响1、上述问题充分考虑了照相机内部参数对成像的影响,但未考虑物理因素的影响的是照相机的镜头,照相机的镜头分为广角镜头、鱼眼镜头等。 用这个镜头拍摄的照片和用普通镜头拍摄的照片不同,会发生图像失真。 图像扭曲后,映射的二维平面上的某个点应该稍微扭曲,而不是平面上的实际位置。 应变类型主要为无畸变、桶型畸变、枕型畸变
2、从后面两种失真类型可以看出,以图像为中心向外扩展,失真程度越大,与距离呈非线性关系。 在网上查阅资料,这种非线性关系可以用多项式近似表达。 其中k1、k2、k3是径向偏斜系,r2=x2 y2
3、考虑失真,修正k矩阵后,得到新的k矩阵。 这里,s是应变参数
相机位移旋转的影响1、实际上,人们拿着相机拍摄时,相机的位置会发生变化。 拿着照相机在这个位置拍几张,也许在别的位置拍几张。 另外拍摄的时候相机可能有旋转角度,从某个角度拍摄的照片是最完美的。 因此,摄像机在生产时必须加入外部参数的影响,外部参数就包括相机的位移、旋转等于是,对上面得到的x~K [I | 0] X矩阵进行修正,得到包含摄像机旋转和位移的外部参数矩阵。 其中,k是考虑了失真的k。 从与上式的不同来看,其实用了[R | t]矩阵,叫做外部参数矩阵置换[I | 0]矩阵,r表示摄像机的旋转矩阵,t表示摄像机的位移矩阵。
2、世界上的摄像机旋转有x、y、z三个方向,分别称为pitch、yaw、roll。
乘以3、3个方向的旋转,得到旋转矩阵r。 其中c表示cos,s表示sin。
所谓摄像机校准1、摄像机校准是指求解上述K[R | t]矩阵的前提,已知物体在世界上的三维坐标和在图像上的二维坐标。 二维坐标的位置比较好地确定,问题是如何确定三维坐标的位置,采用传统方法是搭建一个标定板,标定板三个平面相互垂直,各小孔距离相等,通过标定板中小孔可以确定物体在三维空间的坐标。 但这种标定方式存在缺点,板上各小孔距离数值的精确度要非常高
2、上标定板需要极高的精度,包括不同平面的角度、特征点的物理距离等。 因此,制作标定板非常困难。 简单的标定板可以采用棋盘格作为标定板。 将棋盘格放置在严格平面上,棋盘格各网格间距相等,棋盘格位于严格平面上,因此三维空间中z方向的坐标可以表示为0。 假设棋盘网格的各网格的宽度为2厘米,则图中的角点a在三维中的坐标能够为(2,2,0 )
求解内外参数矩阵的前置原理1,得到物体在空间中的三维坐标后,可以求解摄像机的内外参数矩阵。 和求解单应性矩阵时一样,很容易用最小二乘法求解。 因此,这里省略最小二乘法的说明,介绍另一种令人兴奋的绿草提出的方法。
2、把上面的x~K[R | t]X
矩阵方程改写成以下的形式。m=[u, v, 1]T(这里的m只的是头上有个~号的m,下面的M也是如此),u、v表示的是二维坐标中的x、y,M=[X, Y, Z, 1]T,s表示世界坐标系到图像坐标系的尺度因子,A是相机的内参矩阵
3、假设旋转矩阵R的第i列为ri,则相机的外部参数可以写成以下形式,因为Z=0,所以可以去掉r3
4、进一步得到空间到图像的映射可改为,其中H是描述homographic的矩阵,H=[h1,h2,h3]=A[r1,r2,r3],H矩阵可以根据棋盘格的角点的空间坐标,以及在二维平面上的二维坐标,用最小二乘法解的。现在我们重新确定目标,需要求解的应该就是内部参数矩阵A和外部参数矩阵 [r1, r2, t]
求解内外部参数矩阵
1、设B=A-TA-1,得到的B矩阵如下图
2、观察矩阵B,可以发现B是一个对称矩阵,取B矩阵上三角部分,将B矩阵简写为b=[B11,B12,B22,B13,B23,B33]
3、另外,根据矩阵A=AT公式(这里的A不是内部参数矩阵A),单应性矩阵H中的第i列 hi=[hi1,h i2,hi3]T。
4、将上面得到的公式:H=[h1,h2,h3]=A[r1,r2,r3],进行变换,可以得到两个关于 r 和 h 的方程。
5、由于r1和r2正交,而且r1和r2的模都相等,且等于1,由此可以得到如下的约束条件
6、因此由步骤【2】中得到的b矩阵和步骤【3】中得到的hi矩阵,联立可以得到下面的公式,
其中vij的值如下:
7、根据r1和r2正交且长度为1的关系,即r1Tr2=0、||r1||-||r2||=0,可以转化为向量v和向量b之间的关系
8、根据最小二乘法,就可计算得出上面方程的解,从而得到矩阵b的值,进一步得到矩阵B的值。由于V就一个2n×6的矩阵,其中n表示n张观察的图像,因此n≥3,才能得到b矩阵的唯一解。
9、得到了B矩阵后,按照公式变换,可以得到相机内参矩阵A和矩阵B之间的关系
10、而内部参数可以根据Homographic求解。到此已经求解出了相机的内外参数。
相机标定代码 代码 import cv2import numpy as npimport glob# 找棋盘格角点# 阈值criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)# 棋盘格模板规格w = 6 # 内角点个数,内角点是和其他格子连着的点h = 4# 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ….,(8,5,0),去掉Z坐标,记为二维矩阵objp = np.zeros((w * h, 3), np.float32)objp[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2)# 储存棋盘格角点的世界坐标和图像坐标对objpoints = [] # 在世界坐标系中的三维点imgpoints = [] # 在图像平面的二维点images = glob.glob(‘picture/*.jpg’)for fname in images: img = cv2.imread(fname) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 找到棋盘格角点 # 棋盘图像(8位灰度或彩色图像) 棋盘尺寸 存放角点的位置 ret, corners = cv2.findChessboardCorners(gray, (w, h), None) # 如果找到足够点对,将其存储起来 if ret == True: cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria) objpoints.append(objp) imgpoints.append(corners) # 将角点在图像上显示 cv2.drawChessboardCorners(img, (w, h), corners, ret) cv2.imshow(‘findCorners’, img) cv2.waitKey(1000)cv2.destroyAllWindows()ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)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) # 平移向量 # 外参数# 去畸变img2 = cv2.imread(‘picture/5_d.jpg’)h, w = img2.shape[:2]newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 0, (w, h)) # 自由比例参数# 去畸变dst = cv2.undistort(img2, mtx, dist, None, newcameramtx)# 根据前面ROI区域裁剪图片x, y, w, h = roidst = dst[y:y + h, x:x + w]cv2.imwrite(‘calibresult.jpg’, dst)total_error = 0for i in range(len(objpoints)): imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2) total_error += errorprint((“total error: “), total_error / len(objpoints)) 运行结果
输入数据:输入的数据为一组在严格平面上的棋盘格,这些棋盘格用自己的手机拍出来的,则计算的就是手机相机的内外参数。
运行结果
另外还有一个图像畸变的矫正,由于输入的图像都是用普通镜头拍摄的,因此不存在什么畸变