相机模型与相机标定

针孔相机模型

主要参考:OpenCV: Camera Calibration and 3D Reconstruction

四个坐标系

世界坐标系 P w ( m ) : ( x w , y w , z w ) P_w(m):(x_w,y_w,z_w) Pw(m):(xw,yw,zw)

世界坐标系可任意选择,为假想坐标系,在被指定后不变且唯一。

相机坐标系 P c ( m ) : ( x c , y c , z c ) P_c(m):(x_c,y_c,z_c) Pc(m):(xc,yc,zc)

相机坐标系原点在光心,x轴为相机平面的水平方向,y轴为相机平面的竖直方向,z轴指向相机观察方向,其随相机移动而变化,即为相对坐标系。

图像坐标系 P ( m m ) : ( x , y ) P(mm):(x,y) P(mm):(x,y)

图像坐标系原点位于透镜光轴与成像平面的交点,x轴与y轴分别平行于相机坐标系的x轴与y轴,是二维平面直角坐标系,单位为毫米,依托相机坐标系,也为相对坐标系。

像素坐标系 p ( p i x e l ) : ( u , v ) p(pixel):(u,v) p(pixel):(u,v)

像素坐标系为固定在图像上的以像素为单位的平面直角坐标系,原点位于图像左上角,x轴与y轴分别平行于图像坐标系的x轴与y轴,依托图像坐标系,也为相对坐标系。

在这里插入图片描述

坐标系变换

从世界坐标系到相机坐标系,为刚体变换(旋转+平移)
P c = T c w P w P_c = T_{cw}P_w Pc=TcwPw


[ x c y c z c 1 ] = [ R t 0 T 1 ] [ x w y w z w 1 ] \begin{bmatrix}x_c \\ y_c \\ z_c \\ 1\end{bmatrix} = \begin{bmatrix}R & t \\ 0^T & 1\end{bmatrix} \begin{bmatrix}x_w \\ y_w \\ z_w \\ 1\end{bmatrix} xcyczc1=[R0Tt1]xwywzw1

从相机坐标系到图像坐标系,会丢失一个自由度 z z z f f f为焦距。
z c f = x c x = y c y \frac{z_c}{f} = \frac{x_c}{x} = \frac{y_c}{y} fzc=xxc=yyc


[ x y 1 ] = 1 z c [ f 0 0 0 f 0 0 0 1 ] [ x c y c z c ] = 1 z c [ f 0 0 0 0 f 0 0 0 0 1 0 ] [ x c y c z c 1 ] \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} = \frac{1}{z_c} \begin{bmatrix}f & 0 & 0 \\ 0 & f & 0 \\ 0 & 0 & 1\end{bmatrix} \begin{bmatrix}x_c \\ y_c \\ z_c \end{bmatrix} = \frac{1}{z_c} \begin{bmatrix}f & 0 & 0 & 0\\ 0 & f & 0 & 0\\ 0 & 0 & 1 & 0\end{bmatrix} \begin{bmatrix}x_c \\ y_c \\ z_c \\ 1\end{bmatrix} xy1=zc1f000f0001xcyczc=zc1f000f0001000xcyczc1

从图像坐标系到像素坐标系,其中像素坐标系原点位于左上角,图像坐标系原点不一定位于中心

α = 1 d x \alpha=\frac{1}{dx} α=dx1 β = 1 d y \beta=\frac{1}{dy} β=dy1 d x dx dx d y dy dy分别表示sensor上每个点在图像坐标系横纵轴的物理尺寸
u = α x + c x v = β y + c y u = \alpha{x} + c_x \\ v = \beta{y} + c_y u=αx+cxv=βy+cy


[ u v 1 ] = [ α 0 c x 0 β c y 0 0 1 ] [ x y 1 ] \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} = \begin{bmatrix}\alpha & 0 & c_x \\ 0 & \beta & c_y \\ 0 & 0 & 1\end{bmatrix} \begin{bmatrix}x \\ y \\ 1 \end{bmatrix} uv1=α000β0cxcy1xy1

