1、针孔照相机模型
针孔照相机模型
(有时称为
射影照相机模型
)是计算机视觉中广泛使用的照相机模型。
该照相机从一个小孔采集射到暗箱内部的光线。 在针孔照相机模型中,在光线投影到图像平面
之前,从唯一一个点经过,也就是照相机中心C
。
![](https://img-blog.csdnimg.cn/3e0b7357a5904a19b4e0640e813fd2f1.png)
针孔照相机模型。图像点
x
是由图像平面与连接三维点
X
和照相机中心
C
的直线相交而成的。虚线表示该照相机的光学坐标轴。
三维点
X
投影为图像点
x
(两个点都是用齐次坐标表示的)
x = PX
P
为
照相机矩阵
(或
投影矩阵);
在齐次坐标系中,三维
点
X
的坐标由
4
个元素组成,
X
=[
X
,
Y
,
Z
,
W
];
标量
λ
是三维点的逆深度。
1.1 照相机矩阵
照相机矩阵:
P = K[R|t]
R
是描述照相机方向的旋转矩阵,
t
是描述照相机中心位置的三维平移向量,内标定矩阵K
描述照相机的投影性质。
因为标定矩阵仅和照相机自身的情况相关,所以通常情况下可以写成:
图像平面和照相机中心间的距离为焦距 f。当像素数组在传感器上偏斜的时候,需要用到倾斜参数 s。在大多数情况下,s 可以设置成 0。
则可以写为:(s=0)
![](https://img-blog.csdnimg.cn/f73731bca3ae46a689ae6fb28dd68c36.png)
其中:
=α
。
纵横比例参数
α
是在像素元素非正方形的情况下使用的。通常情况下,默认设置 α
=1。
则标定矩阵变为:
![](https://img-blog.csdnimg.cn/27dc27ca7c914c7c9cd3938816bf927f.png)
上式
未知的变量只有焦距
f
。
1.2 三维点的投影
1.3 照相机矩阵的分解
1.4 计算照相机中心
2、相机标定
标定照相机是指计算出该照相机的内参数。
![](https://img-blog.csdnimg.cn/bf9410c8494146d680059bd1098d2204.png)
![](https://img-blog.csdnimg.cn/4da061d3b20e4b188b6dba08e8c1b6b7.png)
2.1 实验数据集
2.2 实现代码
import cv2
import numpy as np
import glob
np.set_printoptions(suppress=True)
# 找棋盘格角点
# 阈值
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('E:/Junior_N/computerVision/imgTest/Lab_4/imgData/*.jpg')
i = 0
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:
# 角点精确检测
# 输入图像 角点初始坐标 搜索窗口为2*winsize+1 死区 求角点的迭代终止条件
i += 1
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.imwrite('E:/Junior_N/computerVision/imgTest/Lab_4/imgData' + str(i) + '.jpg', img)
cv2.waitKey(10)
cv2.destroyAllWindows()
# 标定、去畸变
# 输入:世界坐标系里的位置 像素坐标 图像的像素尺寸大小 3*3矩阵,相机内参数矩阵 畸变矩阵
# 输出:标定结果 相机的内参数矩阵 畸变系数 旋转矩阵 平移向量
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
# mtx:内参数矩阵
# dist:畸变系数
# rvecs:旋转向量 (外参数)
# tvecs :平移向量 (外参数)
print(("ret:"), ret)
print(("内参矩阵:\n"), mtx) # 内参数矩阵
print(("畸变参数:\n"), dist) # 畸变系数 distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print(("旋转向量(外参数):\n"), rvecs) # 旋转向量 # 外参数
print(("平移向量(外参数):\n"), tvecs) # 平移向量 # 外参数
# 去畸变
img2 = cv2.imread('E:/Junior_N/computerVision/imgTest/Lab_4/imgData/1.jpg')
h, w = img2.shape[:2]
# 我们已经得到了相机内参和畸变系数,在将图像去畸变之前,
# 我们还可以使用cv.getOptimalNewCameraMatrix()优化内参数和畸变系数,
# 通过设定自由自由比例因子alpha。当alpha设为0的时候,
# 将会返回一个剪裁过的将去畸变后不想要的像素去掉的内参数和畸变系数;
# 当alpha设为1的时候,将会返回一个包含额外黑色像素点的内参数和畸变系数,并返回一个ROI用于将其剪裁掉
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)
# 反投影误差
# 通过反投影误差,我们可以来评估结果的好坏。越接近0,说明结果越理想。
# 通过之前计算的内参数矩阵、畸变系数、旋转矩阵和平移向量,使用cv2.projectPoints()计算三维点到二维图像的投影,
# 然后计算反投影得到的点与图像上检测到的点的误差,最后计算一个对于所有标定图像的平均误差,这个值就是反投影误差。
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))