【标定+Opencv】张正友:A Flexible New Technique for Camera Calibration

文章目录

    • 1 Motivations
    • 2 Basic Equations - 3 Solving Camera Calibration
    • 3 实践OpenCV
      • 1.获取棋盘格文件目录
      • 2. 角点提取
        • 1. cv::findChessboardCorners
        • 2. cv::TermCriteria
        • 3. cv::cornerSubPix
        • 4. cv::drawChessboardCorners
      • 3.标定
        • 1. cv::calibrateCamera
        • 2. cv::stereoCalibrate
        • 3.cv::stereoRectify
        • 4. cv::initUndistortRectifyMap
        • 5. cv::undistort
        • 6. cv::undistortPoints

1 Motivations

将标定方法粗略分为摄影测量标定( photogrammetric calibration)和自标定(selfcalibration)。
机器视觉中的摄像机标定和自标定分析

  • 摄影测量标定( photogrammetric calibration)
    观察校准对象(在3D空间中其几何信息已知且高精度)。校准对象通常由两个或三个相互正交的平面组成。
  • 自标定(selfcalibration)
    不需要任何校准对象。仅利用摄像机在运动过程中周围环境图像与图像之间的对应关系来对摄像机进行的标定的方法称为摄像机自标定方法。

本文:
只需要相机观察在几个(至少两个)不同方向上显示的平面图案。
相机和平面都可以移动,且不需要知道它们的移动。
介于摄影测量校准和自校准之间,因为我们使用 2D 度量信息而不是 3D 或纯隐式信息。

2 Basic Equations - 3 Solving Camera Calibration

立体视觉入门指南(3):相机标定之张式标定法【超详细值得收藏】

3 实践OpenCV

第六节、双目视觉之相机标定
张正友畸变矫正C++代码
双目视觉标定程序讲解
OPENCV3.0 双目立体标定
双目标定的注意事项 已经遇到了起源点的问题
双目相机OpenCV标定常见问题汇总
双目标定(三)标定流程(含矫正)
OpenCV学习笔记(17)双目测距与三维重建的OpenCV实现问题集锦(二)双目定标与双目校正

1.获取棋盘格文件目录

ubuntu中获取文件名称并生成txt文件
问题:读取图片时可能会出现图片为空,导致错误。
注意:读取时判断一下是否为空。

int main()
{
    //单个相机,图片路径
    std::string infile="/home/标定/camera/chessboard.txt";
    //标定结果和保存文件
    std::string outfile="/home/标定/camera/calib_result.txt";
    //读取图片
    std::ifstream fin(infile);
    std::ofstream fout(outfile);
    std::vector<cv::Mat> images;
    if(fin.is_open())
    {
        while(!fin.eof()){
            std::string str;
            fin>>str;
            cv::Mat image=cv::imread("/home/标定/camera"+str);
            if(!image.empty())
                images.emplace_back(image);
        }
        cv::Size board=cv::Size(9,13);
        SingleCameraCalib scc(images,board);
    }
    
    return 0;
}

2. 角点提取

1. cv::findChessboardCorners

findChessboardCorners函数学习笔记
openCV函数用法之 findChessboardCorners
该函数尝试确定输入图像是否是棋盘图案的视图并定位内部棋盘角。如果找到所有角并且它们按特定顺序放置(逐行,每行从左到右),则该函数返回一个非零值。 否则,如果函数未能找到所有角点或重新排序它们,则返回 0。例如,一个普通的棋盘有 8 x 8 个方格和 7 x 7个内角,即黑色方格相互接触的点。 检测到的坐标是近似的,为了更准确地确定它们的位置,该函数调用cornerSubPix。如果返回的坐标不够准确,您也可以使用带有不同参数的函数cornerSubPix。

 bool cv::findChessboardCorners 	( 	
 		InputArray  	image,
		Size  	patternSize,
		OutputArray  	corners,
		int  	flags = CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE 
	) 		
image 源棋盘视图。 它必须是 8 位灰度或彩色图像
patternSize 每个棋盘行和列的内角数( patternSize = cv::Size(points_per_row,points_per_colum) = cv::Size(columns,rows) )
corners 检测到的角的输出数组
flags 可以为零或以下值组合的各种操作标志:
CALIB_CB_ADAPTIVE_THRESH 使用自适应阈值将图像转换为黑白,而不是固定阈值级别(根据平均图像亮度计算)
CALIB_CB_NORMALIZE_IMAGE 在应用固定或自适应阈值之前,使用 equalizeHist 规范化图像伽玛
CALIB_CB_FILTER_QUADS 使用其他标准(如轮廓面积、周长、类似正方形的形状)过滤掉在轮廓检索阶段提取的错误四边形
CALIB_CB_FAST_CHECK 对图像进行快速检查以查找棋盘角,如果没有找到则快捷调用。 当没有观察到棋盘时,这可以大大加快退化条件下的调用
2. cv::TermCriteria

