桶状畸变:
枕形畸变:
2.3.像主点偏移:
2.4.单应性矩阵H:
最大似然估计:
使用最大似然估计进行优化。假设拍摄了n张棋盘格图像,每张图像有m个角点。最终获得的最大似然估计公式为:
二.相机标定策略:
2.1.相关策略:
•
同步标定内部参数和外部参数,一般包括两种策略
:
1.
光学标定
:
利用已知的几何信息
(
如定长棋盘格
)
实现参数求解。
2.
自标定
:
在静态场景中利用
structure from motion
估算参数。
2.2.棋盘格标定:
优点:
•
仅需要平面标定板,拍摄若干张图片
•
标定板中的模式十分灵活,可以是棋盘格,也可以是其他几何结构已知的图形
•
实验结果表明具有很好的标定精度
•
具有很强的灵活性
相关流程:
1.
打印一张棋盘格
A4
纸张(黑白间距已知),并贴在一个平板上
2.
针对棋盘格拍摄若干张图片(一般
10-20
张)
3.
在图片中检测特征点(Harris
角点)
4.
根据角点位置信息及图像中的坐标,求解Homographic
矩阵
5.
利用解析解估算方法计算出
5
个内部参数,以及6
个外部参数
6. 根据极大似然估计策略,设计优化目标并实现 参数的refinement
三.实验内容:
1.实验数据:
2.实验代码:
import cv2
import numpy as np
import glob
# 找棋盘格角点
# 棋盘格模板规格(内角点个数,内角点是和其他格子连着的点,如11 X 8)
w = 11
h = 8
# 世界坐标系中的棋盘格点,例如(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('D:\\pythonProject\\computervision4\\picture\\*.jpg')
size = tuple()
for fname in images:
img = cv2.imread(fname)
# 修改图像尺寸,参数依次为:输出图像,尺寸,沿x轴,y轴的缩放系数,INTER_AREA在缩小图像时效果较好
img = cv2.resize(img, None, fx=0.1, fy=0.1, interpolation=cv2.INTER_AREA)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转灰度
size = gray.shape[::-1] # 矩阵转置
# 找到棋盘格角点
# 棋盘图像(8位灰度或彩色图像) 棋盘尺寸 存放角点的位置
ret, corners = cv2.findChessboardCorners(gray, (w, h), None)
# 角点精确检测
# criteria:角点精准化迭代过程的终止条件(阈值)
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# 执行亚像素级角点检测
corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
objpoints.append(objp)
imgpoints.append(corners2)
# 将角点在图像上显示
cv2.drawChessboardCorners(img, (w, h), corners2, ret)
cv2.imshow('findCorners', img)
cv2.waitKey(1000)
"""
标定、去畸变:
输入:世界坐标系里的位置 像素坐标 图像的像素尺寸大小 3*3矩阵,相机内参数矩阵 畸变矩阵
输出:标定结果 相机的内参数矩阵 畸变系数 旋转矩阵 平移向量
"""
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, size, None, None)
# mtx:内参数矩阵
# dist:畸变系数
# rvecs:旋转向量 (外参数)
# tvecs :平移向量 (外参数)
print("ret:", ret)
print("内参数矩阵:\n", mtx, '\n')
print("畸变系数:\n", dist, '\n')
print("旋转向量(外参数):\n", rvecs, '\n')
print("平移向量(外参数):\n", tvecs, '\n')
# 去畸变
img2 = cv2.imread('D:\\pythonProject\\computervision4\\picture\\IMG_20220512_151929.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,说明结果越理想。
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))
3.实验结果: