OpenCV相机标定

发布时间 2023-08-19 20:23:49作者: Champrin

OpenCV相机标定

相机内参矩阵cameraMatrix

\[cameraMatrix = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \]

相机畸变系数distCoeffs

畸变系数:径向畸变\((k_1,k_2,k_3)\), 切向畸变\((p_1,p_2)\)

\[distCoeffs = \begin{pmatrix} k_1 & k_2 & p_1 & p_2 & k_3 \end{pmatrix} \]

findChessboardCorners

棋盘格角点检测

#include <opencv2/calib3d.hpp>

bool cv::findChessboardCorners(
    InputArray image,
    Size patternSize,
    OutputArray corners,
    int flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE 
)	
Python:
retval, corners	= cv.findChessboardCorners(image, patternSize[, corners[, flags]])
  • image:输入 棋盘格图像,必须是8位灰度或彩色图像(cv::Mat)
    patternSize:输入 棋盘图内角点的行列数(注意:不是棋盘格的行列数,如棋盘格的行列数分别为4、8,而内部角点的行列数分别是3、7,因此这里应该指定为cv::Size(3, 7))(cv::Size)
  • corners:输出 检测到的棋盘格角点(std::vector<cv::Point2f>)
  • flags:输入 用于指定在检测棋盘格角点的过程中所应用的一种或多种过滤方法(int):
    • cv::CALIB_CB_ADAPTIVE_THRESH:使用自适应阈值将图像转化成二值图像
    • cv::CALIB_CB_NORMALIZE_IMAGE:归一化图像灰度系数(用直方图均衡化或者自适应阈值)
    • cv::CALIB_CB_FILTER_QUADS:在轮廓提取阶段,使用附加条件排除错误的假设
    • cv::CALIB_CV_FAST_CHECK:快速检测

drawChessboardCorners

棋盘格角点的绘制

#include <opencv2/calib3d.hpp>

void cv::drawChessboardCorners(
    InputOutputArray image,
    Size patternSize,
    InputArray corners,
    bool patternWasFound 
)		
Python:
image = cv.drawChessboardCorners(image, patternSize, corners, patternWasFound)
  • image:输入 棋盘格图像,必须是8位灰度或彩色图像(cv::Mat)
  • patternSize:输入 棋盘图内角点的行列数(cv::Size)
  • corners:输入 findChessboardCorners检测到的角点(std::vector<cv::Point2f>)
  • patternWasFound:输入 标志位,用来指示定义的棋盘内角点是否被完整的探测到,true表示别完整的探测到,函数会用直线依次连接所有的内角点,作为一个整体,false表示有未被探测到的内角点,这时候函数会以(红色)圆圈标记处检测到的内角点;(bool)

cornerSubPix

亚像素检测

#include <opencv2/imgproc.hpp>

void cv::cornerSubPix(
    InputArray image,
    InputOutputArray corners,
    Size winSize,
    Size zeroZone,
    TermCriteria criteria 
)		
Python:
corners = cv.cornerSubPix(image, corners, winSize, zeroZone, criteria)
  • image:输入 8位或浮点型单通道图像(cv::Mat)
  • corners:输入输出 输入角点的初始坐标,输出更加精确的点(std::vector<cv::Point2f>)
  • winSize:输入 大小为搜索窗口的一半,如果winSize=cv::Size(5,5),则搜索窗口为11*11(cv::Size)
  • zeroZone:输入 死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。它是用来避免自相关矩阵出现某些可能的奇异性。当值为(-1,-1)时表示没有死区(cv::Size)
  • criteria:输入 求角点的迭代过程的终止条件,可以为迭代次数和角点精度两者的组合(cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 30, 0.1))

经过重投影projectPointscornerSubPixfind4QuadCornerSubpix效果对比,find4QuadCornerSubpix进行亚像素精确化的重投影结果不如cornerSubPix
参考文章

calibrateCamera

求解相机内参和外参

#include <opencv2/calib3d.hpp>