因此,世界坐标系到像素坐标系
p = [ u v 1 ] = 1 z c [ α 0 c x 0 β c y 0 0 1 ] [ f 0 0 0 0 f 0 0 0 0 1 0 ] [ R t 0 T 1 ] [ x w y w z w 1 ] = 1 z c K T P w p = \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} = \frac{1}{z_c} \begin{bmatrix}\alpha & 0 & c_x \\ 0 & \beta & c_y \\ 0 & 0 & 1\end{bmatrix} \begin{bmatrix}f & 0 & 0 & 0\\ 0 & f & 0 & 0\\ 0 & 0 & 1 & 0\end{bmatrix} \begin{bmatrix}R & t \\ 0^T & 1\end{bmatrix} \begin{bmatrix}x_w \\ y_w \\ z_w \\ 1\end{bmatrix}= \frac{1}{z_c}KTP_w p=uv1=zc1α000β0cxcy1f000f0001000[R0Tt1]xwywzw1=zc1KTPw

或者写成
p = [ u v 1 ] = 1 z c [ f x 0 c x 0 f y c y 0 0 1 ] [ r 11 r 12 r 13 t 1 r 21 r 22 r 23 t 2 r 31 r 32 r 33 t 3 ] [ x w y w z w 1 ] = 1 z c K T P w p = \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} = \frac{1}{z_c} \begin{bmatrix}f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1\end{bmatrix} \begin{bmatrix}r_{11} & r_{12} &r_{13} &t_1 \\ r_{21} & r_{22} &r_{23} &t_2 \\r_{31} & r_{32} &r_{33} &t_3\end{bmatrix} \begin{bmatrix}x_w \\ y_w \\ z_w \\ 1\end{bmatrix}= \frac{1}{z_c}KTP_w p=uv1=zc1fx000fy0cxcy1r11r21r31r12r22r32r13r23r33t1t2t3xwywzw1=zc1KTPw

真正的镜头通常会有一些畸变,主要是径向畸变,还有轻微的切向畸变
[ u v ] = [ f x x ′ + c x f y y ′ + c y ] \begin{bmatrix} u \\ v \end{bmatrix} = \begin{bmatrix}f_{x}x' +c_x\\ f_{y}y'+c_y \end{bmatrix} [uv]=[fxx+cxfyy+cy]


{ x ′ = x ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) + 2 p 1 x y + p 2 ( r 2 + 2 x 2 ) y ′ = y ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) + 2 p 2 x y + p 1 ( r 2 + 2 y 2 ) \begin{cases} \begin{aligned} x' &= x(1+k_1r^2+k_2r^4+k_3r^6)+2p_1xy+p_2(r^2+2x^2)\\ y' &= y(1+k_1r^2+k_2r^4+k_3r^6)+2p_2xy+p_1(r^2+2y^2) \end{aligned} \end{cases} {xy=x(1+k1r2+k2r4+k3r6)+2p1xy+p2(r2+2x2)=y(1+k1r2+k2r4+k3r6)+2p2xy+p1(r2+2y2)

其中, r 2 = x 2 + y 2 r^2=x^2+y^2 r2=x2+y2

这里的 ( x , y ) (x,y) (x,y)不同于上面的,而是 x = X c / Z c x=X_c/Z_c x=Xc/Zc y = Y c / Z c y=Y_c/Z_c y=Yc/Zc

相机标定示例程序

#include "opencv.hpp"
#include <iostream>
#include <fstream> 
#include <io.h>  
#include <string>  
#include <vector>

using namespace cv;
using namespace std;

void getFilesName(string& fileDirectory, string& fileType, vector<string>& filesPath);
void m_calibration(vector<string>& FilesName, Size board_size, Size square_size, Mat& cameraMatrix, Mat& distCoeffs, vector<Mat>& rvecsMat, vector<Mat>& tvecsMat);

int main()
{
    string fileDirectory = "D:/VS2019Projects/cameraCalibration/cameraCalibration/chessImage";
    string fileType = ".jpg";    //查找指定的文件类型
    vector<string> filesPath;    //存放文件路径名的容器

    getFilesName(fileDirectory, fileType, filesPath);              //寻找文件的路径

    Size boardSize = Size(9, 6);                                   // 标定板上每行、列的角点数 
    Size squareSize = Size(30, 30);                                // 实际测量得到的标定板上每个棋盘格的物理尺寸,单位mm

    Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));        // 摄像机内参数矩阵
    Mat distCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));          // 摄像机的5个畸变系数:k1,k2,p1,p2,k3
    vector<Mat> rVecsMat;                                          // 存放所有图像的旋转向量,每一副图像的旋转向量为一个mat
    vector<Mat> tVecsMat;                                          // 存放所有图像的平移向量,每一副图像的平移向量为一个mat

    m_calibration(filesPath, boardSize, squareSize, cameraMatrix, distCoeffs, rVecsMat, tVecsMat);

    return 0;
}

