3. 相机标定与像素当量计算

相机标定与像素当量计算 学习卡片

标定任务与坐标系约定

本例使用 9×6 方格棋盘格标定板(方格边长 10.0 mm,即内角点阵列 8×5),在固定工作距离下采集 12 张不同姿态图像,完成相机内参标定并计算像素当量。像素当量定义为:1 个像素在物方平面上对应的实际物理尺寸,单位 mm/pixel。标定后需用已知尺寸标准件验证尺寸测量误差。

坐标系约定:图像坐标系原点在左上角,u 向右、v 向下;物方平面与光轴垂直,标定板平面与物方平面重合时,像素当量 k = 标定板实际尺寸 / 对应像素数。

标定布局与像素当量关系 工业相机 2448×2048 光轴 工作距离 WD 棋盘格 9×6,格边长 10.0 mm 像素当量计算 k = L_real / N_pixel L_real:标定板实际尺寸 (mm) N_pixel:对应像素数 (pixel) k:像素当量 (mm/pixel) 标定与验证流程 ① 采集 12 张不同姿态棋盘格图像 覆盖画面四角与中心区域 ② 提取内角点亚像素坐标 8×5=40 个角点/张 ③ 求解内参与畸变系数 fx, fy, cx, cy, k1, k2, p1, p2 ④ 计算像素当量 k k = 10.0 mm / 格像素数 ⑤ 标准件验证尺寸误差 误差 = |测量值 − 真值| / 真值 标定精度对尺寸测量的影响: k 偏差 1% → 100 mm 尺寸测量偏差约 1 mm;k 偏差 0.1% → 偏差约 0.1 mm。标定重投影误差应 < 0.1 pixel。 重投影误差判据 RMS < 0.1 pixel → 标定合格 RMS > 0.3 pixel → 需重新采集

标定实现与像素当量计算

以下代码使用 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%