相机标定(Camera Calibration)在多相机系统和三维视觉等领域极为重要,不仅能构建二维相机平面和三维世界坐标的相互关系,更重要的是能构建真实世界的尺度信息。
在三维重建领域,COLMAP或者DUST3R被用作常见的相机标定算法,通过立体匹配的方式得到相机的位姿,可以用于重建任务。但在相机标定领域,COLMAP真的够用了吗?答:远远不够用。先不说其在稀疏视点下通常无法完成标定,更重要的是,其估计的只是相对位姿,无法给出真实世界的尺度。
本文介绍一种用棋盘格标定板的相机标定步骤。
1,棋盘格的挑选与购买,要求:够大、不要有明显的镜面反射。本文采用的是GP400规格的标定板。
2,相机图像采集,实验中我用了三个相机。
3,标定程序:
import os
import os.path as osp
import cv2
import numpy as np
# 定义棋盘格的尺寸
chessboard_size = (11, 8) # 内部角点的数量
square_size = 0.03 # 每个方格的实际大小(可以用物理测量值替换,单位为米)
# 准备标定所需的真实世界坐标点
objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2)
objp *= square_size
# 用于存储所有图像的角点与对应的世界坐标
obj_points = [] # 世界坐标系中的 3D 点
img_points = [] # 图像平面中的 2D 点
root = "img/"
images = [osp.join(root, pp) for pp in sorted(os.listdir(root))]
print(images)
for i, image_path in enumerate(images):
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 找到棋盘格角点
ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)
print(ret)
if ret:
obj_points.append(objp)
img_points.append(corners)
# 在图像上绘制并显示角点(可选)
cv2.drawChessboardCorners(img, chessboard_size, corners, ret)
cv2.imwrite(f"viz_{i}.jpg", img)
# 标定相机
ret, camera_matrix, distortion_coeffs, rvecs, tvecs = cv2.calibrateCamera(
obj_points, img_points, gray.shape[::-1], None, None)
for i, (r, t) in enumerate(zip(rvecs, tvecs)):
R, _ = cv2.Rodrigues(r)
Rt = np.hstack((R, t))
print(Rt)
np.save(f"parm/{i}_extrinsic.npy", Rt)
# 输出结果
print("相机内参矩阵:")
print(camera_matrix)
np.save("intrinsic.npy", camera_matrix)
print("\n畸变系数:")
print(distortion_coeffs)
# 可选:保存标定结果
np.savez("camera_calibration.npz", camera_matrix=camera_matrix, distortion_coeffs=distortion_coeffs)
# 校正图像
for i, image_path in enumerate(images):
img = cv2.imread(image_path)
h, w = img.shape[:2]
new_camera_matrix, roi = cv2.getOptimalNewCameraMatrix(camera_matrix, distortion_coeffs, (w, h), 1, (w, h))
dst = cv2.undistort(img, camera_matrix, distortion_coeffs, None, new_camera_matrix)
cv2.imwrite(f"undist_{i}.jpg", dst)
其中比较关键的是设置棋盘格的角点数量和方块变长(用于绝对尺度的估计)。
实验结果:
三张视图的角点全部检测到。咱们通过一个可视化程序可以看到: