利用OpenCV进行Camera Calibration本人在教学机器视觉讲到了相机标定章节设计了本实验。借助AI设计了可视化的交互代码。实验目标本项目使用棋盘格图片完成相机标定。程序检测每张图片中的棋盘格内角点建立棋盘格真实三维坐标与图像二维像素坐标之间的对应关系并计算相机内参、畸变系数、每张图片对应的外参和重投影误差。本教程所用的所有代码和采集的棋盘格数据集在OpenCVPython棋盘格标定代码进行下载。完整流程输入棋盘格图片 - 检测棋盘格内角点 - cornerSubPix 亚像素优化 - 构造 3D-2D 对应关系 - calibrateCamera 求解相机参数 - projectPoints 计算重投影误差 - undistort 生成去畸变图片 - 输出 calib.json 和 debug 可视化结果项目结构calibrate.py 相机标定主程序 visualize_extrinsics_interactive.py 外参交互式 HTML 可视化脚本 environment.yml Conda 环境配置 pattern.png 对称棋盘格打印图 asymmetric-pattern.png 非对称棋盘格打印图 camera-calibration-checker-board_9x7.pdf 9x7 内角点棋盘格 PDF canon-efs-24mm-crop1.6/ Canon 相机标定数据集 c920-symmetric/ Logitech C920 对称棋盘格数据集 c920-asymmetric/ Logitech C920 非对称棋盘格数据集 new_captured_0601/ 教室自采的数据集棋盘格6x9方格大小30mm本次实验使用的棋盘格标定数据集是canon-efs-24mm-crop1.6/、c920-symmetric/和c920-asymmetric/以及本人自采的new_captured_0601/。环境配置cdopencv-camera-calibration condaenvcreate-fenvironment.yml conda activate machine-vision用到的关键函数# -------------------------------------------------------------------------# 3. 在每张图片中检测棋盘格内角点也叫 image points。# -------------------------------------------------------------------------found,cornerscv2.findChessboardCorners(img,pattern_size)# 在每张图片里找到角点# -------------------------------------------------------------------------# 5. 调用 OpenCV 标定函数求相机内参、畸变系数和每张图的外参。# -------------------------------------------------------------------------## 普通针孔相机模型# cv2.calibrateCameracalibrate_funccv2.calibrateCameraprint(正在标定相机 Calibrating camera using %d images%len(img_points))# 调用 OpenCV 求相机参数。# 参数 (w, h) 是图像分辨率None, None 表示让 OpenCV 自己初始化内参和畸变。rms,camera_matrix,dist_coefs,rvecs,tvecs\ calibrate_func(obj_points,img_points,(w,h),None,None)# -------------------------------------------------------------------------# 6. 计算重投影误差用来评估标定质量。# -------------------------------------------------------------------------project_funccv2.projectPoints# 选择对应的投影函数快速运行calibrate.py 三组数据集运行命令的核心区别是-c内角点数量和是否提供 -s 棋盘格单个网格实际大小单位米-S传感器尺寸可以不用提供视不同相机的cmos各有不同visualize_extrinsics_interactive.py -c 输入的标定部分保存的校正参数 -o 设置输出可视化文件名1. Canon 数据集cdcanon-efs-24mm-crop1.6 python../calibrate.py-c9x6-s0.0244-jcalib.json-S22.3x14.9-ddebug *.JPG python../visualize_extrinsics_interactive.py-ccalib.json-ointeractive_extrinsics.html打开生成的交互式外参页面canon-efs-24mm-crop1.6/interactive_extrinsics.html这组数据使用 Canon 相机和 EF-S 24mm 镜头拍摄棋盘格内角点为9x6方格边长为0.0244 m。命令中加入-S 22.3x14.9是因为该相机的 APS-C 传感器尺寸已知程序可以进一步把像素焦距换算成毫米焦距并输出水平、垂直视场角。2. C920 对称棋盘格数据集cdc920-symmetric python../calibrate.py-c9x7-s0.0244-jcalib.json-ddebug *.jpg python../visualize_extrinsics_interactive.py-ccalib.json打开生成的交互式外参页面c920-symmetric/interactive_extrinsics.html这组数据使用 Logitech C920 摄像头拍摄对称棋盘格棋盘格内角点为9x7方格边长为0.0244 m。普通 webcam 通常不容易精确确认传感器物理尺寸所以这里不使用-S输出的焦距仍然是像素单位的fx、fy。3. C920 非对称棋盘格数据集cdc920-asymmetric python../calibrate.py-c9x6-s0.0244-jcalib.json-ddebug *.jpg python../visualize_extrinsics_interactive.py-ccalib.json打开生成的交互式外参页面c920-asymmetric/interactive_extrinsics.html这组数据同样使用 Logitech C920 摄像头棋盘格内角点为9x6方格边长为0.0244 m。它适合与c920-symmetric/对比相机相同棋盘格图案和拍摄姿态不同可以观察角点检测、重投影误差和外参分布的变化。4. 自采棋盘格数据集cdnew_captured_0601 python../calibrate.py-c8x5-s0.03-jcalib.json-ddebug *.jpg python../visualize_extrinsics_interactive.py-ccalib.json打开生成的交互式外参页面new_captured_0601/interactive_extrinsics.html这组数据同样使用手机进行采集棋盘格内角点为8x5方格边长为0.03 m。当然大家也可以根据自己的实际需求设计其他格式和尺寸的棋盘格。可以在这一个网站Calib.io - Camera Calibration进行棋盘格设计和定制下载pdf打印到平板上。主要需要设置板子的大小一般是A4纸随后设计棋盘格的长宽以及最重要的方格大小例如20mm这个就是输入到标定代码建立世界坐标系的参数。参数说明参数示例说明-c-c 9x6棋盘格内角点数量表示 9 列 6 行。该值不是方格数量。-s-s 0.0244棋盘格每个方格的真实边长单位为米。该值决定外参平移向量的物理尺度。-j-j calib.json将标定结果保存为 JSON 文件。-S-S 22.3x14.9传感器尺寸单位为毫米。已知 CMOS 尺寸时程序可输出毫米焦距和视场角。-d-d debug保存角点检测图、去畸变图和裁剪后的去畸变图。-t-t 4棋盘角点检测使用的线程数。-f-f使用鱼眼相机模型。普通镜头不需要该参数。棋盘格尺寸说明10x7 个方格 - 9x6 个内角点 10x8 个方格 - 9x7 个内角点-c参数填写内角点数量不填写方格数量。内角点是黑白方格交界处位于棋盘内部的交点。输出文件每组数据运行后都会在对应数据集目录中生成calib.json debug/ interactive_extrinsics.html在debug文件夹下面有原始棋盘格图像的角点检测结果图有图像校正去畸变之后的图部分区域用纯黑色填充也有校正去畸变之后对图像进行裁剪保证图像没有空白填充区域。xxx_chessboard.png 角点检测图 xxx_undistorted.png 校正去畸变后图 xxx_undistorted_cropped.png 去畸变裁剪图例如 Canon 数据集对应canon-efs-24mm-crop1.6/calib.json canon-efs-24mm-crop1.6/debug/ canon-efs-24mm-crop1.6/interactive_extrinsics.htmlcalib.jsoncalib.json保存完整标定结果camera_matrix 相机内参矩阵 distortion_coefficients 畸变系数 rms OpenCV 标定 RMS 误差 reprojection_error 每张图片和整体的重投影误差 chessboard_points 棋盘格三维点 chessboard_orientations 每张图片中棋盘格相对相机的外参 image_resolution 输入图像分辨率 fov_degrees 视场角使用 -S 时输出 focal_length_mm 物理焦距使用 -S 时输出相机内参矩阵形式[fx 0 cx] [ 0 fy cy] [ 0 0 1]fx、fy是像素单位焦距cx、cy是主点坐标。只有提供-S时程序才会额外输出毫米单位焦距和视场角这就是 Canon 示例比 C920 示例多一个-S参数的原因。debug 目录debug/中主要包含*_chessboard.png 棋盘格角点检测结果 *_undistorted.png 去畸变结果未裁剪 *_undistorted_cropped.png 去畸变结果裁剪有效区域 extrinsic_camera_poses.png 外参可视化图 extrinsic_chessboard_positions.png 棋盘位置可视化图角点检测图用于检查-c参数和棋盘识别是否正确。去畸变图用于检查畸变校正效果。interactive_extrinsics.html交互式外参可视化文件由visualize_extrinsics_interactive.py生成。该 HTML 读取calib.json中的外参数据展示相机与棋盘格之间的空间关系。图中的彩色线框表示相机拍照时的视野范围。不同颜色对应不同标定图片。通过这些线框可以观察每张图片中相机与棋盘格的相对姿态。打开可视化脚本之后将看到如下界面效果。棋盘格位姿。此时相机固定通过计算出的外参展示出在采集图像时棋盘格的在每一帧不同位姿。相机位姿。此时棋盘格固定通过计算出的外参展示出在采集图像时相机的位姿。终端输出说明图像分辨率 Image resolution: 5184x3456 正在处理 Processing 7 images using 4 threads ....... 完成 done 成功检测棋盘格 Found chessboards: 7 / 7 images 正在标定相机 Calibrating camera using 7 images OpenCV RMS 误差 RMS: 1.1816539348859303 相机内参矩阵 Camera matrix: [[5.86740810e03 0.00000000e00 2.59146595e03] [0.00000000e00 5.87687560e03 1.72775439e03] [0.00000000e00 0.00000000e00 1.00000000e00]] 畸变系数 Distortion coefficients: [-0.12292006 0.17978175 -0.00165217 -0.00162774 -0.94788816] 平均重投影误差 Average reprojection error: 0.159998 /- 0.016063输出含义图像分辨率 Image resolution 输入图片分辨率。所有标定图片必须保持一致。 成功检测棋盘格 Found chessboards 成功检测到棋盘格的图片数量。失败图片不会参与标定。 OpenCV RMS 误差 RMS OpenCV 标定过程中的整体误差指标。 相机内参矩阵 Camera matrix 相机内参矩阵描述相机自身的成像参数。 畸变系数 Distortion coefficients 镜头畸变系数描述径向畸变和切向畸变。 平均重投影误差 Average reprojection error 平均重投影误差单位为像素。数值越小说明估计参数越能解释检测到的角点。如果运行 Canon 数据集并提供-S 22.3x14.9终端还会输出视场角 FOV: 47.668073 32.770236 degrees 焦距 Focal length: 25.239815 mm 主点 Principal point: 11.147704 7.448943 mm 像素宽高比 Aspect ratio: 1.001614三组数据中Canon 已有结果的平均重投影误差约为0.160 pxC920 对称棋盘格约为0.215 px。重新拍摄或重新运行时数值可能因输入图片、角点检测和参数设置不同而变化。标定核心原理真实三维点棋盘格放在一个平面上所有内角点的Z0。程序根据-c和-s构造棋盘格真实坐标(0, 0, 0) (1*s, 0, 0) (2*s, 0, 0) ...其中s是-s指定的方格边长。代码位置calibrate.py - pattern_points图像二维点cv2.findChessboardCorners()在每张图片中检测棋盘格内角点。cv2.cornerSubPix()对角点位置进行亚像素优化使角点坐标达到小数像素精度。代码位置calibrate.py - process_image()3D-2D 对应关系每张成功检测到棋盘格的图片都会提供一组对应关系棋盘格真实 3D 点 obj_points - 图片中的 2D 像素角点 img_points同一张棋盘格的 3D 点不变不同图片中的 2D 角点位置不同。多张图片提供多组约束算法据此求解相机参数。代码位置calibrate.py - obj_points / img_points相机标定cv2.calibrateCamera()根据多组 3D-2D 对应关系求解camera_matrix distortion_coefficients rvecs tvecscamera_matrix和distortion_coefficients是相机自身参数。rvecs和tvecs是每张图片中棋盘格相对于相机的外参。代码位置calibrate.py - calibrate_func(...)重投影误差cv2.projectPoints()使用求出的相机参数把棋盘格 3D 点重新投影回图像平面。重投影点与真实检测角点之间的距离就是重投影误差。标定质量检查重投影误差较小 debug 角点图检测正确 棋盘覆盖图像不同区域 棋盘拍摄角度具有变化 去畸变结果视觉正常代码位置calibrate.py - project_func(...)如果有任何问题请私信我。所有代码均开源。标定代码和配备的实验标定数据代码链接https://download.csdn.net/download/qq_32998593/92952627?spm1001.2014.3001.5503