如何用Python为AprilTag位姿估计进行相机校准?
核心概念明确
pupil_apriltags的位姿估计依赖的camera_params参数,本质就是相机的内参参数,格式为[fx, fy, cx, cy]:
fx/fy:相机在x/y轴上的焦距(像素单位)cx/cy:相机光心的x/y像素坐标
这和你之前用Aruco时用到的相机内参矩阵是同一组数据,只是提取方式不同。另外如果相机存在畸变,还需要传入distortion参数,格式为[k1, k2, p1, p2, k3](对应OpenCV校准输出的畸变系数)。
如何获取相机校准参数
用OpenCV完成相机校准即可得到所需参数,步骤如下:
1. 准备校准素材
- 打印一张棋盘格(推荐9x6个内角点的规格,格子边长自己测量记录)
- 用目标相机拍摄10-20张不同角度、不同距离的棋盘格照片(覆盖画面不同区域,尽量倾斜棋盘格)
2. 用OpenCV计算内参和畸变系数
运行以下代码(适配你的Windows环境和OpenCV 4.7.0):
import cv2 import numpy as np import glob # 棋盘格内角点数量(根据你打印的棋盘格调整) chessboard_corners = (9, 6) # 生成棋盘格的世界坐标(假设每个格子边长1单位,后续不影响内参计算) obj_points = np.zeros((chessboard_corners[0]*chessboard_corners[1], 3), np.float32) obj_points[:,:2] = np.mgrid[0:chessboard_corners[0], 0:chessboard_corners[1]].T.reshape(-1,2) world_points = [] # 存储所有棋盘格的世界坐标 image_points = [] # 存储所有棋盘格的图像坐标 # 读取校准照片(替换为你的照片路径) calib_images = glob.glob("calibration_photos/*.jpg") for img_path in calib_images: img = cv2.imread(img_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 检测棋盘格角点 ret, corners = cv2.findChessboardCorners(gray, chessboard_corners, None) if ret: world_points.append(obj_points) # 亚像素优化角点精度 refined_corners = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)) image_points.append(refined_corners) # 执行相机校准 ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera( world_points, image_points, gray.shape[::-1], None, None ) # 提取pupil_apriltags需要的参数 fx = camera_matrix[0][0] fy = camera_matrix[1][1] cx = camera_matrix[0][2] cy = camera_matrix[1][2] camera_params = [fx, fy, cx, cy] # 畸变系数转为列表格式 distortion = dist_coeffs[0].tolist() # 可以把参数保存到文件,后续直接读取使用 np.savez("camera_calib_params.npz", camera_params=camera_params, distortion=distortion)
3. 保存复用参数
校准完成后,把camera_params和distortion保存到文件,后续不需要重复校准,直接读取即可。
传入参数实现位姿估计
用pupil_apriltags检测时,开启位姿估计并传入校准参数,示例代码:
from pupil_apriltags import Detector import cv2 import numpy as np # 读取保存的校准参数 calib_data = np.load("camera_calib_params.npz") camera_params = calib_data["camera_params"] distortion = calib_data["distortion"] # 初始化AprilTag检测器(指定你使用的tag家族,比如tag36h11) detector = Detector(families="tag36h11") # 读取测试图像(或从摄像头实时获取帧) img = cv2.imread("test_tag.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 检测并估计位姿 # tag_size为AprilTag的实际物理边长(单位:米,和后续平移向量单位一致) detections = detector.detect( gray, estimate_tag_pose=True, camera_params=camera_params, distortion=distortion, tag_size=0.1 # 替换为你的tag实际尺寸 ) # 处理检测结果 for det in detections: print(f"检测到Tag ID: {det.tag_id}") print(f"旋转矩阵:\n{det.pose_R}") print(f"平移向量(米):\n{det.pose_t}")
注意事项
- 校准照片质量直接影响参数精度:避免模糊、过曝/欠曝,尽量让棋盘格占画面不同区域
tag_size必须是实际物理尺寸,否则位姿结果的平移向量会有比例误差- 如果相机畸变很小,也可以不传
distortion参数,或传入[0,0,0,0,0]跳过畸变校正
内容的提问来源于stack exchange,提问作者Maxime Dumonteil
相关产品推荐
相关产品推荐