OpenCV cv::TermCriteria 模板类

3. cv::cornerSubPix

【OpenCV3】角点检测——cv::goodFeaturesToTrack()与cv::cornerSubPix()详解
优化角点位置

image 输入单通道、8 位或浮点图像
corners 输入角的初始坐标和为输出提供的细化坐标
winSize 搜索窗口边长的一半。 例如,如果 winSize=Size(5,5) ,则使用 (5∗2+1)×(5∗2+1)=11×11 搜索窗口
zeroZone 搜索区域中间的死区大小的一半,在该区域上未进行以下公式中的求和。 它有时用于避免自相关矩阵可能出现的奇异性。 (-1,-1) 的值表示没有这样的大小。
criteria 角细化迭代过程的终止标准。 也就是说,角位置细化的过程在criteria.maxCount 迭代之后或在某个迭代中角位置移动小于criteria.epsilon 时停止。
4. cv::drawChessboardCorners

【OpenCV3】棋盘格角点检测与绘制——cv::findChessboardCorners()与cv::drawChessboardCorners()详解

3.标定

1. cv::calibrateCamera
double cv::calibrateCamera 	( 	InputArrayOfArrays  	objectPoints,
		InputArrayOfArrays  	imagePoints,
		Size  	imageSize,
		InputOutputArray  	cameraMatrix,
		InputOutputArray  	distCoeffs,
		OutputArrayOfArrays  	rvecs,
		OutputArrayOfArrays  	tvecs,
		OutputArray  	stdDeviationsIntrinsics,
		OutputArray  	stdDeviationsExtrinsics,
		OutputArray  	perViewErrors,
		int  	flags = 0,
		TermCriteria  	criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, DBL_EPSILON) 
	) 	
2. cv::stereoCalibrate

C++ OpenCV V4.x中的新版双目标定函数stereoCalibrate() 参数说明【新增perViewErrors】

校准立体相机设置。 此函数查找两个相机中每一个的内在参数和两个相机之间的外在参数。
该函数估计构成立体对的两个相机之间的转换。如果计算对象相对于第一个摄像机和第二个摄像机的位姿,分别为 (R1, T1) 和 (R2, T2),对于两个摄像机之间的相对位置和方向固定的立体摄像机, 那么这些姿势肯定是相互关联的。这意味着,如果两个相机的相对位置和方向 (R, T) 已知,则可以在给定 (R1, T1) 时计算 (R2, T2)。
除了立体相关信息外,该功能还可以对两个摄像头中的每一个进行全面校准。 然而,由于参数空间的高维和输入数据中的噪声,函数可能会偏离正确的解。如果可以单独为每个相机高精度估计内在参数(例如,使用 calibrateCamera ),建议您这样做,然后将 CALIB_FIX_INTRINSIC 标志与计算的内在参数一起传递给函数。 否则,如果一次估计所有参数,则限制某些参数是有意义的,例如,传递 CALIB_SAME_FOCAL_LENGTH 和 CALIB_ZERO_TANGENT_DIST 标志,这通常是一个合理的假设。
与 calibrateCamera 类似,该函数将两个相机的所有可用视图中所有点的总重投影误差最小化。 该函数返回重投影误差的最终值。

