本文采用知识共享署名 4.0 国际许可协议进行许可,转载时请注明原文链接,图片在使用时请保留全部内容,可适当缩放并在引用处附上图片所在的文章链接。
相机标定即获取相机的内参,外参和畸变矩阵等相机参数
内参
相机内参矩阵是相机自身的属性,内参分别为:
f:焦距,单位毫米;
fx:使用像素来描述x轴方向焦距的长度;
fy:使用像素来描述y轴方向焦距的长度
u0,v0: 主点坐标(相对于成像平面),单位也是像素;
γ:为坐标轴倾斜参数,理想情况下为0;
外参
相机的旋转矩阵R和平移向量t
旋转矩阵:描述了世界坐标系的坐标轴相对于摄像机坐标轴的方向
平移矩阵:描述了在摄像机坐标系下,空间原点的位置
畸变参数
畸变参数:k1,k2,k3径向畸变系数,p1,p2是切向畸变系数。径向畸变发生在相机坐标系转图像物理坐标系的过程中。而切向畸变是发生在相机制作过程,其是由于感光元平面跟透镜不平行。径向畸变,即由于透镜的不同区域的焦距的不同而引起的畸变,分为枕形畸变和桶形畸变如下图所示,越靠近镜头边缘畸变越明显。
相机内参和外参的解释
相机内参的标定方法
bool findChessboardCorners( InputArray image,
Size patternSize,
OutputArray corners,
int flags = CALIB_CB_ADAPTIVE_THRESH +
CALIB_CB_NORMALIZE_IMAGE );
第一个参数是输入的棋盘格图像(可以是8位单通道或三通道图像);
第二个参数是棋盘格内部的角点的行列数(注意:不是棋盘格的行列数,如棋盘格的行列数分别为4、8,而内部角点的行列数分别是3、7,因此这里应该指定为cv::Size(3, 7));
第三个参数是检测到的棋盘格角点,类型为std::vectorcv::Point2f。
第四个参数flag,用于指定在检测棋盘格角点的过程中所应用的一种或多种过滤方法,可以使用下面的一种或多种,如果都是用则使用OR:
cv::CALIB_CB_ADAPTIVE_THRESH:使用自适应阈值将图像转化成二值图像
cv::CALIB_CB_NORMALIZE_IMAGE:归一化图像灰度系数(用直方图均衡化或者自适应阈值)
cv::CALIB_CB_FILTER_QUADS:在轮廓提取阶段,使用附加条件排除错误的假设
cv::CALIB_CV_FAST_CHECK:快速检测
bool find4QuadCornerSubpix( InputArray img,
InputOutputArray corners,
Size region_size );
image源图像
corners,提供角点的初始坐标
region_size: 搜索窗口的一般尺寸\
void cornerSubPix( InputArray image,
InputOutputArray corners,
Size winSize,
Size zeroZone,
TermCriteria criteria );
image源图像
corners,提供角点的初始坐标,返回更加精确的点
winSize,搜索窗口的一般尺寸,如果winSize=Size(5,5),则search windows为11*11
winSize,死区的一般尺寸,用来避免自相关矩阵的奇点,(-1,-1)表示没有死区
criteria,控制迭代次数和精度
void drawChessboardCorners( InputOutputArray image,
Size patternSize,
InputArray corners,
bool patternWasFound );
image为8-bit,三通道图像
patternSize,每一行每一列的角
corners,已经检测到的角
patternWasFound,findChessboardCorners的返回值
void CCalibration::init3DPoints(cv::Size boardSize, cv::Size squareSize, vector<cv::Point3f> &singlePatternPoint)
{
for (int i = 0; i < boardSize.height; i++)
{
for (int j = 0; j < boardSize.width; j++)
{
cv::Point3f tempPoint; //单个角点的三维坐标
tempPoint.x = float(i * squareSize.width);
tempPoint.y = float(j * squareSize.height);
tempPoint.z = 0;
singlePatternPoint.push_back(tempPoint);
}
}
}
double calibrateCamera( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints,
Size imageSize,
InputOutputArray cameraMatrix,
InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
int flags = 0,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT +
TermCriteria::EPS, 30, DBL_EPSILON) );
objectPoints,世界坐标,用vector,输入x,y坐标,z坐标为0
imagePoints,图像坐标,vector
imageSize,图像的大小用于初始化标定摄像机的image的size
cameraMatrix
,内参数矩阵
distCoeffs
,畸变矩阵
rvecs
,位移向量
tvecs
,旋转向量
flags,可以组合:
CV_CALIB_USE_INTRINSIC_GUESS:使用该参数时,将包含有效的fx,fy,cx,cy的估计值的内参矩阵cameraMatrix,作为初始值输入,然后函数对其做进一步优化。如果不使用这个参数,用图像的中心点初始化光轴点坐标(cx, cy),使用最小二乘估算出fx,fy(这种求法好像和张正友的论文不一样,不知道为何要这样处理)。注意,如果已知内部参数(内参矩阵和畸变系数),就不需要使用这个函数来估计外参,可以使用solvepnp()函数计算外参数矩阵。CV_CALIB_FIX_PRINCIPAL_POINT:在进行优化时会固定光轴点,光轴点将保持为图像的中心点。当CV_CALIB_USE_INTRINSIC_GUESS参数被设置,保持为输入的值。
CV_CALIB_FIX_ASPECT_RATIO:固定fx/fy的比值,只将fy作为可变量,进行优化计算。当
CV_CALIB_USE_INTRINSIC_GUESS没有被设置,fx和fy的实际输入值将会被忽略,只有fx/fy的比值被计算和使用。CV_CALIB_ZERO_TANGENT_DIST:切向畸变系数(P1,P2)被设置为零并保持为零。
CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6:对应的径向畸变系数在优化中保持不变。如果设置了CV_CALIB_USE_INTRINSIC_GUESS参数,就从提供的畸变系数矩阵中得到。否则,设置为0。
CV_CALIB_RATIONAL_MODEL(理想模型):启用畸变k4,k5,k6三个畸变参数。使标定函数使用有理模型,返回8个系数。如果没有设置,则只计算其它5个畸变参数。
CALIB_THIN_PRISM_MODEL (薄棱镜畸变模型):启用畸变系数S1、S2、S3和S4。使标定函数使用薄棱柱模型并返回12个系数。如果不设置标志,则函数计算并返回只有5个失真系数。
CALIB_FIX_S1_S2_S3_S4 :优化过程中不改变薄棱镜畸变系数S1、S2、S3、S4。如果cv_calib_use_intrinsic_guess设置,使用提供的畸变系数矩阵中的值。否则,设置为0。
CALIB_TILTED_MODEL (倾斜模型):启用畸变系数tauX and tauY。标定函数使用倾斜传感器模型并返回14个系数。如果不设置标志,则函数计算并返回只有5个失真系数。
CALIB_FIX_TAUX_TAUY :在优化过程中,倾斜传感器模型的系数不被改变。如果cv_calib_use_intrinsic_guess设置,从提供的畸变系数矩阵中得到。否则,设置为0。
参考:
相机标定(4) 矫正畸变 undistort()和initUndistortRectifyMap()
initUndistortRectifyMap
CV_EXPORTS_W void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs,
InputArray R, InputArray newCameraMatrix,
Size size, int m1type, OutputArray map1, OutputArray map2 );
//! initializes maps for cv::remap() for wide-angle
CV_EXPORTS_W float initWideAngleProjMap( InputArray cameraMatrix, InputArray distCoeffs,
Size imageSize, int destImageWidth,
int m1type, OutputArray map1, OutputArray map2,
int projType = PROJ_SPHERICAL_EQRECT, double alpha = 0);
1.
cameraMatrix
:输入相机矩阵
2.distCoeffs
:输入参数,相机的畸变系数: (k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τ**x,τ**y]]]]) ,有4,5,8,12或14个元素。如果这个向量是空的,就认为是零畸变系数。
3.R
:可选的修正变换矩阵,是个3*3的矩阵。通过stereoRectify
计算得来的R1或R2可以放在这里。如果这个矩阵是空的,就假设为单位矩阵。在cvInitUndistortMap
中,R被认为是单位矩阵。
4.newCameraMatrix
:新的相机矩阵
5.size
:未畸变的图像尺寸。
6.m1type
:第一个输出的映射的类型,可以为 CV_32FC1, CV_32FC2或CV_16SC2,参见cv::convertMaps
。
7.map1
:第一个输出映射。
8.map2
:第二个输出映射。
这个函数用于计算无畸变和修正转换关系,为了重映射,将结果以映射的形式表达。无畸变的图像看起来就像原始的图像,就像这个图像是用内参为newCameraMatrix的且无畸变的相机采集得到的。
在单目相机例子中,newCameraMatrix一般和cameraMatrix相等,或者可以用cv::getOptimalNewCameraMatrix来计算,获得一个更好的有尺度的控制结果。
在双目相机例子中,newCameraMatrix一般是用cv::stereoRectify计算而来的,设置为P1或P2。 此外,根据R,新的相机在坐标空间中的取向是不同的。例如,它帮助配准双目相机的两个相机方向,从而使得两个图像的极线是水平的,且y坐标相同(在双目相机的两个相机谁水平放置的情况下)。 该函数实际上为反向映射算法构建映射,供反向映射使用。也就是,对于在已经修正畸变的图像中的每个像素(u,v),该函数计算原来图像(从相机中获得的原始图像)中对应的坐标系。
函数输出得到map1和map2,然后使用remap()函数
void remap( InputArray src, OutputArray dst,
InputArray map1, InputArray map2,
int interpolation, int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar());
第一个参数:输入图像,即原图像,需要单通道8位或者浮点类型的图像
第二个参数:输出图像,即目标图像,需和原图形一样的尺寸和类型
第三个参数:它有两种可能表示的对象:(1)表示点(x,y)的第一个映射;(2)表示CV_16SC2,CV_32FC1等
第四个参数:它有两种可能表示的对象:(1)若map1表示点(x,y)时,这个参数不代表任何值;(2)表示 CV_16UC1,CV_32FC1类型的Y值
第五个参数:插值方式,有四种插值方式:
(1)INTER_NEAREST——最近邻插值(2)INTER_LINEAR——双线性插值(默认)
(3)INTER_CUBIC——双三样条插值(默认)
(4)INTER_LANCZOS4——lanczos插值(默认)
第六个参数:边界模式,默认BORDER_CONSTANT
第七个参数:边界颜色,默认Scalar()黑色
完整代码工程(包含标定图片):
camera-calibration