3. 相机标定与像素当量计算
标定任务与坐标系约定
本例使用 9×6 方格棋盘格标定板(方格边长 10.0 mm,即内角点阵列 8×5),在固定工作距离下采集 12 张不同姿态图像,完成相机内参标定并计算像素当量。像素当量定义为:1 个像素在物方平面上对应的实际物理尺寸,单位 mm/pixel。标定后需用已知尺寸标准件验证尺寸测量误差。
坐标系约定:图像坐标系原点在左上角,u 向右、v 向下;物方平面与光轴垂直,标定板平面与物方平面重合时,像素当量 k = 标定板实际尺寸 / 对应像素数。
标定实现与像素当量计算
以下代码使用 OpenCV 完成棋盘格角点检测、相机标定与像素当量计算。标定板参数:内角点 8×5,方格边长 10.0 mm。采集图像存放于 calib_images/ 目录。
import cv2
import numpy as np
import glob
# 标定板参数:内角点数量(列×行)
PATTERN = (8, 5)
SQUARE_MM = 10.0 # 方格实际边长 mm
# 生成物方角点坐标(Z=0 平面)
objp = np.zeros((PATTERN[0] * PATTERN[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:PATTERN[0], 0:PATTERN[1]].T.reshape(-1, 2) * SQUARE_MM
obj_points = [] # 3D 物方点
img_points = [] # 2D 图像点
img_size = None
images = sorted(glob.glob("calib_images/*.png"))
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_size = gray.shape[::-1]
ret, corners = cv2.findChessboardCorners(gray, PATTERN, None)
if not ret:
print(f"未检测到角点: {fname}")
continue
# 亚像素精化
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corners_refined = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
obj_points.append(objp)
img_points.append(corners_refined)
# 相机标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
obj_points, img_points, img_size, None, None
)
print(f"标定 RMS 重投影误差: {ret:.4f} pixel")
print(f"内参矩阵:\n{mtx}")
print(f"畸变系数: {dist.ravel()}")
# 计算像素当量:使用标定板方格在图像中的平均像素尺寸
# 取第一张图的角点,计算相邻角点像素距离
corners0 = img_points[0].reshape(-1, 2)
# 水平方向相邻角点距离(同一行)
d_h = np.linalg.norm(corners0[1] - corners0[0])
# 垂直方向相邻角点距离(同一列)
d_v = np.linalg.norm(corners0[PATTERN[0]] - corners0[0])
k_h = SQUARE_MM / d_h # mm/pixel
k_v = SQUARE_MM / d_v
k_avg = (k_h + k_v) / 2
print(f"水平像素当量: {k_h:.6f} mm/pixel")
print(f"垂直像素当量: {k_v:.6f} mm/pixel")
print(f"平均像素当量: {k_avg:.6f} mm/pixel")
标定精度验证
使用已知尺寸的标准件(如 50.00 mm 量块)验证标定精度。将量块置于物方平面,测量其像素长度并换算为物理尺寸,计算相对误差。
# 验证:测量标准件尺寸
# 假设标准件真值 50.00 mm
TRUE_MM = 50.00
# 在图像中测量标准件两端点像素坐标(示例值)
p1 = np.array([320.5, 480.2])
p2 = np.array([1520.8, 480.5])
pixel_len = np.linalg.norm(p2 - p1)
measured_mm = pixel_len * k_avg
error_mm = abs(measured_mm - TRUE_MM)
error_pct = error_mm / TRUE_MM * 100
print(f"像素长度: {pixel_len:.2f} pixel")
print(f"测量尺寸: {measured_mm:.4f} mm")
print(f"绝对误差: {error_mm:.4f} mm")
print(f"相对误差: {error_pct:.4f}%")
# 判断标准:相对误差 < 0.1% 为合格
if error_pct < 0.1:
print("标定精度合格")
else:
print("标定精度不足,需重新标定")
提高标定精度的要点:
- 标定板姿态应覆盖画面四角、中心及不同倾斜角度,避免所有图像姿态过于接近。
- 棋盘格图像应清晰、无运动模糊,角点对比度足够。
- 标定板平面应平整,方格边长加工误差应小于 0.01 mm。
- 重投影误差 RMS 应控制在 0.1 pixel 以内;若大于 0.3 pixel,需检查角点提取质量或重新采集。
- 像素当量应在实际工作距离下计算,若工作距离变化,需重新标定或使用远心镜头。
常见问题:
- 角点检测失败:检查棋盘格是否完整出现在画面中,光照是否均匀,必要时调整
findChessboardCorners的阈值参数。 - 像素当量水平与垂直方向差异过大:可能存在镜头畸变未校正或标定板倾斜,需检查畸变系数并重新标定。
- 测量误差偏大:确认标定板方格边长输入正确(单位 mm),并检查标准件是否与标定板在同一物方平面。
标定结果记录表
| 项目 | 数值 | 判据 |
|---|---|---|
| 标定图像数量 | 12 张 | ≥ 10 张,姿态多样 |
| 内角点数量 | 8×5 = 40 | 与标定板一致 |
| RMS 重投影误差 | 示例:0.08 pixel | < 0.1 pixel |
| 水平像素当量 k_h | 示例:0.032500 mm/pixel | — |
| 垂直像素当量 k_v | 示例:0.032480 mm/pixel | 与 k_h 差异 < 0.5% |
| 平均像素当量 k_avg | 示例:0.032490 mm/pixel | — |
| 标准件测量误差 | 示例:0.05% | < 0.1% |