鱼眼相机标定旨在确定其独特的内部参数和畸变模型,以校正图像并实现精确的几何测量。其核心在于使用更复杂的模型来描述大视场角镜头引入的严重径向畸变。
一、鱼眼相机模型与标定参数
鱼眼相机模型通常使用等距投影模型,其标定参数与普通透视相机有显著区别。
| 参数类型 | 包含参数 | 物理意义与区别 |
|---|---|---|
| 内参矩阵 (K) | 焦距(fx, fy)、主点(cx, cy) | 与普通相机内参意义相同,描述成像几何中心。 |
| 畸变系数 (D) | (k1, k2, k3, k4) | 核心区别。鱼眼相机使用4个径向畸变系数 (k1, k2, k3, k4) 来描述严重的桶形畸变,而普通相机模型通常使用(k1, k2, p1, p2, k3)。 |
| 外参 | 旋转矩阵R、平移向量t | 与世界坐标系的变换关系,与普通相机标定一致。 |
二、标定流程与OpenCV实现
使用OpenCV进行鱼眼相机标定的流程与普通相机类似,但需调用专门的鱼眼标定函数。
核心步骤:
- 准备标定板:使用棋盘格标定板。
- 采集图像:从多个不同角度和位置拍摄标定板图像(建议15-20张)。
- 角点检测:检测图像中的棋盘格角点。
- 鱼眼标定:使用
cv2.fisheye.calibrate函数计算内参和畸变系数。 - 畸变校正:使用求得的参数对图像进行去畸变。
以下是完整的Python代码示例:
import cv2 import numpy as np import glob # 1. 定义标定板参数 (以9x6内部角点为例) CHECKERBOARD = (9, 6) #内部角点数量 (宽度-1, 高度-1) square_size = 0.025 # 每个方格的实际边长,单位:米 # 2. 为标定板角点创建世界坐标系下的3D点 (Z=0) 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) objp *= square_size # 3. 初始化存储3D点和2D图像点的数组 objpoints = [] # 真实世界3D点 imgpoints = [] # 图像中的2D点 # 读取所有标定图像 images = glob.glob('./calibration_images/*.jpg') img_shape = None for fname in images: img = cv2.imread(fname) if img_shape is None: img_shape = img.shape[:2] # 记录图像尺寸 (高度, 宽度) else: # 确保所有图像尺寸一致 assert img_shape == img.shape[:2], "所有标定图像尺寸必须相同!" 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: objpoints.append(objp) # 亚像素级角点精确化 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) corners_refined = cv2.cornerSubPix(gray, corners, (3, 3), (-1, -1), criteria) imgpoints.append(corners_refined) # 可选:在图像上绘制并显示角点 cv2.drawChessboardCorners(img, CHECKERBOARD, corners_refined, ret) cv2.imshow('Corners Found', img) cv2.waitKey(500) cv2.destroyAllWindows() # 4. 鱼眼相机标定 (核心步骤) print(f"开始标定,使用 {len(objpoints)} 张有效图像...") K = np.zeros((3, 3)) # 内参矩阵 D = np.zeros((4, 1)) # 鱼眼畸变系数 (k1, k2, k3, k4) rvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(len(objpoints))] tvecs = [np.zeros((1, 1, 3), dtype=np.float64) for i in range(len(objpoints))] # 使用鱼眼相机标定函数 ret, K, D, rvecs, tvecs = cv2.fisheye.calibrate( objpoints, imgpoints, gray.shape[::-1], # 图像尺寸 (宽度, 高度) K, D, rvecs, tvecs, # 标定标志位:使用初始内参猜测,并固定主点位于图像中心 flags=cv2.fisheye.CALIB_RECOMPUTE_EXTRINSIC + cv2.fisheye.CALIB_FIX_SKEW, criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-6) ) print("标定完成!") print("内参矩阵 K: ", K) print("鱼眼畸变系数 D (k1, k2, k3, k4): ", D.ravel())三、畸变校正与结果评估
标定后,使用求得的参数对鱼眼图像进行校正。
# 5. 畸变校正# 读取一张测试图像 test_img = cv2.imread('./test_image.jpg') h, w = test_img.shape[:2] # 计算最优的新相机矩阵和ROI(可选,用于裁剪黑边) new_K = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, D, (w, h), np.eye(3), balance=0.8) # balance参数 (0-1) 控制视野与黑边的权衡,1保留全部视野但黑边多,0裁剪多但视野小。 # 生成畸变校正映射 map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), new_K, (w, h), cv2.CV_16SC2) # 应用映射进行校正 undistorted_img = cv2.remap(test_img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT) # 显示结果 cv2.imshow('Original Fisheye', test_img) cv2.imshow('Undistorted', undistorted_img) cv2.waitKey(0) cv2.destroyAllWindows() # 6. 评估标定精度 (计算重投影误差) mean_error = 0 for i in range(len(objpoints)): # 将3D点投影到图像平面 imgpoints_reprojected, _ = cv2.fisheye.projectPoints(objpoints[i], rvecs[i], tvecs[i], K, D) # 计算投影点与检测点的误差 error = cv2.norm(imgpoints[i], imgpoints_reprojected, cv2.NORM_L2) / len(imgpoints_reprojected) mean_error += error print(f"平均重投影误差: {mean_error/len(objpoints):.4f} 像素") # 通常误差小于0.5像素认为标定质量良好。四、其他标定工具除了OpenCV,还有其他专门工具可用于鱼眼相机标定:
| 工具名称 | 主要特点 | 适用场景 |
|---|---|---|
| OCamCalib | 开源工具箱,支持多种非传统相机模型(如中心式鱼眼相机)的标定。 | 学术研究,需要特定鱼眼模型(如等距、正交等)的标定。 |
| Kalibr | ROS环境下功能强大的标定工具箱,支持多相机、相机-IMU、卷帘快门等联合标定。 | 机器人、自动驾驶领域,需要进行传感器融合标定。 |
| MATLAB Camera Calibrator | 图形化界面,操作简单,集成多种模型。 | 快速原型验证,非编程环境下的标定需求。 |
关键实践建议:
- 图像采集:标定板应覆盖图像各个区域(中心、边缘、四角),并具有足够多的倾斜角度,以确保标定参数在全图范围内的准确性。
- 参数初始化:OpenCV的
cv2.fisheye.calibrate对初始内参猜测敏感。通常将主点(cx, cy)初始化为图像中心,焦距(fx, fy)初始化为图像宽度和高度是合理的起点。 - 模型选择:OpenCV的鱼眼模型适用于大多数常见的中心式鱼眼镜头。对于非常规镜头(如某些全景相机),可能需要使用如OCamCalib等更灵活的模型。
可➕V,开发更为精密的视觉算法,见别的博文
参考来源
- 鱼眼相机模型和标定
- opencv鱼眼相机标定python
- 鱼眼相机标定以及OpenCV实现
- 相机模型与标定(十三)--鱼眼相机标定
- kalibr标定realsense鱼眼相机