1. 相机内参标定基础
任务目标
使用棋盘格标定板对相机进行内参标定,获取焦距、主点及畸变系数,并评估重投影误差。本案例使用OpenCV的findChessboardCorners与calibrateCamera完成标定,输出相机内参矩阵与畸变系数,并以重投影误差作为标定质量指标。
环境与依赖
- Python 3.8+
- OpenCV(
opencv-python) - NumPy
- 准备10~20张不同角度拍摄的棋盘格图像(如10×7内角点棋盘格),图像分辨率需一致
关键完整代码
import cv2
import numpy as np
import glob
# 棋盘格内角点尺寸(列, 行)
CHECKERBOARD = (9, 6)
square_size = 25.0 # 方格边长(mm),仅用于统一尺度
# 准备对象点(世界坐标系中棋盘格角点坐标)
objp = np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)
objp *= square_size
obj_points = [] # 3D点
img_points = [] # 2D点
images = glob.glob('calib_images/*.jpg')
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD, None)
if ret:
obj_points.append(objp)
# 亚像素角点精化
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
img_points.append(corners2)
cv2.drawChessboardCorners(img, CHECKERBOARD, corners2, ret)
cv2.imshow('Chessboard', img)
cv2.waitKey(100)
cv2.destroyAllWindows()
# 相机标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
obj_points, img_points, gray.shape[::-1], None, None
)
print("内参矩阵:\n", mtx)
print("畸变系数 (k1, k2, p1, p2, k3):\n", dist.ravel())
# 重投影误差评估
total_error = 0
for i in range(len(obj_points)):
imgpoints2, _ = cv2.projectPoints(obj_points[i], rvecs[i], tvecs[i], mtx, dist)
error = cv2.norm(img_points[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
total_error += error
mean_error = total_error / len(obj_points)
print(f"平均重投影误差: {mean_error:.4f} px")
运行方式
- 创建目录
calib_images/,放入10~20张棋盘格照片(建议不同角度、不同距离)。 - 安装依赖:
pip install opencv-python numpy - 运行脚本:
python camera_calib.py
验证方法与判定标准
- 角点检测成功:运行过程中每张图像会弹出窗口显示检测到的棋盘格角点,若某张图像检测失败(无窗口显示),该图像会被自动跳过。
- 标定输出:程序打印内参矩阵(含fx, fy, cx, cy)与5个畸变系数。
- 通过条件:平均重投影误差小于0.5像素,表明标定精度良好;若误差大于1像素,建议剔除模糊或角点检测质量差的图像后重新标定。
常见问题
- 检测不到角点:确认棋盘格内角点数量与
CHECKERBOARD一致(例如9×6表示每行9个内角点、每列6个内角点);避免反光、过曝或图像过暗。 - 标定误差偏大:增加图像数量(15张以上),并确保棋盘格在画面中占据足够面积且覆盖不同区域(中心、四角、倾斜)。