使用python和opencv实现相机标定
相机标定
相机标定是确定相机内部参数(例如焦距、光学中心)和畸变(镜头失真)的过程,以便将像素坐标转换为世界坐标或者将世界坐标转换为像素坐标,从而在计算机视觉、三维重建等领域中准确地理解和处理图像信息。
输入数据通常包括拍摄的图像或者视频序列,以及相机的参数信息(例如相机型号、传感器尺寸等)。输出结果通常是相机的内部参数矩阵(如相机的焦距、主点坐标等)和外部参数(相机的位置和朝向),以及可能的畸变参数(用于校正图像失真)。一般情况下,通过在不同位置、角度、距离下拍摄标定板的图像,你可以收集到不同视角下标定板在图像中的像素坐标以及标定板上已知的三维坐标(通常是平面上的点)。这些数据将用于相机标定,从而推导出相机的内部参数(如焦距、主点坐标等)和外部参数(相机的位置和朝向)。
1. 准备标定板图像
准备一个已知尺寸和形状的标定板,一般使用(checkboard)棋盘格,拍摄多张包含这个标定板的图像。确保标定板在图像中的各种角度和位置都有覆盖。
以上为标定板的样例。
2. 标定代码
实现相机标定的基本步骤为哦噢:
(1). 棋盘格角点检测:使用cv2.findChessboardCorners
函数检测棋盘格图案在图像中的角点。这个函数寻找特定大小的棋盘格内角点的位置。
(2). 优化角点像素坐标:对检测到的角点进行优化,使用cv2.cornerSubPix
函数对像素级别的角点坐标进行精确化处理。这个步骤提高了检测到的角点的精度。
(3). 收集标定数据:将优化后的角点坐标(二维图像中的坐标)和已知的棋盘格上的三维坐标(世界坐标系中的坐标)对应起来,并保存这些数据,用于后续的相机标定。
(4). 相机标定:使用cv2.calibrateCamera
函数根据已知的三维-二维点对来进行相机标定。该函数利用收集到的标定数据,计算出相机的内部参数(如相机矩阵、畸变参数等)和外部参数(相机的位置和朝向)。
(5). 保存相机参数:最后,将计算得到的相机内参、畸变参数、相机位置和朝向等数据,以便后续使用。
整个过程基于相机成像原理和棋盘格的已知几何特征,通过收集标定图像上的棋盘格角点信息,利用这些已知的2D-3D点对,计算出相机的内部和外部参数,从而实现相机的标定。以下为基于python的代码:
import glob
import cv2
import pickle
import numpy as np
# 定义棋盘格的维度
CHECKERBOARD = (6, 8) # 我的棋盘格是7*9
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
objpoints = []
imgpoints = []
# 定义世界坐标系中的3D点
objp = np.zeros((1, CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
objp[0, :, :2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)
prev_img_shape = None
images = glob.glob('./checkboard/*.jpg')
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD,
cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
if ret == True: # 如果找到角点
objpoints.append(objp)
corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
imgpoints.append(corners2)
# 画图并展示角点
img = cv2.drawChessboardCorners(img, CHECKERBOARD, corners2, ret)
desired_width = 640 # 替换为你想要的宽度
desired_height = 480 # 替换为你想要的高度
img_resized = cv2.resize(img, (desired_width, desired_height))
cv2.imshow('Visualize IMG', img_resized)
cv2.waitKey(100)
cv2.destroyAllWindows()
h, w = img.shape[:2]
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print("Camera matrix : \n")
print(mtx)
print("dist : \n")
print(dist)
print("rvecs : \n")
print(rvecs)
print("tvecs : \n")
print(tvecs)
运行上述代码之后,我的相机标定结果为:
Camera matrix :
[[3.49017392e+03 0.00000000e+00 2.33493976e+03]
[0.00000000e+00 3.48812132e+03 1.73653124e+03]
[0.00000000e+00 0.00000000e+00 1.00000000e+00]]
dist :
[[ 4.31081356e-02 -2.14314100e-01 3.16324064e-04 1.37368140e-05
3.83524452e-01]]
rvecs :
(array([[0.10733804],
[0.03581478],
[1.57752917]]), array([[0.26197925],
[0.17000535],
[1.52887916]]), array([[ 0.23831319],
[-0.29249928],
[ 1.55283966]]), array([[-0.14243786],
[-0.0783745 ],
[-1.53007322]]), array([[-0.12563654],
[-0.30528986],
[ 1.5596221 ]]))
tvecs :
(array([[ 3.69696489],
[-2.4605232 ],
[10.3670443 ]]), array([[ 2.80876299],
[-2.61246982],
[ 8.01137576]]), array([[ 3.81541091],
[-1.83905007],
[ 8.49963633]]), array([[-3.33722804],
[ 2.02980881],
[ 9.65504995]]), array([[ 4.49071749],
[-2.72048691],
[10.77570147]]))
3. 总结
相机标定确定了相机的内部和外部参数,包括焦距、畸变等,使得像素坐标能够准确映射到世界坐标或相反。这为位姿估计提供了基础,通过相机标定获得的参数,可以在计算机视觉中精确地定位物体、重建场景,实现位姿估计并在增强现实、三维重建等领域中应用。