张正友标定相机内参

  1. 拍摄棋盘图像,并按照形式如下命名,放置在工程的images目录下

python标定相机内参标定 opencv内参标定_角点

  1. 编写代码,首先读取图像,然后提取棋盘角点,然后利用opencv计算重投影误差做标定,最后做相机内参的评价,代码注释完整,简单易懂
//
// Created by gj on 2021/11/15.
//

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>

using namespace cv;
using namespace std;

int main()
{
    ifstream fin("../calibdata.txt"); /* 标定所用图像文件的路径 */
    ofstream fout("calibration_result.txt");  /* 保存标定结果的文件 */
    //读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
    cout<<".........开始提取角点.........\n";
    int image_count=0;  /* 图像数量 */
    Size image_size;  /* 图像的尺寸 */
    Size board_size = Size(8,6);    /* 标定板上每行、列的角点数 */
    vector<Point2f> image_points_buf;  /* 缓存每幅图像上检测到的角点 */
    vector<vector<Point2f>> image_points_seq; /* 保存检测到的所有角点 */
    string filename;
    int count= -1 ;//用于存储角点个数。
    while (getline(fin,filename))
    {
        image_count++;

        string input_path="../images/"+to_string(image_count-1)+".png";
        Mat imageInput=imread(input_path);
        if (imageInput.empty()) {
            cout << "未找到拍摄的棋盘图片";
            return 0;
        }
        /* 输出检验*/
        cout << "input image" << image_count << ":  " << filename << endl;
        if (image_count == 1)  //读入第一张图片时获取图像宽高信息
        {
            image_size.width = imageInput.cols;
            image_size.height =imageInput.rows;
            cout<<"image_size.width = "<<image_size.width<<endl;
            cout<<"image_size.height = "<<image_size.height<<endl;
        }

        /* 提取角点 */
        if (0 == findChessboardCorners(imageInput,board_size,image_points_buf))
        {
            cout<<"can not find chessboard corners!\n"; //找不到角点
            exit(1);
        }
        else
        {
            Mat view_gray;
            cvtColor(imageInput,view_gray,CV_RGB2GRAY);
            /* 亚像素精确化 */
            find4QuadCornerSubpix(view_gray,image_points_buf,Size(5,5)); //对粗提取的角点进行精确化
            //cornerSubPix(view_gray,image_points_buf,Size(5,5),Size(-1,-1),TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));
            image_points_seq.push_back(image_points_buf);  //保存亚像素角点
            /* 在图像上显示角点位置 */
            drawChessboardCorners(view_gray,board_size,image_points_buf,false); //用于在图片中标记角点
            imshow("Camera Calibration",view_gray);//显示图片
            waitKey(500);//暂停0.5S
        }
        int CornerNum=board_size.width*board_size.height;  //每张图片上总的角点数
        if (1 == image_count)// 48 是每幅图片的角点个数。此判断语句是为了输出 图片号,便于控制台观看
        {
            cout << "只展示第一张图片的数据:\n";
            cout<<" 第 1 张图片角点的数据 : ";

            //输出所有的角点
            for (int j = 0; j < CornerNum; ++j) {
                cout<<" x:"<<image_points_seq[0][j].x;
                cout<<" y:"<<image_points_seq[0][j].y;
            }
        }
    }
    int total = image_points_seq.size();
    cout<<"图片总数 = "<<total<<endl;
    cout<<"角点提取完成!\n";

    //以下是摄像机标定
    cout<<"..........开始标定........."<<endl;
    /*棋盘三维信息*/
    Size square_size = Size(10.8,10.8);  /* 实际测量得到的标定板上每个棋盘格的大小 */
    vector<vector<Point3f>> object_points; /* 保存标定板上角点的三维坐标 */
    /*内外参数*/
    Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0)); /* 摄像机内参数矩阵 */
    vector<int> point_counts;  // 每幅图像中角点的数量
    Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0)); /* 摄像机的5个畸变系数:k1,k2,p1,p2,k3 */
    vector<Mat> tvecsMat;  /* 每幅图像的旋转向量 */
    vector<Mat> rvecsMat; /* 每幅图像的平移向量 */
    /* 初始化标定板上角点的三维坐标 */
    int i,j,t;
    for (t=0;t<image_count;t++)
    {
        vector<Point3f> tempPointSet;
        for (i=0;i<board_size.height;i++)
        {
            for (j=0;j<board_size.width;j++)
            {
                Point3f realPoint;
                /* 假设标定板放在世界坐标系中z=0的平面上 */
                realPoint.x = i*square_size.width;
                realPoint.y = j*square_size.height;
                realPoint.z = 0;
                tempPointSet.push_back(realPoint);
            }
        }
        object_points.push_back(tempPointSet);
    }
    /* 初始化每幅图像中的角点数量,假定每幅图像中都可以看到完整的标定板 */
    for (i=0;i<image_count;i++)
    {
        point_counts.push_back(board_size.width*board_size.height);
    }
    /* 开始标定 */
    calibrateCamera(object_points,image_points_seq,image_size,cameraMatrix,distCoeffs,rvecsMat,tvecsMat,0);
    cout<<"标定完成!\n";
    //对标定结果进行评价
    cout<<".........开始评价标定结果.........\n";
    double total_err = 0.0; /* 所有图像的平均误差的总和 */
    double err = 0.0; /* 每幅图像的平均误差 */
    vector<Point2f> image_points2; /* 保存重新计算得到的投影点 */
    cout<<"\t每幅图像的标定误差:\n";
    fout<<"每幅图像的标定误差:\n";
    for (i=0;i<image_count;i++)
    {
        vector<Point3f> tempPointSet=object_points[i];
        /* 通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点 */
        projectPoints(tempPointSet,rvecsMat[i],tvecsMat[i],cameraMatrix,distCoeffs,image_points2);
        /* 计算新的投影点和旧的投影点之间的误差*/
        vector<Point2f> tempImagePoint = image_points_seq[i];
        Mat tempImagePointMat = Mat(1,tempImagePoint.size(),CV_32FC2);
        Mat image_points2Mat = Mat(1,image_points2.size(), CV_32FC2);
        for (int j = 0 ; j < tempImagePoint.size(); j++)
        {
            image_points2Mat.at<Vec2f>(0,j) = Vec2f(image_points2[j].x, image_points2[j].y);
            tempImagePointMat.at<Vec2f>(0,j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);
        }
        err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
        total_err += err/=  point_counts[i];
        std::cout<<"第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<endl;
        fout<<"第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<endl;
    }
    std::cout<<"总体平均误差:"<<total_err/image_count<<"像素"<<endl;
    fout<<"总体平均误差:"<<total_err/image_count<<"像素"<<endl<<endl;
    std::cout<<"评价完成!"<<endl;
    //保存定标结果
    std::cout<<"开始保存定标结果………………"<<endl;
    Mat rotation_matrix = Mat(3,3,CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */
    fout<<"相机内参数矩阵:"<<endl;
    fout<<cameraMatrix<<endl<<endl;
    fout<<"畸变系数:\n";
    fout<<distCoeffs<<endl<<endl<<endl;
    for (int i=0; i<image_count; i++)
    {
        fout<<"第"<<i+1<<"幅图像的旋转向量:"<<endl;
        fout<<tvecsMat[i]<<endl;
        /* 将旋转向量转换为相对应的旋转矩阵 */
        Rodrigues(tvecsMat[i],rotation_matrix);
        fout<<"第"<<i+1<<"幅图像的旋转矩阵:"<<endl;
        fout<<rotation_matrix<<endl;
        fout<<"第"<<i+1<<"幅图像的平移向量:"<<endl;
        fout<<rvecsMat[i]<<endl<<endl;
    }
    std::cout<<"完成保存"<<endl;
    fout<<endl;
    return 0;
}
  1. 因为我是在clion中编译的,最后的结果在cmake-build-debug目录中的calibration_result.txt中
