相机标定Camera Calibration是计算机视觉、自动驾驶、机器人SLAM以及 AR/VR 领域中不可或缺的“基本功”。简单来说相机的镜头就像是一面哈哈镜多多少少都有畸变而标定的目的就是帮相机找回“视力”看清真实的三维世界。下面为你带来一份通俗易懂、包含数学原理与代码实战的相机标定全景指南。一、 核心原理我们在标定什么相机成像的过程实际上是把**三维世界World中的点映射到相机的二维像素平面Pixel上。这个过程可以用四个坐标系的转换来描述世界坐标系→相机坐标系→图像坐标系→像素坐标系标定的核心任务就是求解两个矩阵内参和外参以及一组畸变参数1. 相机内参Intrinsic Parameters—— 解决“相机本身”的问题内参是由相机自身的机械和光学结构决定的如焦距、感光元件大小。一旦相机组装好并且不失焦内参就是固定不变的。 内参矩阵通常写为Kfx,fy横向和纵向的焦距以像素为单位。cx,cy主点坐标即相机光轴在图像传感器上的中心点通常接近图像的正中央。2. 相机外参Extrinsic Parameters—— 解决“相机摆放”的问题外参决定了相机在三维世界中的位置和朝向。旋转矩阵R相机朝哪儿看俯仰、偏航、翻滚。平移向量T相机在什么位置。注意如果相机在移动比如装在车上外参是会随着运动实时变化的。3. 畸变参数Distortion Coefficients—— 解决“镜头变型”的问题普通的透镜尤其是广角或鱼眼镜头往往会导致直线变曲线。主要分为两种径向畸变Radial Distortion由于透镜形状导致越靠近图像边缘变型越厉害。表现为桶形畸变鼓起来或枕形畸变凹进去。切向畸变Tangential Distortion由于镜头组装时透镜与感光芯片CMOS/CCD没有完全平行导致。二、 主流标定方法张正友标定法目前工业界和学术界最常用的方案是**“张正友标定法”Zhang’s Method。在它问世之前标定需要搭建昂贵的三维标定物而张氏标定法只需要一张打印出来的二维黑白棋盘格**在不同角度拍十几张照片即可。标定的标准流水线Workflow准备标定板打印一张高精度的黑白棋盘格或 ChArUco 标定板通常贴在平整的刚体表面如玻璃或碳纤维板上。采集图像变换不同的角度、距离、高度拍摄 15∼25 张标定板的照片。避坑指南标定板要尽量占满整个画面特别是图像的四周边缘因为边缘的畸变最大只有覆盖到边缘才能准确计算畸变参数。提取角点Corner Extraction在计算机中识别棋盘格黑白相间的交点。优化求解利用数学优化算法如 LM 算法让重投影误差最小从而解出内参、外参和畸变系数。三、 代码实战使用 OpenCV 自动标定以下是使用 Python 和 OpenCV 实现相机标定的标准脚本。你只需要把拍摄好的照片放到一个文件夹里即可运行。import cv2 import numpy as np import glob # 1. 设定标定板的参数 # 注意这里的行列数是黑白格子交点的个数不是格子的个数 # 例如一个 9x7 格子的棋盘内角点是 8x6 CHECKERBOARD (8, 6) square_size 25.0 # 单个黑白格子的实际物理边长单位毫米 mm # 定义三维世界坐标系下的棋盘格点坐标 objp np.zeros((CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32) objp[:, :2] np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2) objp objp * square_size # 存储所有照片的三维世界点和二维像素点 objpoints [] # 3d points in real world space imgpoints [] # 2d points in image plane. # 读取文件夹中所有的标定照片 images glob.glob(calibration_images/*.jpg) for fname in images: img cv2.imread(fname) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 2. 寻找棋盘格角点 ret, corners cv2.findChessboardCorners(gray, CHECKERBOARD, None) if ret True: 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, CHECKERBOARD, corners2, ret) cv2.imshow(Chessboard Detection, img) cv2.waitKey(100) cv2.destroyAllWindows() # 3. 核心步骤相机标定 # 返回值ret(重投影误差), mtx(内参), dist(畸变系数), rvecs(旋转外参), tvecs(平移外参) ret, mtx, dist, rvecs, tvecs cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) print(f--- 标定完成 ---) print(f重投影误差 (Re-projection Error): {ret:.4f} 像素) print(f相机内参矩阵 (Intrinsic Matrix):\n{mtx}) print(f畸变系数 (Distortion Coefficients):\n{dist}) # 4. 利用标定结果矫正一张畸变照片 test_img cv2.imread(calibration_images/test_pic.jpg) h, w test_img.shape[:2] # 优化内参矩阵 newcameramtx, roi cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h)) # 矫正去畸变 dst cv2.undistort(test_img, mtx, dist, None, newcameramtx) # 裁剪并保存 x, y, w_box, h_box roi dst dst[y:yh_box, x:xw_box] cv2.imwrite(calibrated_result.jpg, dst) print(去畸变照片已保存为 calibrated_result.jpg)四、 工业级标定的避坑与评估拿到标定数据后你怎么知道标定得准不准1. 核心指标重投影误差Re-projection Error它是指把标定计算出的三维世界点重新投影回像素平面与实际拍摄到的角点之间的像素距离。优秀误差 0.5 像素。合格误差 1.0 像素。如果误差 1.5 像素说明部分照片拍糊了、标定板不平整或者角点识别错误建议剔除坏照片重新计算。2. 提高标定精度的实战技巧关键要素错误做法正确做法画面覆盖率标定板只在屏幕中心晃悠必须把标定板移动到图像的四个角落和边缘角度丰富度标定板永远平行于相机正对标定板需要产生倾斜角度俯仰角度、翻转角度光照与对焦画面有反光、阴影、或者运动模糊使用高均匀度光源运动时拿稳停顿再拍严禁动态模糊硬件刚性打印纸贴在软纸板上产生肉眼难察的弯曲必须贴在高平整度的亚克力板、玻璃或专业定制的铝合金板上