手把手教你用手机摄像头和A4纸完成棋盘格标定(附完整Python代码)

张开发
2026/4/17 5:16:04 15 分钟阅读

分享文章

手把手教你用手机摄像头和A4纸完成棋盘格标定(附完整Python代码)
用手机和A4纸玩转相机标定零成本实践指南想象一下你手里只有一部智能手机和一台普通打印机却想探索计算机视觉中最基础的相机标定技术。这听起来像天方夜谭事实上这正是我三年前在宿舍里完成的第一个视觉项目。当时作为穷学生的我用打印的棋盘格和手机摄像头不仅理解了相机内参的奥秘还做出了一个能测量桌面物体距离的小工具。今天我就把这份穷人版标定秘籍完整分享给你。1. 准备工作你的标定实验室1.1 硬件准备清单智能手机任何能拍摄清晰照片的机型都可建议关闭自动美颜功能A4纸和打印机用于打印棋盘格图案硬纸板或书本确保标定板平整不弯曲照明环境均匀的自然光或室内灯光避免强烈反光1.2 生成标准棋盘格使用Python生成可打印的棋盘格图案import cv2 import numpy as np def generate_chessboard(rows6, cols9, square_size25, filenamechessboard.png): width cols * square_size height rows * square_size image np.ones((height, width), dtypenp.uint8) * 255 for i in range(rows): for j in range(cols): if (i j) % 2 0: start_x j * square_size start_y i * square_size image[start_y:start_ysquare_size, start_x:start_xsquare_size] 0 cv2.imwrite(filename, image) return image # 生成6x9的棋盘格每个方格25mm generate_chessboard()提示实际打印后请用尺子测量方格尺寸确保打印缩放比例准确2. 拍摄技巧获取高质量标定图像2.1 拍摄姿势大全多角度覆盖从不同视角拍摄15-20张照片包括棋盘格位于画面中心棋盘格靠近四边和角落棋盘格有明显倾斜角度30°-60°距离变化近景占画面80%和远景占画面30%都要包含避免常见错误反光导致棋盘格过曝棋盘格弯曲变形手指遮挡部分图案2.2 手机相机设置建议设置项推荐值说明分辨率最高可用确保角点检测精度对焦模式手动对焦锁定在棋盘格平面ISO自动避免图像噪点过多HDR关闭防止自动图像处理干扰3. Python实战从图像到内参矩阵3.1 角点检测全流程import cv2 import glob import numpy as np # 准备对象点假设棋盘格在3D空间中的Z坐标为0 objp np.zeros((6*9,3), np.float32) objp[:,:2] np.mgrid[0:9,0:6].T.reshape(-1,2) * 25 # 25mm方格尺寸 # 存储所有图像的对象点和图像点 objpoints [] # 3D点 imgpoints [] # 2D点 images glob.glob(calib_photos/*.jpg) for fname in images: img cv2.imread(fname) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 查找角点 ret, corners cv2.findChessboardCorners(gray, (9,6), None) if ret: objpoints.append(objp) # 亚像素级精确化 criteria (cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) corners2 cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria) imgpoints.append(corners2) # 可视化可选 cv2.drawChessboardCorners(img, (9,6), corners2, ret) cv2.imshow(Corners, img) cv2.waitKey(500) cv2.destroyAllWindows()3.2 相机标定与结果解读# 执行相机标定 ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera( objpoints, imgpoints, gray.shape[::-1], None, None) print(相机矩阵:\n, mtx) print(\n畸变系数:, dist.ravel()) # 评估重投影误差 mean_error 0 for i in range(len(objpoints)): imgpoints2, _ cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist) error cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2)/len(imgpoints2) mean_error error print(\n平均重投影误差: {} 像素.format(mean_error/len(objpoints)))典型输出解析相机矩阵(mtx)fx,fy焦距像素单位反映手机摄像头的放大能力cx,cy主点坐标通常接近图像中心畸变系数(dist)k1,k2径向畸变系数桶形畸变为负值枕形畸变为正值p1,p2切向畸变系数反映镜头安装偏差重投影误差理想值应小于0.5像素大于1像素需检查拍摄质量4. 趣味应用打造手机测距仪4.1 单目测距原理利用已知物体尺寸如棋盘格方格和相机内参可以估算物体到相机的距离。基本公式实际物体高度 (焦距 × 物体像素高度 × 传感器高度) / (图像高度 × 物体实际高度)4.2 实战代码实现def distance_to_camera(known_width, focal_length, per_width): 计算到相机的距离 return (known_width * focal_length) / per_width # 假设已知棋盘格方格宽度为25mm square_width 25 # mm focal_length mtx[0,0] # 从相机矩阵获取焦距 # 检测当前图像中的棋盘格 ret, corners cv2.findChessboardCorners(gray, (9,6), None) if ret: # 计算最左侧和最右侧角点的像素距离 leftmost corners[0][0] rightmost corners[8][0] pixel_width abs(rightmost[0] - leftmost[0]) # 计算距离 distance distance_to_camera(square_width * 8, focal_length, pixel_width) print(f相机到棋盘格的距离: {distance:.1f} mm)4.3 精度提升技巧多方格平均法使用多个方格的平均尺寸减少误差动态校准在不同距离拍摄已知尺寸物体建立误差补偿模型姿态补偿当棋盘格不平行于成像平面时使用PNP算法修正# 使用PNP算法进行精确位姿估计 ret, rvec, tvec cv2.solvePnP(objp, corners2, mtx, dist) distance np.linalg.norm(tvec) # 计算相机到棋盘格的距离 print(f精确距离估计: {distance:.1f} mm)5. 进阶探索从标定到AR应用掌握了这些基础后你可以尝试镜头质量评估比较不同手机的畸变系数简单AR标记在棋盘格上叠加虚拟物体自制扫描仪用标定结果进行3D重建视觉SLAM入门理解相机运动估计的基础注意实际应用中环境光照、标定板平整度等因素都会影响最终精度。建议在正式项目中使用专业标定板本方法更适合教学和原型验证。

更多文章