每幅图像的标定误差:
第1幅图像的平均误差:0.0611951像素
第2幅图像的平均误差:0.102013像素
第3幅图像的平均误差:0.0923479像素
第4幅图像的平均误差:0.0711323像素
第5幅图像的平均误差:0.0456678像素
第6幅图像的平均误差:0.114321像素
第7幅图像的平均误差:0.103894像素
第8幅图像的平均误差:0.0934296像素
第9幅图像的平均误差:0.108852像素
第10幅图像的平均误差:0.109755像素
第11幅图像的平均误差:0.141707像素
第12幅图像的平均误差:0.0613077像素
第13幅图像的平均误差:0.246986像素
第14幅图像的平均误差:0.110797像素
第15幅图像的平均误差:0.0961908像素
总体平均误差:0.103973像素

相机内参数矩阵:
[379.3643974682103, 0, 311.4027147649293;
 0, 378.2406004051696, 237.2316005121863;
 0, 0, 1]

畸变系数:
[-0.1632403355249804, 0.5007861402302362, -0.004126230171804792, -0.005271513365273738, -0.6580069027097243]


第1幅图像的旋转向量:
[-27.53007980274755;
 -11.79933419715619;
 102.2026862178985]
第1幅图像的旋转矩阵:
[0.9546925136147651, 0.2967753848688849, 0.02205845379546779;
 -0.2939944556310656, 0.9520442467079487, -0.08472905268258321;
 -0.04614612124669788, 0.07440512916607167, 0.9961598326813149]