/*
@param fileDirectory 为文件夹目录
@param fileType 为需要查找的文件类型
@param filesPath 为存放文件名的容器
*/
void getFilesName(string& fileDirectory, string& fileType, vector<string>& filesPath)
{
    string buffer = fileDirectory + "\\*" + fileType;
    _finddata_t fileInfo;   //存放文件信息的结构体
    intptr_t hFile;
    hFile = _findfirst(buffer.c_str(), &fileInfo); //找第一个文件

    if (hFile == -1L) {
        //没找到指定类型的文件
        cout << "No " << fileType << " files in current directory!" << endl;
    }
    else {
        string fullFilePath;
        do {
            fullFilePath.clear();
            fullFilePath = fileDirectory + "\\" + fileInfo.name;
            filesPath.push_back(fullFilePath);

        } while (_findnext(hFile, &fileInfo) == 0);  //如果找到下个文件的名字成功的话就返回0,否则返回-1  
        _findclose(hFile);
    }
}

void m_calibration(vector<string>& filesPath, Size boardSize, Size squareSize, Mat& cameraMatrix, Mat& distCoeffs, vector<Mat>& rVecsMat, vector<Mat>& tVecsMat)
{
    ofstream fout("caliberation_left.txt");                       // 保存标定结果的文件 

    cout << "开始提取角点………………" << endl;
    int imageCount = 0;                                             // 图像数量 
    Size imageSize;                                                 // 图像的尺寸 

    vector<Point2f> imagePoints;                                    // 缓存每幅图像上检测到的角点
    vector<vector<Point2f>> imagePointsSeq;                         // 保存检测到的所有角点

    for (int i = 0; i < filesPath.size(); i++)
    {
        imageCount++;

        // 用于观察检验输出
        cout << "image_count = " << imageCount << endl;
        Mat imageInput = imread(filesPath[i]);
        if (imageCount == 1)  //读入第一张图片时获取图像宽高信息
        {
            imageSize.width = imageInput.cols;
            imageSize.height = imageInput.rows;
            cout << "image_size.width = " << imageSize.width << endl;
            cout << "image_size.height = " << imageSize.height << endl;
        }

        // 提取角点
        bool ok = findChessboardCorners(imageInput, boardSize, imagePoints, 
            CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE);
        //cout << "imagePoints.size = " << imagePoints.size() << endl;
        //for (int j = 0; j < imagePoints.size(); j++) {

        //    cout << "imagePoints: " << imagePoints[j] << endl;
        //}
        
        if (0 == ok)
        {
            cout << "第" << imageCount << "张照片提取角点失败,请删除后,重新标定!" << endl;
            imshow("失败照片", imageInput);
            waitKey(0);
        }
        else
        {
            Mat view_gray;
            cout << "imageInput.channels()=" << imageInput.channels() << endl;
            cvtColor(imageInput, view_gray, CV_RGB2GRAY);

            // 亚像素精确化  cv::Size(11, 11)不懂为什么取11*11
            cv::cornerSubPix(view_gray, imagePoints, cv::Size(11, 11), cv::Size(-1, -1), 
                cv::TermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 20, 0.01));

            imagePointsSeq.push_back(imagePoints);  //保存亚像素角点

            drawChessboardCorners(view_gray, boardSize, imagePoints, true);  //在图像上显示角点位置

            imshow("camera calibration", view_gray);
            waitKey(500);
        }
    }
    cout << "角点提取完成!!!" << endl;


    // 获取棋盘中角点的三维坐标信息
    Point3f realPoint;
    vector<Point3f> objectPoints;
    vector<vector<Point3f>> objectPointsSeq;
    for (int t = 0; t < imageCount; t++)
    {
        objectPoints.clear();
        for (int i = 0; i < boardSize.height; i++)
        {
            for (int j = 0; j < boardSize.width; j++)
            {              
                /* 假设标定板放在世界坐标系中z=0的平面上 */
                realPoint.x = i * squareSize.width;
                realPoint.y = j * squareSize.height;
                realPoint.z = 0;
                objectPoints.push_back(realPoint);
            }
        }
        objectPointsSeq.push_back(objectPoints);
    }


    // 运行标定函数
    double err_first = calibrateCamera(objectPointsSeq, imagePointsSeq, imageSize, 
        cameraMatrix, distCoeffs, rVecsMat, tVecsMat, CV_CALIB_FIX_K3);
    fout << "重投影误差1:" << err_first << "像素" << endl << endl;
    cout << "标定完成!!!" << endl;


    cout << "开始评价标定结果………………" << endl;
    double total_err = 0.0;            // 所有图像的平均误差的总和 
    double err = 0.0;                  // 每幅图像的平均误差
    double totalErr = 0.0;
    double totalPoints = 0.0;
    vector<Point2f> imagePointsPro;     // 保存重新计算得到的投影点

    for (int i = 0; i < imageCount; i++)
    {
        //通过得到的摄像机内外参数,对角点的空间三维坐标进行重新投影计算
        projectPoints(objectPointsSeq[i], rVecsMat[i], tVecsMat[i], cameraMatrix, distCoeffs, imagePointsPro);

        err = norm(Mat(imagePointsSeq[i]), Mat(imagePointsPro), NORM_L2);

        totalErr += err * err;
        totalPoints += objectPointsSeq[i].size();

        err /= objectPointsSeq[i].size();
        //fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
        total_err += err;
    }
    fout << "重投影误差2:" << sqrt(totalErr / totalPoints) << "像素" << endl << endl;
    fout << "重投影误差3:" << total_err / imageCount << "像素" << endl << endl;


    //保存定标结果    
    cout << "开始保存标定结果………………" << endl;
    Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */
    fout << "相机内参数矩阵:" << endl;
    fout << cameraMatrix << endl << endl;
    fout << "畸变系数:" << endl;
    fout << distCoeffs << endl << endl << endl;
    for (int i = 0; i < imageCount; i++)
    {
        fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
        fout << rVecsMat[i] << endl;

        /* 将旋转向量转换为相对应的旋转矩阵 */
        Rodrigues(rVecsMat[i], rotation_matrix);
        fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
        fout << rotation_matrix << endl;
        fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
        fout << tVecsMat[i] << endl << endl;
    }
    cout << "标定结果完成保存!!!" << endl;
    fout << endl;
}