flag
CALIB_FIX_INTRINSIC 内参数固定,仅估计 R、T、E 和 F 矩阵。
CALIB_USE_INTRINSIC_GUESS 根据指定的标志优化部分或全部内在参数。 初始值由用户提供。
CALIB_USE_EXTRINSIC_GUESS R 和 T 为有效初始值。 否则 R 和 T 被初始化为模式视图的中值(每个维度)。
CALIB_FIX_PRINCIPAL_POINT 在优化过程中固定主点。
CALIB_FIX_FOCAL_LENGTH 固定焦距
CALIB_FIX_ASPECT_RATIO 优化fy,固定比率 fx/fy
CALIB_SAME_FOCAL_LENGTH 强制执行 f(0)x=f(1)x 和 f(0)y=f(1)y 焦距相等
CALIB_ZERO_TANGENT_DIST 将每个相机的切向畸变系数设置为零并固定
CALIB_FIX_K1,…, CALIB_FIX_K6 在优化过程中不要改变相应的径向畸变系数。 如果设置了 CALIB_USE_INTRINSIC_GUESS,则使用提供的 distCoeffs 矩阵中的系数。 否则,将其设置为 0。
CALIB_RATIONAL_MODEL 启用系数 k4、k5 和 k6。 为了提供向后兼容性,应明确指定此额外标志以使校准函数使用有理模型并返回 8 个系数。 如果未设置该标志,则该函数仅计算并返回 5 个失真系数。
CALIB_THIN_PRISM_MODEL 启用系数 s1、s2、s3 和 s4。 为了提供向后兼容性,应明确指定此额外标志以使校准函数使用薄棱镜模型并返回 12 个系数。 如果未设置该标志,则该函数仅计算并返回 5 个失真系数。
CALIB_FIX_S1_S2_S3_S4 薄棱镜畸变系数在优化过程中没有改变。 如果设置了 CALIB_USE_INTRINSIC_GUESS,则使用提供的 distCoeffs 矩阵中的系数。 否则,将其设置为 0。
CALIB_TILTED_MODEL 启用系数 tauX 和 tauY。 为了提供向后兼容性,应明确指定此额外标志以使校准函数使用倾斜传感器模型并返回 14 个系数。 如果未设置该标志,则该函数仅计算并返回 5 个失真系数。
CALIB_FIX_TAUX_TAUY 倾斜传感器模型的系数在优化过程中没有改变。 如果设置了 CALIB_USE_INTRINSIC_GUESS,则使用提供的 distCoeffs 矩阵中的系数。 否则,将其设置为 0。
3.cv::stereoRectify

OpenCV学习之stereoRectify()函数及initUndistortRectifyMap()函数参数说明
为每一个标定过的双目相机计算校正变换

void cv::stereoRectify 	( 	
		InputArray  	cameraMatrix1,
		InputArray  	distCoeffs1,
		InputArray  	cameraMatrix2,
		InputArray  	distCoeffs2,
		Size  	imageSize,
		InputArray  	R,
		InputArray  	T,
		OutputArray  	R1,
		OutputArray  	R2,
		OutputArray  	P1,
		OutputArray  	P2,
		OutputArray  	Q,
		int  	flags = CALIB_ZERO_DISPARITY,
		double  	alpha = -1,
		Size  	newImageSize = Size(),
		Rect *  	validPixROI1 = 0,
		Rect *  	validPixROI2 = 0 
	) 	
cameraMatrix1 第一个相机内参矩阵
distCoeffs1 第一个相机畸变参数
cameraMatrix2 第二个相机内参矩阵
distCoeffs2 第二个相机畸变参数
imageSize 用于相机标定的图像尺寸
R 从第一个相机到第二个相机坐标系系统的旋转矩阵
T 从第一个相机到第二个相机的坐标系的平移矩阵
R1 为第一个相机输出3x3的修正矩阵(旋转矩阵)。该矩阵将未经过校正的第一个摄像机坐标系中给出的点引入到经过校正的第一个摄像机坐标系中的点。用更专业的术语来说,它执行了一个基础的改变,从未矫正的第一个摄像机的坐标系到矫正的第一个摄像机的坐标系。
R2 为第二个相机输出3x3的校正变换(旋转矩阵)。该矩阵将未校正的第二摄像机坐标系中给定的点引入已校正的第二摄像机坐标系中的点。用更专业的术语来说,它执行了一个基础的改变,从未矫正的第二个摄像机的坐标系到矫正的第二个摄像机的坐标系。
P1 为第一个摄像机输出新的(经校正的)坐标系统中的3x4投影矩阵,即它将经校正的第一个摄像机坐标系统中给定的点投影到被校正的第一个摄像机的图像中。
P2 为第二个摄像机输出新的(经校正的)坐标系统中的3x4投影矩阵,即将经校正的第一个摄像机坐标系统中给定的点投影到经校正的第二个摄像机的图像中。
Q 输出4x4的视差-深度映射矩阵
flags 操作标志,可以是零或CALIB_ZERO_DISPARITY。如果设置了标志,该函数将使每个摄像机的主点在校正视图中具有相同的像素坐标。如果没有设置标志,函数仍然可以在水平或垂直方向(取决于极线的方向)移动图像,以最大化有用的图像区域。
alpha 自由的尺度参数。如果是-1或缺席,函数将执行默认的缩放。否则,参数应该在0和1之间。alpha=0表示校正后的图像被缩放和移动,只有有效像素可见(校正后没有黑色区域)。alpha=1表示对校正后的图像进行抽取和移位,使所有来自相机的原始图像的像素都保留在校正后的图像中(无源图像像素丢失)。任何中间值都是这两个极端情况的中间结果。
newImageSize 校正后图像分辨率。同样的大小也应该传递给initUndistortRectifyMap (参见OpenCV样本目录中的stereo_calib.cpp样本)。当传递(0,0)时(默认),将其设置为原始imageSize。将其设置为较大的值可以帮助您保存原始图像的细节,特别是当有一个大的径向失真。
validPixROI1 矫正图像内的可选的输出矩形,其中所有像素是有效的。如果alpha=0, ROI覆盖整个图像。否则,它们可能会更小(见下图)。
validPixROI2 矫正图像内的可选的输出矩形,其中所有像素是有效的。如果alpha=0, ROI覆盖整个图像。否则,它们可能会更小(见下图)。
4. cv::initUndistortRectifyMap