第1幅图像的平移向量:
[2.20176132512684;
 2.185533601019431;
 -0.0963506995960441]

第2幅图像的旋转向量:
[-37.31630217955718;
 -30.08048831398644;
 99.09048755986471]
第2幅图像的旋转矩阵:
[-0.7639699279363039, 0.2907745627722495, -0.5760209222359947;
 0.07850693611841375, -0.8441877142173231, -0.5302676344505955;
 -0.6404581252434056, -0.4503301642230267, 0.6221062071709004]
第2幅图像的平移向量:
[1.832827675754982;
 1.758313404587785;
 -0.6647769097344208]

第3幅图像的旋转向量:
[-36.59204564266251;
 -33.17295204605372;
 95.10235209253118]
第3幅图像的旋转矩阵:
[0.9468298512063428, -0.2968742834814561, -0.1240116634512532;
 0.30959820026062, 0.9455796826020066, 0.1001399932378333;
 0.08753392062486325, -0.1332093227130156, 0.9872148140513187]
第3幅图像的平移向量:
[1.987801195530061;
 1.93780404642594;
 -0.46776413483636]

第4幅图像的旋转向量:
[-38.40529981129137;
 -29.43804839128432;
 81.94361231189357]
第4幅图像的旋转矩阵:
[0.6720630918922319, -0.6345595428661064, -0.3816613512969469;
 0.7323673845422911, 0.6457476828694688, 0.2159813513417207;
 0.1094039056658276, -0.4246694204040008, 0.8987138970767019]
第4幅图像的平移向量:
[2.240121074835526;
 2.128518190969042;
 -0.09890788625265373]

第5幅图像的旋转向量:
[-38.13055262423675;
 -28.49177115281911;
 84.77698630745486]
第5幅图像的旋转矩阵:
[-0.6810868933534013, 0.08633638922628201, -0.7270946785650274;
 0.3703114812451084, -0.8160455681081916, -0.4437781400982169;
 -0.6316565922716759, -0.5715029822024963, 0.5238265846378815]
第5幅图像的平移向量:
[-2.183850592874764;
 -2.092247996793978;
 -0.195439058766755]

第6幅图像的旋转向量:
[-38.3092789370934;
 -22.6186892240845;
 89.29163845796771]
第6幅图像的旋转矩阵:
[0.7593677430386671, 0.6478092947935352, 0.06085842925563847;
 -0.5986592648771036, 0.7322546951334563, -0.3246692871705221;
 -0.2548876525239443, 0.2101099213128965, 0.9438676313746126]
第6幅图像的平移向量:
[-1.992603788307841;
 -1.921067351580686;
 -0.4678212251747607]

第7幅图像的旋转向量:
[-42.29392266662697;
 -29.53875019445829;
 103.0943279368649]
第7幅图像的旋转矩阵:
[-0.3633334773670537, -0.583332413782476, -0.7264379390251272;
 0.8795203713050701, -0.4719449445351589, -0.06092524753414802;
 -0.3072990411370593, -0.6610531479075004, 0.6845261389880064]