棋盘格标定的相关函数

findChessboardCorners

findChessboardCorners函数原型

bool cv::findChessboardCorners(InputArray 	image,
    Size 	patternSize,
    OutputArray 	corners,
    int 	flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE
)
参数含义
image源棋盘视图。 它必须是8位灰度或彩色图像。
patternSize每个棋盘行和列的内部角点数(patternsize = cvSize(points_per_row,points_per_colum)= cvSize(列,行))
corners被检测到的角点的输出矩阵
flags各种操作标志

该函数试图确定输入图像是否是棋盘图案的视图,并找到内部棋盘角。 如果找到所有角点,则该函数将返回非零值,并且将其放置在一定顺序(行逐行,每行从左到右)。 否则,如果该功能未能找到所有的角或重新排序,则它将返回0。例如,常规棋盘具有8 x 8正方形和7 x 7的内部拐角,即黑色正方形相互接触的点。 检测到的坐标是近似的,于是为了更准确地确定其位置,可使用函数CornerSubpix

cornerSubPix

cornerSubPix函数原型

void cv::cornerSubPix(InputArray 	image,
    InputOutputArray 	corners,
    Size 	winSize,
    Size 	zeroZone,
    TermCriteria 	criteria
)	
参数含义
image输入单通道,8位或浮点图像。
corners输入角的初始坐标和用于输出的修正坐标
winSize搜索窗口的一半长度的一半。 例如,如果winsize = size(5,5),则使用a(5 ∗ 2+1)×(5 ∗ 2+1)= 11×11搜索窗口。
zeroZone搜索区中间的死区域大小的一半, 它有时用于避免自相关矩阵的可能奇异性。 (-1,-1)的值表示没有这样的大小。
criteria终止角点迭代过程的准则