double cv::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) 
)	
Python:
retval, cameraMatrix, distCoeffs, rvecs, tvecs = cv.calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs[, rvecs[, tvecs[, flags[, criteria]]]])
  • objectPoints:输入 世界坐标系中的三维点集。在使用时,应该是有多张图片同时进行标定,即应该输入一个三维坐标点的向量的向量(std::vector<std::vector<cv::Point3f>>)。测量棋盘上单个黑白矩阵的实际大小,以初始化每一个内角点的世界坐标
  • imagePoints:输入 每一个3D内角点对应的图像坐标2D点(std::vector<std::vector<cv::Point2f>>)
  • imageSize:输入 图像的像素尺寸大小,在计算相机的内参和畸变矩阵时需要使用到该参数(cv::Size)
  • cameraMatrix:输出 相机内参矩阵(cv::Mat)
  • distCoeffs:输出 相机畸变系数矩阵(cv::Mat)
  • rvecs:输出 旋转向量(std::vector<cv::Vec3d>)
  • tvecs:输出 平移向量(std::vector<cv::Vec3d>)
  • flags:输入 标定时所采用的算法(int),有如下几个参数:
    • CV_CALIB_USE_INTRINSIC_GUESS:使用该参数时,在cameraMatrix矩阵中应该有fx,fy,u0,v0的估计值。否则的话,将初始化(u0,v0)图像的中心点,使用最小二乘估算出fx,fy。
    • 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。
  • criteria:输入 可选,最优迭代终止条件设定。

在使用该函数进行标定运算之前,需要对棋盘上每一个内角点的空间坐标系的位置坐标进行初始化,标定的结果是生成相机的内参矩阵cameraMatrix、相机的5个畸变系数distCoeffs,另外每张图像都会生成属于自己的平移向量和旋转向量。

projectPoints

将世界坐标系中的3D坐标投影到像素坐标系中的2D坐标
可用于计算标定的误差

#include <opencv2/calib3d.hpp>

void cv::projectPoints(
    InputArray objectPoints,
    InputArray rvec,
    InputArray tvec,
    InputArray cameraMatrix,
    InputArray distCoeffs,
    OutputArray imagePoints,
    OutputArray jacobian = noArray(),
    double aspectRatio = 0 
)		
Python:
imagePoints, jacobian = cv.projectPoints(objectPoints, rvec, tvec, cameraMatrix, distCoeffs[, imagePoints[, jacobian[, aspectRatio]]])
  • objectPoints:世界坐标系中的3D坐标(std::vector<cv::Point3f>)
  • rvec:世界坐标系到相机坐标系的旋转向量(cv::Vec3d)
  • tvec:世界坐标系到相机坐标系的平移向量(cv::Vec3d)
  • cameraMatrix:相机内参矩阵(cv::Mat)
  • distCoeffs:相机畸变系数矩阵(cv::Mat)
  • imagePoints:3D坐标点在像素坐标系中估计的2D坐标(std::vectorcv::Point2f)
  • jacobian:可选输出的雅可比矩阵
  • aspectRatio:是否固定“宽高比”参数标志

initUndistortRectifyMap

计算畸变参数

#include <opencv2/calib3d.hpp>
void cv::initUndistortRectifyMap(
    InputArray cameraMatrix,
    InputArray distCoeffs,
    InputArray R,
    InputArray newCameraMatrix,
    Size size,
    int m1type,
    OutputArray map1,
    OutputArray map2 
)		
Python:
map1, map2 = cv.initUndistortRectifyMap(cameraMatrix, distCoeffs, R, newCameraMatrix, size, m1type[, map1[, map2]])
  • cameraMatrix:输入 相机内参矩阵(cv::Mat)
  • distCoeffs:输入 相机畸变系数矩阵(cv::Mat)
  • R:输入 畸变矫正矩阵,在客观空间中的转换对象(cv::Mat::eye(cv::Size(3, 3), CV_32FC1))
  • newCameraMatrix:输入 新的3*3的浮点型矩矩阵(cv::Mat)
  • size:输入 失真图像的大小(cv::Size)
  • m1type:输入 第一个输出的map(CV_32FC1/CV_16SC2)
  • map1:输出 x映射函数(cv::Mat)
  • map2:输出 y映射函数(cv::Mat)