第7幅图像的平移向量:
[-2.038107857398446;
 -1.910960564126662;
 0.4871780355598174]

第8幅图像的旋转向量:
[-19.8548154590127;
 -33.28781090802723;
 124.456363809498]
第8幅图像的旋转矩阵:
[-0.0002036794387580074, 0.9943251990671246, 0.1063830673312706;
 -0.9146674964994629, 0.04281554453553882, -0.4019330789988934;
 -0.4042070377443862, -0.0973869993697758, 0.9094682198909757]
第8幅图像的平移向量:
[-1.87951674111304;
 -1.88096702117784;
 0.7453835582518447]

第9幅图像的旋转向量:
[-43.66216451422579;
 -22.85747031718025;
 115.6451050232866]
第9幅图像的旋转矩阵:
[0.9991160660398525, -0.04117418748635484, -0.008471886796192188;
 0.04130115291679647, 0.9990280355212062, 0.01540126651878901;
 0.007829517787985971, -0.01573755150834711, 0.9998455021270685]
第9幅图像的平移向量:
[-1.93167570682439;
 -1.693608329039564;
 0.3084130144264655]

第10幅图像的旋转向量:
[-22.50034331453363;
 -32.89586926067927;
 126.4389142091563]
第10幅图像的旋转矩阵:
[0.8166306652416266, -0.5497773165310738, -0.1756680358372285;
 0.5656803779109127, 0.8228171901763742, 0.05456722090067771;
 0.114542859374058, -0.1439332268037784, 0.9829359895681238]
第10幅图像的平移向量:
[-1.832165042876404;
 -2.088924412648336;
 1.134371347296932]

第11幅图像的旋转向量:
[-20.78997605305722;
 -25.31394777448223;
 72.18217000773689]
第11幅图像的旋转矩阵:
[-0.6267640275124919, 0.7517882051584726, -0.2048935050237624;
 -0.459148161415432, -0.5687747551791589, -0.6824062160764044;
 -0.629563197530755, -0.3336311922699829, 0.7016697284758411]
第11幅图像的平移向量:
[1.847473223172457;
 1.72738886961609;
 0.6585688875521605]

第12幅图像的旋转向量:
[-32.80393536580875;
 -28.52194351479875;
 73.8405276891212]
第12幅图像的旋转矩阵:
[-0.4085588026967788, 0.8648679303152287, -0.2916901915581442;
 -0.4442140853656964, -0.4675897050082407, -0.7642209851430566;
 -0.7973415523486105, -0.1826563190326541, 0.5752244066586089]
第12幅图像的平移向量:
[1.904208503215055;
 1.768778728703117;
 0.3966278248943234]

第13幅图像的旋转向量:
[-14.5997794388444;
 -21.04996827256533;
 60.98800816393639]
第13幅图像的旋转矩阵:
[-0.887826650444868, 0.301099981569611, -0.3479980457684012;
 -0.02234594011432139, -0.7835415349763792, -0.6209374541185824;
 -0.4596351789411396, -0.5435084765352234, 0.702377418639087]
第13幅图像的平移向量:
[1.86204888781338;
 2.053921855673591;
 0.9987560523683087]

第14幅图像的旋转向量:
[-22.1954903529919;
 -26.83286753787837;
 68.69086212649877]
第14幅图像的旋转矩阵:
[0.04230107762330343, -0.7861726872253972, -0.6165574788231061;
 0.9959298006083485, 0.08233928640779563, -0.03666161717750999;
 0.079589264930156, -0.6124971410338604, 0.7864558481779028]
第14幅图像的平移向量:
[1.782981714578705;
 1.331350426884584;
 0.4203645050400237]

第15幅图像的旋转向量:
[-30.83187103185273;
 -28.91653360678463;
 73.94896222158316]
第15幅图像的旋转矩阵:
[-0.6838981874850625, 0.5395453298402869, -0.491094803680697;
 -0.06329710480155293, -0.714463502186754, -0.6968036886862606;
 -0.7268264893895844, -0.4454579004693643, 0.5227719514578399]
第15幅图像的平移向量:
[1.855010045356094;
 1.592445843852865;
 0.1319879765401926]