相机标定与畸变矫正,解决的是同一个问题的两端:标定是“搞清楚相机把世界扭曲成了什么样”,矫正是“把扭曲的图像拉回正常”。
为什么需要标定
工业视觉测量的前提是:图像中的像素坐标和真实世界的物理坐标之间存在确定的对应关系。但这个关系不是简单的线性缩放——镜头会引入畸变,相机安装角度会引入透视变形。
标定的目标就是求解相机的内参和外参:
内参描述相机自身的特性:焦距(fx, fy)、主点(cx, cy)、畸变系数(k1, k2, p1, p2, k3)。这些参数一旦标定,只要相机和镜头不动,就保持不变。
外参描述相机相对于世界坐标系的位置和姿态:旋转矩阵 R 和平移向量 t。如果相机移动了,外参需要重新标定。
畸变:镜头的“先天缺陷”
畸变主要分两类:
径向畸变:由镜头形状引起,表现为图像边缘的“桶形”或“枕形”弯曲。直线拍出来变成弯的,就是径向畸变。它用 k1、k2、k3 三个系数描述,越靠近边缘越明显。
切向畸变:由镜头和传感器不平行引起,表现为图像的“剪切”变形。它用 p1、p2 两个系数描述,通常比径向畸变小得多。
畸变模型的核心公式是:
x_distorted = x(1 + k1r² + k2r⁴ + k3r⁶) + 2p1xy + p2(r² + 2x²) y_distorted = y(1 + k1r² + k2r⁴ + k3r⁶) + p1(r² + 2y²) + 2p2xy其中 r² = x² + y²。标定的过程,就是通过已知的世界坐标和对应的图像坐标,反解出 k1、k2、p1、p2、k3 这些系数。
标定流程:用棋盘格求解
第一步:制作标定板。最常用的是棋盘格标定板,黑白方格交替,每个方格的物理尺寸已知(如 10mm)。棋盘格的优势是角点检测精度高,OpenCV 和 Halcon 都有现成的角点检测算子。
第二步:拍摄多张不同姿态的标定板图像。一般需要 10-20 张,覆盖图像的各个区域(中心、四角、边缘),并且标定板要有不同的倾斜角度。只拍正对相机的图,标定结果会不准——因为畸变在边缘最明显,必须让标定板出现在图像边缘。
第三步:检测角点。OpenCV 用FindChessboardCorners找到棋盘格的内角点,再用CornerSubPix做亚像素精化。
// OpenCV 标定varobjectPoints=newList<Mat>();varimagePoints=newList<Mat>();SizeboardSize=newSize(9,6);// 内角点数floatsquareSize=10.0f;// 方格物理尺寸 mm// 对每张标定图Matgray=newMat();Cv2.CvtColor(image,gray,ColorConversionCodes.BGR2GRAY);varcorners=newList<Point2f>();boolfound=Cv2.FindChessboardCorners(gray,boardSize,corners);if(found){Cv2.CornerSubPix(gray,corners,newSize(11,11),newSize(-1,-1),newTermCriteria(CriteriaTypes.Eps|CriteriaTypes.MaxIter,30,0.001));imagePoints.Add(Mat.FromArray(corners.ToArray()));objectPoints.Add(GenerateObjectPoints(boardSize,squareSize));}// 标定MatcameraMatrix=newMat();MatdistCoeffs=newMat();Cv2.CalibrateCamera(objectPoints,imagePoints,gray.Size(),cameraMatrix,distCoeffs,out_,out_);第四步:评估标定质量。CalibrateCamera返回的重投影误差(reprojection error)是核心指标。它表示用标定出的参数把世界点投影回图像后,与检测到的角点之间的平均偏差。小于 0.5 像素算好,小于 0.2 像素算优秀。如果误差大于 1 像素,说明标定板图像质量有问题,或者姿态覆盖不够。
畸变矫正:两种方式
方式一:Undistort直接矫正。对整幅图像做畸变矫正,输出一张“拉直”的图。适合需要保存矫正后图像的场景。
Matundistorted=newMat();Cv2.Undistort(src,undistorted,cameraMatrix,distCoeffs);方式二:InitUndistortRectifyMap+Remap。预先计算矫正映射表,后续每帧用Remap快速应用。高帧率场景必须用这种方式,因为映射表只算一次,每帧只做查表操作。
Matmap1=newMat(),map2=newMat();Cv2.InitUndistortRectifyMap(cameraMatrix,distCoeffs,newMat(),cameraMatrix,imageSize,MatType.CV_32FC1,map1,map2);// 每帧Cv2.Remap(src,dst,map1,map2,InterpolationFlags.Linear);工业实操要点
标定板要覆盖整个视野。畸变在图像边缘最严重,如果标定板只在中心区域拍摄,边缘的畸变系数就标不准。正确做法是让标定板出现在图像的中心、四角、四边,每个位置都有不同倾斜角度的图像。
标定后不要动相机和镜头。一旦标定完成,相机和镜头的相对位置、焦距、光圈都不能再变。动了任何一个,标定就失效了。工业现场通常把相机和镜头锁死,标定一次用很久。
畸变矫正会损失边缘像素。矫正后图像边缘可能被“拉”出视野,或者出现黑边。如果检测区域靠近图像边缘,需要预留余量。
精度要求极高时用远心镜头。远心镜头的畸变极小,几乎不需要矫正,而且没有透视误差。代价是视野小、工作距离固定、价格高。
一句话总结
标定是用已知尺寸的标定板,反解出相机的内参和畸变系数。矫正是用这些系数把畸变图像拉直。标定的质量决定了测量的上限——重投影误差小于 0.2 像素,是工业级标定的基本门槛。