计算不失真和校正变换图。

void cv::initUndistortRectifyMap 	( 	
		InputArray  	cameraMatrix,//输入相机矩阵
		InputArray  	distCoeffs,//失真系数的输入向量
		InputArray  	R,//对象空间中的可选校正变换(3x3 矩阵)。 
		//可以在此处传递由 stereoRectify 计算的 R1 或 R2 。 如果矩阵为空,则假定恒等变换。 在 cvInitUndistortMap假定R为单位矩阵。
		InputArray  	newCameraMatrix,//新的相机矩阵
		Size  	size,//不失真的图像大小。
		int  	m1type,//第一个输出映射的类型,可以是 CV_32FC1、CV_32FC2 或 CV_16SC2,请参阅 convertMaps
		OutputArray  	map1,//第一个输出映射。
		OutputArray  	map2 //第二个输出图。
	) 	

该函数实际上为 remap 使用的逆映射算法构建映射。 对于目标(不失真和校正过)图像中的每个像素 (u,v),该函数计算源图像(即来自相机的原始图像)中的相应坐标。 应用以下过程:
【标定+Opencv】张正友:A Flexible New Technique for Camera Calibration_第1张图片

5. cv::undistort

转换图像以补偿镜头失真。
该函数转换图像以补偿径向和切向镜头失真。

void cv::undistort 	( 	
		InputArray  	src,//输入(失真)图像。
		OutputArray  	dst,//输出(校正后的)图像,其大小和类型与 src 相同。
		InputArray  	cameraMatrix,//输入相机矩阵
		InputArray  	distCoeffs,//失真系数的输入向量
		InputArray  	newCameraMatrix = noArray() 
		//畸变图像的相机矩阵。 默认情况下,它与 cameraMatrix 相同,但您可以使用不同的矩阵额外缩放和移动结果。
	) 		

6. cv::undistortPoints

【标定+Opencv】张正友:A Flexible New Technique for Camera Calibration_第2张图片根据观测点坐标计算理想点坐标。(推公式,相机坐标系到像素坐标系这一块)
该函数类似于 undistort 和 initUndistortRectifyMap,但它对稀疏的点集而不是光栅图像进行操作。 该函数还对 projectPoints 执行反向转换。 在 3D 对象的情况下,它不会重建其 3D 坐标,但对于平面对象,如果指定了适当的 R,它会重建一个平移向量。其中 undistort 是一种近似迭代算法,它从归一化的失真点坐标中估计出归一化的原始点坐标(“归一化”意味着坐标不依赖于相机矩阵)。
该函数可用于立体摄像头或单目摄像头(当 R 为空时)。

src:观测到的点,1xN or Nx1 2-channel (CV_32FC2 or CV_64FC2)
dst:输出不失真(去畸变?)和反向透视变换后的理想点坐标。如果矩阵 P 是恒等矩阵或省略,则 dst 将包含归一化点坐标。
cameraMatrix: 内参矩阵
distCoeffs: 畸变系数
R:对象空间中的校正变换(3x3 矩阵)。通过 stereoRectify 计算的 R1 或 R2 可以在这里传递。如果矩阵为空,则使用恒等变换
P:新相机矩阵 (3x3) 或新投影矩阵 (3x4)。通过stereoRectify 计算的 P1 或 P2 可以在这里传递。如果矩阵为空,则使用标识新相机矩阵。

你可能感兴趣的:(三维重建,opencv)