该函数迭代以找到角点的亚像素精确位置

cv::TermCriteria类介绍

定义迭代算法终止标准的类。您可以默认情况下对其进行初始化,然后覆盖任何参数,或者使用构造函数的高级变体可以完全初始初始化结构。

构造函数

cv::TermCriteria::TermCriteria(int 	type,
    int 	maxCount,
    double 	epsilon
)	
参数含义
type终止标准的类型
maxCount要计算的最大迭代或元素数量
epsilon迭代算法停止的所需准确性或参数的变化

drawChessboardCorners

drawChessboardCorners函数原型

void cv::drawChessboardCorners(InputOutputArray 	image,
    Size 	patternSize,
    InputArray 	corners,
    bool 	patternWasFound
)
参数含义
image目标图像。 它必须是8位颜色图像。
patternSize每个棋盘行和列的内部角点数(patternsize = cv :: size(points_per_row,points_per_column))
corners检测到的角点的数组,即FindchessboardCorners的输出。
patternWasFound参数指示是否找到完整的板

该函数在图像上渲染检测到的棋盘角点

calibrateCamera

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)
)	

calibrateCamera函数原型二

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)
)
参数含义
objectPoints世界坐标系中的点,在新界面中,它是校准模式坐标空间中校准模式点向量的向量(例如std::vector<std::vector<cv::vec3f>>)。尽管这些点为3D,但它们都位于校准模式的XY坐标平面(因此在Z坐标中为0)
imagePoints图像像素坐标点,在新界面中,它是校准模式点投影的向量的向量(例如,std::vector<std:vector<cv::vec2f>>)。ImagePoints.Size()ObjectPoints.Size()必须相等,ImagePoints[i].size()ObjectPoints[i].size(),对于每个i,必须分别相等
imageSize图像的大小仅用于初始化固有的摄像机矩阵
cameraMatrix输入/输出3x3相机内参数矩阵
distCoeffs畸变系数的输入/输出向量(4, 5, 8, 12 or 14 个元素)
rvecs估计每个模式视图的旋转矢量的输出向量(例如std::vector<cv:mat>>
tvecs对每个模式视图估计的平移向量的输出向量
stdDeviationsIntrinsics估计内在参数的标准偏差的输出向量
stdDeviationsEntrinsics估计外在参数的标准偏差的输出向量
perViewErrors每个标定图片的重投影均方根误差的输出向量
flags标定函数所采用的模型
criteria迭代优化算法的终止标准

标定模型

flags含义
CALIB_USE_INTRINSIC_GUESScameraMatrix 包含进一步优化的 fx、fy、cx、cy 的有效初始值。 否则,最初将 (cx, cy) 设置为图像中心(使用 imageSize),并以最小二乘方式计算焦距。 请注意,如果内部参数已知,则无需仅使用此函数来估计外部参数。 请改用solvePnP。
CALIB_FIX_PRINCIPAL_POINT全局优化期间主点不变。 当 CALIB_USE_INTRINSIC_GUESS 也被设置时,它会停留在中心或指定的不同位置。
CALIB_FIX_ASPECT_RATIO这些函数仅将 fy 视为自由参数。 fx/fy 的比率与输入 cameraMatrix 中的比率相同。 当 CALIB_USE_INTRINSIC_GUESS 未设置时,将忽略 fx 和 fy 的实际输入值,仅计算并进一步使用它们的比率。
CALIB_ZERO_TANGENT_DIST切向畸变系数 (p1,p2) 设置为零并保持为零
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。

projectPoints

projectPoints函数原型

void cv::projectPoints(InputArray 	objectPoints,
    InputArray 	rvec,
    InputArray 	tvec,
    InputArray 	cameraMatrix,
    InputArray 	distCoeffs,
    OutputArray 	imagePoints,
    OutputArray 	jacobian = noArray(),
    double 	aspectRatio = 0
)
参数含义
objectPoints用 wrt 表示的对象点数组。 世界坐标系。 一个 3xN/Nx3 1 通道或 1xN/Nx1 3 通道(或 vector< Point3f >),其中 N 是视图中的点数。
rvec旋转矢量
tvec平移向量
cameraMatrix3x3相机内参数矩阵
distCoeffs畸变系数向量(4, 5, 8, 12 or 14 个元素)
imagePoints图像点的输出数组,1xN/Nx1 2 通道,或 vector< Point2f >
jacobian雅可比矩阵
aspectRatio可选的“固定纵横比”参数。 如果参数不为0,则函数假定纵横比(fx/fy)是固定的,并相应地调整雅可比矩阵。

该函数在给定内部和外部相机参数的情况下计算 3D 点到图像平面的 2D 投影。 可选地,该函数计算图像点坐标的偏导数(作为所有输入参数的函数)关于特定参数、内在和/或外在的雅可比矩阵。 Jacobians 用于 calibrateCamera、solvePnP 和 stereoCalibrate 的全局优化。 给定当前的内在和外在参数,该函数本身也可用于计算重投影误差。

norm

norm函数原型

double cv::norm(InputArray 	src1,
    InputArray 	src2,
    int 	normType = NORM_L2,
    InputArray 	mask = noArray()
)
参数含义
src1第一个输入数组
src2与 src1 大小和类型相同的第二个输入数组
normTypenorm类型
mask可选操作掩码; 它必须具有与 src1 和 CV_8UC1 类型相同的大小。

enum cv::NormTypes常用枚举值

  • NORM_INF n o r m = ∥ s r c 1 − s r c 2 ∥ L ∞ = m a x I ∣ s r c 1 ( I ) − s r c 2 ( I ) ∣ norm = \|src1-src2\|_{L_\infty}=max_{I}|src1(I)-src2(I)| norm=src1src2L=maxIsrc1(I)src2(I)
  • NORM_L1 n o r m = ∥ s r c 1 − s r c 2 ∥ L 1 = Σ I ∣ s r c 1 ( I ) − s r c 2 ( I ) ∣ norm = \|src1-src2\|_{L_1}=\Sigma_{I}|src1(I)-src2(I)| norm=src1src2L1=ΣIsrc1(I)src2(I)
  • NORM_L2 n o r m = ∥ s r c 1 − s r c 2 ∥ L 2 = Σ I ( s r c 1 ( I ) − s r c 2 ( I ) ) 2 norm = \|src1-src2\|_{L_2}=\sqrt{\Sigma_{I}(src1(I)-src2(I))^2} norm=src1src2L2=ΣI(src1(I)src2(I))2

此版本的 cv::norm 计算数组 src1 和 src2 的绝对差范数或相对差范数。 使用 NormTypes 指定要计算的范数类型。

Rodrigues

Rodrigues函数原型

void cv::Rodrigues(InputArray 	src,
    OutputArray 	dst,
    OutputArray 	jacobian = noArray()
)
参数含义
src输入旋转向量(3x1 和 1x3)或旋转矩阵(3x3)
dst输出旋转矩阵 (3x3) 或旋转向量 (3x1 或 1x3)
jacobian可选输出雅可比矩阵,3x9 或 9x3,它是输出数组分量相对于输入数组分量的偏导数矩阵

将旋转矩阵转换为旋转向量,反之亦然。

待标定图片百度链接:

链接:https://pan.baidu.com/s/1kdwKtE8CaHHLr4RtRKn9lA 
提取码:ms39 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值