相机标定


参考文章

相机成像

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是畸变参数
新K

相机的位移旋转影响

1、在实际中,人们拿相机拍摄的时候,相机的位置是发生变化的,可能拿着相机在这个位置拍几张,在另一个位置拍几张。另外可能拍摄的时候相机是有旋转角度的,某个角度拍摄出来的照片才是最完美的。因此相机在生产的时候,必须加入外部参数的影响,而外部参数就包括相机的位移、旋转等。因此将上面得到的x~K [I | 0] X矩阵进行修改,得到含有相机旋转和位移的外部参数矩阵,其中K是考虑进畸变情况后的K。观察和上面式子的差异,其实就是把 [I | 0]矩阵替换成了[R | t]矩阵,叫做外部参数矩阵,R表示相机的旋转矩阵,t表示相机的位移矩阵。

2、相机在世界中的旋转包括三个方向:X、Y、Z,分别称作pitch、yaw、roll。
rollyawpitch
3、将着三个方向上的旋转相乘,就得到了旋转矩阵R,其中C表示cos、S表示sin。
R

相机标定

1、相机标定就是求解上面的 K[R | t] 矩阵前提是我们已知了物体在世界中的三维坐标和在图像上的二维坐标。二维坐标的位置比较好确定,问题是如何确定三维坐标的位置,采用传统的办法就是构造一个标定板,标定板的3个平面相互垂直,每个小孔的距离相等,通过标定板中的小孔可以确定物体在三维空间中的坐标。但是这种标定方式有个缺点是板上每个小孔的距离数值的精确度要非常高
标定板
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是相机的内参矩阵

zzy
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矩阵如下图
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
hi
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之间的关系
AB的关系
10、而内部参数可以根据Homographic求解。到此已经求解出了相机的内外参数。

相机标定代码

代码

import cv2
import numpy as np
import 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 = roi
dst = dst[y:y + h, x:x + w]
cv2.imwrite('calibresult.jpg', dst)

total_error = 0
for 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 += error
print(("total error: "), total_error / len(objpoints))

运行结果

输入数据:输入的数据为一组在严格平面上的棋盘格,这些棋盘格用自己的手机拍出来的,则计算的就是手机相机的内外参数。
数据
运行结果
内部参数
畸变系数
旋转向量
平移向量
另外还有一个图像畸变的矫正,由于输入的图像都是用普通镜头拍摄的,因此不存在什么畸变

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值