• 相机标定问题-实践操作流程


    接上一篇文章讲解的相机标定的基本概念,这篇文章主要阐述一下如何使用Matlab或者Opencv等软件得的Camera内参之后,如何保存调用内参完成对应Camera的标定流程。

    一、Matlab标定鱼眼镜头实践

    1. 这里我使用的Camera是Jetson Nano专用的鱼眼摄像机,具体参数如下所示:

    我使用的畸变较大的鱼眼镜头。

    由于我采用的是红外夜视的Camera,结果在光线稍微不好的时候就会出现图片偏红色的情况(解决方案:微雪Camera-wiki

        如果大家没有必要的夜视应用场景,建议不要使用红外夜视的摄像头,如果在后期处理的过程中还要对畸变图像矫正,建议就不要使用广角鱼眼摄像头了,因为矫正之后的视野区域也会有所减少,这一点可以在后面矫正的程序中看到(在畸变矫正的过程中,也需要消耗部分CPU资源,这样对于嵌入式板卡来说也许就不划算了)

    2. 基于JetsonNano板卡,CSI摄像头的标定图采集Demo程序如下:

     1 import cv2
     2 import sys
     3 import glob
     4 import time
     5 import threading
     6 import numpy as np
     7 
     8 if len(sys.argv) == 1:
     9     print 'Please Choose the CSI-Camera id for image sample.Try again!'
    10     exit(0)
    11 
    12 Camera_ID = int(sys.argv[1])
    13 
    14 def gstreamer_pipeline(
    15     csi_camera_id = 0,
    16     capture_width=1280,
    17     capture_height=720,
    18     display_width=1280,
    19     display_height=720,
    20     framerate=60,
    21     flip_method=0,
    22 ):
    23     return (
    24         "nvarguscamerasrc sensor_id=%d ! "
    25         "video/x-raw(memory:NVMM), "
    26         "width=(int)%d, height=(int)%d, "
    27         "format=(string)NV12, framerate=(fraction)%d/1 ! "
    28         "nvvidconv flip-method=%d ! "
    29         "video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! "
    30         "videoconvert ! "
    31         "video/x-raw, format=(string)BGR ! appsink"
    32         % (
    33             csi_camera_id,
    34             capture_width,
    35             capture_height,
    36             framerate,
    37             flip_method,
    38             display_width,
    39             display_height,
    40         )
    41     )
    42 
    43 print 'Starting Capture...'
    44 csi_pipeline_str = gstreamer_pipeline(csi_camera_id=Camera_ID,flip_method=0)
    45 print csi_pipeline_str
    46 cap = cv2.VideoCapture(csi_pipeline_str, cv2.CAP_GSTREAMER)
    47 count = 0
    48 while not cap.isOpened():
    49     time.sleep(0.5)
    50     print('Camera is Initialize...')
    51     count += 1
    52     if count == 10:
    53         print 'CSICamera Initial Failed!'
    54         cap.release()
    55         exit(0)
    56 
    57 ret, frame = cap.read()
    58 
    59 Key_val = 0
    60 
    61 def Keybo_Moni():
    62     count = 0
    63     while True:
    64         global Key_val, frame, process_flag, cap
    65         if Key_val == ord('r'):
    66             Key_val= 0
    67             cv2.imwrite('CSICamera' + str(Camera_ID) + '-' + str(count) + '.jpg', frame)
    68             count += 1
    69             print('Get new pic %d' % count)
    70         if Key_val == ord('q'):
    71             break
    72 
    73 try:
    74     Keybo_Moni_Thread = threading.Thread(target=Keybo_Moni, name='Keyboard-Thread')
    75     Keybo_Moni_Thread.start()
    76 except:
    77     print('Error:uqnable to start the thread!')
    78 
    79 while True:
    80     ret, frame = cap.read()
    81     cv2.imshow('Video_Show', frame)
    82     Key_val = cv2.waitKey(1)
    83     if Key_val == ord('q'):
    84         cv2.destroyAllWindows()
    85         cap.release()
    86         print('Pic Sample Finished!')
    87         break
    88 
    89 print('Finished CalibrateCamera Image Sample...')

    程序中涉及到了Gstreamer等多媒体pipeline框架内容,请参考这里,Python脚本的使用方法:

    python CSICAM_Calibraton_Sample.py 1 # 采集CSI-Camera1摄像头的内容
    python CSICAM_Calibraton_Sample.py 0 # 采集CSI-Camera0摄像头的内容

    如果你使用的其他的USB Camera,可以参考使用如下程序:

     1 import cv2
     2 import glob
     3 import time
     4 import threading
     5 import numpy as np
     6 
     7 print('Starting Capture...')
     8 cap = cv2.VideoCapture(2)
     9 while not cap.isOpened():
    10         time.sleep(100)
    11         print('Camera is Initialize...')
    12 
    13 width = int(cap.get(3))
    14 height = int(cap.get(4))
    15 
    16 frame = np.zeros((width,height,3),dtype=np.uint8)
    17 ret, frame = cap.read()
    18 
    19 Key_val = 0
    20 
    21 def Keybo_Moni():
    22         count = 0
    23         while True:
    24                 global Key_val, frame, process_flag, cap
    25                 if Key_val == ord('r'):
    26                         Key_val= 0
    27                         cv2.imwrite('ResPic' + str(count) + '.jpg', frame)
    28                         count += 1
    29                         print('Get new pic %d' % count)
    30                 if Key_val == ord('q'):
    31                         Key_val = 'q'
    32                         break;
    33 
    34 try:
    35         Keybo_Moni_Thread = threading.Thread(target=Keybo_Moni, name='Keyboard-Thread')
    36         Keybo_Moni_Thread.start()
    37 except:
    38         print('Error:uqnable to start the thread!')
    39 
    40 while True:
    41         ret, frame = cap.read()
    42         cv2.imshow('Video_Show', frame)
    43         Key_val = cv2.waitKey(1)
    44         if Key_val == ord('q'):
    45                 cv2.destroyAllWindows()
    46                 cap.release()
    47                 print('Pic Sample Finished!')
    48                 break
    49 
    50 print('Finished CalibrateCamera Image Sample...')
    View Code

    3. 接下来使用采集图像进行Matlab进行标定

    能够看到,矫正之后的图像还是粉粉的...(问题待解决!)

    具体matlab进行相机标定流程请参看我前一篇内容,下面是矫正前后的效果图:

    从两图对比中,我们可以看出,section_a区域的部分以及Section_b的部分都发生了明显的变化,原来应该显示的内容由于图像在矫正的过程中根据内插法消失了,那么我们如何获取Camera的内参呢?

    对于Matlab之前的版本直接参看上一篇教程,由于我使用的是2019b版本的Matlab,使用操作方式有所不同,在这里说明如下:

    a) 点击工具栏位置的 Export Camera Parameters,这样会输出相机的基本内参以及外参到Matlab的工作空间中:

    这样就会将相机参数保存在工作空间,名称为cameraParams。

    在工作区中,可以找到cameraParams变量,单机右键,打开所选内容,如下所示:

    将图中颜色标出的参数保存即可。

    同时这里我们有必要将工作空间中cameraParams mat变量保存下来为下一次矫正的过程使用提供相机的内参数据,单机右键点击另存为,将相机的参数数据保存即可(参考.mat数据保存使用)。

    b) 点击工具栏位置的 Export Camera Parameters下拉箭头,选择Generate Matalab script:

    % Auto-generated by cameraCalibrator app on 15-Apr-2020
    %-------------------------------------------------------
    
    
    % Define images to process
    imageFileNames = {'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-0.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-3.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-4.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-5.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-7.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-8.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-9.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-10.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-11.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-12.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-13.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-14.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-15.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-16.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-17.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-18.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-19.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-20.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-21.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-22.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-23.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-24.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-25.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-26.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-27.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-28.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-29.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-30.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-31.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-32.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-33.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-34.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-35.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-36.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-37.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-40.jpg',...
        'C:UsersAdministratorDesktopImageDataCAM0CSICamera0-41.jpg',...
        };
    % Detect checkerboards in images
    [imagePoints, boardSize, imagesUsed] = detectCheckerboardPoints(imageFileNames);
    imageFileNames = imageFileNames(imagesUsed);
    
    % Read the first image to obtain image size
    originalImage = imread(imageFileNames{1});
    [mrows, ncols, ~] = size(originalImage);
    
    % Generate world coordinates of the corners of the squares
    squareSize = 40;  % in units of 'millimeters'
    worldPoints = generateCheckerboardPoints(boardSize, squareSize);
    
    % Calibrate the camera
    [cameraParams, imagesUsed, estimationErrors] = estimateCameraParameters(imagePoints, worldPoints, ...
        'EstimateSkew', false, 'EstimateTangentialDistortion', false, ...
        'NumRadialDistortionCoefficients', 2, 'WorldUnits', 'millimeters', ...
        'InitialIntrinsicMatrix', [], 'InitialRadialDistortion', [], ...
        'ImageSize', [mrows, ncols]);
    
    % View reprojection errors
    h1=figure; showReprojectionErrors(cameraParams);
    
    % Visualize pattern locations
    h2=figure; showExtrinsics(cameraParams, 'CameraCentric');
    
    % Display parameter estimation errors
    displayErrors(estimationErrors, cameraParams);
    
    % For example, you can use the calibration data to remove effects of lens distortion.
    undistortedImage = undistortImage(originalImage, cameraParams);
    
    % See additional examples of how to use the calibration data.  At the prompt type:
    % showdemo('MeasuringPlanarObjectsExample')
    % showdemo('StructureFromMotionExample')
    View Code

    运行刚刚生成保存的代码,得到如下的结果:

                Standard Errors of Estimated Camera Parameters
                ----------------------------------------------
    Intrinsics
    ----------
    Focal length (pixels):   [  794.4361 +/- 1.3790      796.3933 +/- 1.3197  ]
    Principal point (pixels):[  606.8329 +/- 0.8403      393.2514 +/- 0.9863  ]
    Radial distortion:       [   -0.3111 +/- 0.0010        0.0837 +/- 0.0007  ]
    Extrinsics
    ----------
    Rotation vectors:
                             [   -0.2723 +/- 0.0024        0.0407 +/- 0.0022        0.0792 +/- 0.0005  ] ...
    Translation vectors (millimeters):
                             [  -90.3841 +/- 0.5212     -121.9121 +/- 0.6037      485.5467 +/- 0.8995  ] ...

    根据上述结果,我们可以得到此鱼眼相机的畸变参数为(k1=-0.3111 k2=0.0837),使用这个参数进行图像的畸变矫正即可。

    4. 使用畸变参数对Camera采集的图像进行矫正:

    将3步骤中保存下来的cameraParams Mat数据加载到Matlab当中:

    load cameraParams

    注意,此时必须添加cameraParams文件保存的文件空间到Matlab工作空间中来,加载完成之后就可以使用参数进行相机采集图片的矫正了:

    I = imread('C:UsersAdministratorDesktopImageDataCAM0CSICamera0-41.jpg');
    I_R = undistortImage(I, cameraParams);
    figure,
    imshow(I_R)
    figure,
    imshow(I)

    运行结果如下所示:

    至此,关于Matlab这端的图像畸变矫正过程就算是完成了,如何使用畸变以及相机内参完成畸变矫正参看下面链接:

    相机畸变校正详解:https://blog.csdn.net/hanxiaoyong_/article/details/82888946

    二、Cpp-Opencv标定鱼眼镜头实践

    1. 依然使用之前采集的图片源,使用Opencv官方代码进行Camera的矫正:

    首先下载官方源代码:https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration

    参考官方标定算法手册:https://docs.opencv.org/master/d4/d94/tutorial_camera_calibration.html

     下载很慢的可以直接拷贝我的程序:

    camera_calibration.cpp (主程序文件,包括了图像输入,图像角点提取,图形标定,相机参数保存等功能模块)

      1 #include <iostream>
      2 #include <sstream>
      3 #include <string>
      4 #include <ctime>
      5 #include <cstdio>
      6 
      7 #include <opencv2/core.hpp>
      8 #include <opencv2/core/utility.hpp>
      9 #include <opencv2/imgproc.hpp>
     10 #include <opencv2/calib3d.hpp>
     11 #include <opencv2/imgcodecs.hpp>
     12 #include <opencv2/videoio.hpp>
     13 #include <opencv2/highgui.hpp>
     14 
     15 using namespace cv;
     16 using namespace std;
     17 
     18 class Settings
     19 {
     20 public:
     21     Settings() : goodInput(false) {}
     22     enum Pattern { NOT_EXISTING, CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
     23     enum InputType { INVALID, CAMERA, VIDEO_FILE, IMAGE_LIST };
     24 
     25     void write(FileStorage& fs) const                        //Write serialization for this class
     26     {
     27         fs << "{"
     28                   << "BoardSize_Width"  << boardSize.width
     29                   << "BoardSize_Height" << boardSize.height
     30                   << "Square_Size"         << squareSize
     31                   << "Calibrate_Pattern" << patternToUse
     32                   << "Calibrate_NrOfFrameToUse" << nrFrames
     33                   << "Calibrate_FixAspectRatio" << aspectRatio
     34                   << "Calibrate_AssumeZeroTangentialDistortion" << calibZeroTangentDist
     35                   << "Calibrate_FixPrincipalPointAtTheCenter" << calibFixPrincipalPoint
     36 
     37                   << "Write_DetectedFeaturePoints" << writePoints
     38                   << "Write_extrinsicParameters"   << writeExtrinsics
     39                   << "Write_gridPoints" << writeGrid
     40                   << "Write_outputFileName"  << outputFileName
     41 
     42                   << "Show_UndistortedImage" << showUndistorsed
     43 
     44                   << "Input_FlipAroundHorizontalAxis" << flipVertical
     45                   << "Input_Delay" << delay
     46                   << "Input" << input
     47            << "}";
     48     }
     49     void read(const FileNode& node)                          //Read serialization for this class
     50     {
     51         node["BoardSize_Width" ] >> boardSize.width;
     52         node["BoardSize_Height"] >> boardSize.height;
     53         node["Calibrate_Pattern"] >> patternToUse;
     54         node["Square_Size"]  >> squareSize;
     55         node["Calibrate_NrOfFrameToUse"] >> nrFrames;
     56         node["Calibrate_FixAspectRatio"] >> aspectRatio;
     57         node["Write_DetectedFeaturePoints"] >> writePoints;
     58         node["Write_extrinsicParameters"] >> writeExtrinsics;
     59         node["Write_gridPoints"] >> writeGrid;
     60         node["Write_outputFileName"] >> outputFileName;
     61         node["Calibrate_AssumeZeroTangentialDistortion"] >> calibZeroTangentDist;
     62         node["Calibrate_FixPrincipalPointAtTheCenter"] >> calibFixPrincipalPoint;
     63         node["Calibrate_UseFisheyeModel"] >> useFisheye;
     64         node["Input_FlipAroundHorizontalAxis"] >> flipVertical;
     65         node["Show_UndistortedImage"] >> showUndistorsed;
     66         node["Input"] >> input;
     67         node["Input_Delay"] >> delay;
     68         node["Fix_K1"] >> fixK1;
     69         node["Fix_K2"] >> fixK2;
     70         node["Fix_K3"] >> fixK3;
     71         node["Fix_K4"] >> fixK4;
     72         node["Fix_K5"] >> fixK5;
     73 
     74         validate();
     75     }
     76     void validate()
     77     {
     78         goodInput = true;
     79         if (boardSize.width <= 0 || boardSize.height <= 0)
     80         {
     81             cerr << "Invalid Board size: " << boardSize.width << " " << boardSize.height << endl;
     82             goodInput = false;
     83         }
     84         if (squareSize <= 10e-6)
     85         {
     86             cerr << "Invalid square size " << squareSize << endl;
     87             goodInput = false;
     88         }
     89         if (nrFrames <= 0)
     90         {
     91             cerr << "Invalid number of frames " << nrFrames << endl;
     92             goodInput = false;
     93         }
     94 
     95         if (input.empty())      // Check for valid input
     96                 inputType = INVALID;
     97         else
     98         {
     99             if (input[0] >= '0' && input[0] <= '9')
    100             {
    101                 stringstream ss(input);
    102                 ss >> cameraID;
    103                 inputType = CAMERA;
    104             }
    105             else
    106             {
    107                 if (isListOfImages(input) && readStringList(input, imageList))
    108                 {
    109                     inputType = IMAGE_LIST;
    110                     nrFrames = (nrFrames < (int)imageList.size()) ? nrFrames : (int)imageList.size();
    111                 }
    112                 else
    113                     inputType = VIDEO_FILE;
    114             }
    115             if (inputType == CAMERA)
    116                 inputCapture.open(cameraID);
    117             if (inputType == VIDEO_FILE)
    118                 inputCapture.open(input);
    119             if (inputType != IMAGE_LIST && !inputCapture.isOpened())
    120                     inputType = INVALID;
    121         }
    122         if (inputType == INVALID)
    123         {
    124             cerr << " Input does not exist: " << input;
    125             goodInput = false;
    126         }
    127 
    128         flag = 0;
    129         if(calibFixPrincipalPoint) flag |= CALIB_FIX_PRINCIPAL_POINT;
    130         if(calibZeroTangentDist)   flag |= CALIB_ZERO_TANGENT_DIST;
    131         if(aspectRatio)            flag |= CALIB_FIX_ASPECT_RATIO;
    132         if(fixK1)                  flag |= CALIB_FIX_K1;
    133         if(fixK2)                  flag |= CALIB_FIX_K2;
    134         if(fixK3)                  flag |= CALIB_FIX_K3;
    135         if(fixK4)                  flag |= CALIB_FIX_K4;
    136         if(fixK5)                  flag |= CALIB_FIX_K5;
    137 
    138         if (useFisheye) {
    139             // the fisheye model has its own enum, so overwrite the flags
    140             flag = fisheye::CALIB_FIX_SKEW | fisheye::CALIB_RECOMPUTE_EXTRINSIC;
    141             if(fixK1)                   flag |= fisheye::CALIB_FIX_K1;
    142             if(fixK2)                   flag |= fisheye::CALIB_FIX_K2;
    143             if(fixK3)                   flag |= fisheye::CALIB_FIX_K3;
    144             if(fixK4)                   flag |= fisheye::CALIB_FIX_K4;
    145             if (calibFixPrincipalPoint) flag |= fisheye::CALIB_FIX_PRINCIPAL_POINT;
    146         }
    147 
    148         calibrationPattern = NOT_EXISTING;
    149         if (!patternToUse.compare("CHESSBOARD")) calibrationPattern = CHESSBOARD;
    150         if (!patternToUse.compare("CIRCLES_GRID")) calibrationPattern = CIRCLES_GRID;
    151         if (!patternToUse.compare("ASYMMETRIC_CIRCLES_GRID")) calibrationPattern = ASYMMETRIC_CIRCLES_GRID;
    152         if (calibrationPattern == NOT_EXISTING)
    153         {
    154             cerr << " Camera calibration mode does not exist: " << patternToUse << endl;
    155             goodInput = false;
    156         }
    157         atImageList = 0;
    158 
    159     }
    160     Mat nextImage()
    161     {
    162         Mat result;
    163         if( inputCapture.isOpened() )
    164         {
    165             Mat view0;
    166             inputCapture >> view0;
    167             view0.copyTo(result);
    168         }
    169         else if( atImageList < imageList.size() )
    170             result = imread(imageList[atImageList++], IMREAD_COLOR);
    171 
    172         return result;
    173     }
    174 
    175     static bool readStringList( const string& filename, vector<string>& l )
    176     {
    177         l.clear();
    178         FileStorage fs(filename, FileStorage::READ);
    179         if( !fs.isOpened() )
    180             return false;
    181         FileNode n = fs.getFirstTopLevelNode();
    182         if( n.type() != FileNode::SEQ )
    183             return false;
    184         FileNodeIterator it = n.begin(), it_end = n.end();
    185         for( ; it != it_end; ++it )
    186             l.push_back((string)*it);
    187         return true;
    188     }
    189 
    190     static bool isListOfImages( const string& filename)
    191     {
    192         string s(filename);
    193         // Look for file extension
    194         if( s.find(".xml") == string::npos && s.find(".yaml") == string::npos && s.find(".yml") == string::npos )
    195             return false;
    196         else
    197             return true;
    198     }
    199 public:
    200     Size boardSize;              // The size of the board -> Number of items by width and height
    201     Pattern calibrationPattern;  // One of the Chessboard, circles, or asymmetric circle pattern
    202     float squareSize;            // The size of a square in your defined unit (point, millimeter,etc).
    203     int nrFrames;                // The number of frames to use from the input for calibration
    204     float aspectRatio;           // The aspect ratio
    205     int delay;                   // In case of a video input
    206     bool writePoints;            // Write detected feature points
    207     bool writeExtrinsics;        // Write extrinsic parameters
    208     bool writeGrid;              // Write refined 3D target grid points
    209     bool calibZeroTangentDist;   // Assume zero tangential distortion
    210     bool calibFixPrincipalPoint; // Fix the principal point at the center
    211     bool flipVertical;           // Flip the captured images around the horizontal axis
    212     string outputFileName;       // The name of the file where to write
    213     bool showUndistorsed;        // Show undistorted images after calibration
    214     string input;                // The input ->
    215     bool useFisheye;             // use fisheye camera model for calibration
    216     bool fixK1;                  // fix K1 distortion coefficient
    217     bool fixK2;                  // fix K2 distortion coefficient
    218     bool fixK3;                  // fix K3 distortion coefficient
    219     bool fixK4;                  // fix K4 distortion coefficient
    220     bool fixK5;                  // fix K5 distortion coefficient
    221 
    222     int cameraID;
    223     vector<string> imageList;
    224     size_t atImageList;
    225     VideoCapture inputCapture;
    226     InputType inputType;
    227     bool goodInput;
    228     int flag;
    229 
    230 private:
    231     string patternToUse;
    232 
    233 
    234 };
    235 
    236 static inline void read(const FileNode& node, Settings& x, const Settings& default_value = Settings())
    237 {
    238     if(node.empty())
    239         x = default_value;
    240     else
    241         x.read(node);
    242 }
    243 
    244 enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 };
    245 
    246 bool runCalibrationAndSave(Settings& s, Size imageSize, Mat&  cameraMatrix, Mat& distCoeffs,
    247                            vector<vector<Point2f> > imagePoints, float grid_width, bool release_object);
    248 
    249 int main(int argc, char* argv[])
    250 {
    251     const String keys
    252         = "{help h usage ? |           | print this message            }"
    253           "{@settings      |default.xml| input setting file            }"
    254           "{d              |           | actual distance between top-left and top-right corners of "
    255           "the calibration grid }"
    256           "{winSize        | 11        | Half of search window for cornerSubPix }";
    257     CommandLineParser parser(argc, argv, keys);
    258     parser.about("This is a camera calibration sample.
    "
    259                  "Usage: camera_calibration [configuration_file -- default ./default.xml]
    "
    260                  "Near the sample file you'll find the configuration file, which has detailed help of "
    261                  "how to edit it. It may be any OpenCV supported file format XML/YAML.");
    262     if (!parser.check()) {
    263         parser.printErrors();
    264         return 0;
    265     }
    266 
    267     if (parser.has("help")) {
    268         parser.printMessage();
    269         return 0;
    270     }
    271 
    272     //! [file_read]
    273     Settings s;
    274     const string inputSettingsFile = parser.get<string>(0);
    275     FileStorage fs(inputSettingsFile, FileStorage::READ); // Read the settings
    276     if (!fs.isOpened())
    277     {
    278         cout << "Could not open the configuration file: "" << inputSettingsFile << """ << endl;
    279         parser.printMessage();
    280         return -1;
    281     }
    282     fs["Settings"] >> s;
    283     fs.release();                                         // close Settings file
    284     //! [file_read]
    285 
    286     //FileStorage fout("settings.yml", FileStorage::WRITE); // write config as YAML
    287     //fout << "Settings" << s;
    288 
    289     if (!s.goodInput)
    290     {
    291         cout << "Invalid input detected. Application stopping. " << endl;
    292         return -1;
    293     }
    294 
    295     int winSize = parser.get<int>("winSize");
    296 
    297     float grid_width = s.squareSize * (s.boardSize.width - 1);
    298     bool release_object = false;
    299     if (parser.has("d")) {
    300         grid_width = parser.get<float>("d");
    301         release_object = true;
    302     }
    303 
    304     vector<vector<Point2f> > imagePoints;
    305     Mat cameraMatrix, distCoeffs;
    306     Size imageSize;
    307     int mode = s.inputType == Settings::IMAGE_LIST ? CAPTURING : DETECTION;
    308     clock_t prevTimestamp = 0;
    309     const Scalar RED(0,0,255), GREEN(0,255,0);
    310     const char ESC_KEY = 27;
    311 
    312     //! [get_input]
    313     for(;;)
    314     {
    315         Mat view;
    316         bool blinkOutput = false;
    317 
    318         view = s.nextImage();
    319 
    320         //-----  If no more image, or got enough, then stop calibration and show result -------------
    321         if( mode == CAPTURING && imagePoints.size() >= (size_t)s.nrFrames )
    322         {
    323           if(runCalibrationAndSave(s, imageSize,  cameraMatrix, distCoeffs, imagePoints, grid_width,
    324                                    release_object))
    325               mode = CALIBRATED;
    326           else
    327               mode = DETECTION;
    328         }
    329         if(view.empty())          // If there are no more images stop the loop
    330         {
    331             // if calibration threshold was not reached yet, calibrate now
    332             if( mode != CALIBRATED && !imagePoints.empty() )
    333                 runCalibrationAndSave(s, imageSize,  cameraMatrix, distCoeffs, imagePoints, grid_width,
    334                                       release_object);
    335             break;
    336         }
    337         //! [get_input]
    338 
    339         imageSize = view.size();  // Format input image.
    340         if( s.flipVertical )    flip( view, view, 0 );
    341 
    342         //! [find_pattern]
    343         vector<Point2f> pointBuf;
    344 
    345         bool found;
    346 
    347         int chessBoardFlags = CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE;
    348 
    349         if(!s.useFisheye) {
    350             // fast check erroneously fails with high distortions like fisheye
    351             chessBoardFlags |= CALIB_CB_FAST_CHECK;
    352         }
    353 
    354         switch( s.calibrationPattern ) // Find feature points on the input format
    355         {
    356         case Settings::CHESSBOARD:
    357             found = findChessboardCorners( view, s.boardSize, pointBuf, chessBoardFlags);
    358             break;
    359         case Settings::CIRCLES_GRID:
    360             found = findCirclesGrid( view, s.boardSize, pointBuf );
    361             break;
    362         case Settings::ASYMMETRIC_CIRCLES_GRID:
    363             found = findCirclesGrid( view, s.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID );
    364             break;
    365         default:
    366             found = false;
    367             break;
    368         }
    369         //! [find_pattern]
    370         //! [pattern_found]
    371         if ( found)                // If done with success,
    372         {
    373               // improve the found corners' coordinate accuracy for chessboard
    374                 if( s.calibrationPattern == Settings::CHESSBOARD)
    375                 {
    376                     Mat viewGray;
    377                     cvtColor(view, viewGray, COLOR_BGR2GRAY);
    378                     cornerSubPix( viewGray, pointBuf, Size(winSize,winSize),
    379                         Size(-1,-1), TermCriteria( TermCriteria::EPS+TermCriteria::COUNT, 30, 0.0001 ));
    380                 }
    381 
    382                 if( mode == CAPTURING &&  // For camera only take new samples after delay time
    383                     (!s.inputCapture.isOpened() || clock() - prevTimestamp > s.delay*1e-3*CLOCKS_PER_SEC) )
    384                 {
    385                     imagePoints.push_back(pointBuf);
    386                     prevTimestamp = clock();
    387                     blinkOutput = s.inputCapture.isOpened();
    388                 }
    389 
    390                 // Draw the corners.
    391                 drawChessboardCorners( view, s.boardSize, Mat(pointBuf), found );
    392         }
    393         //! [pattern_found]
    394         //----------------------------- Output Text ------------------------------------------------
    395         //! [output_text]
    396         string msg = (mode == CAPTURING) ? "100/100" :
    397                       mode == CALIBRATED ? "Calibrated" : "Press 'g' to start";
    398         int baseLine = 0;
    399         Size textSize = getTextSize(msg, 1, 1, 1, &baseLine);
    400         Point textOrigin(view.cols - 2*textSize.width - 10, view.rows - 2*baseLine - 10);
    401 
    402         if( mode == CAPTURING )
    403         {
    404             if(s.showUndistorsed)
    405                 msg = format( "%d/%d Undist", (int)imagePoints.size(), s.nrFrames );
    406             else
    407                 msg = format( "%d/%d", (int)imagePoints.size(), s.nrFrames );
    408         }
    409 
    410         putText( view, msg, textOrigin, 1, 1, mode == CALIBRATED ?  GREEN : RED);
    411 
    412         if( blinkOutput )
    413             bitwise_not(view, view);
    414         //! [output_text]
    415         //------------------------- Video capture  output  undistorted ------------------------------
    416         //! [output_undistorted]
    417         if( mode == CALIBRATED && s.showUndistorsed )
    418         {
    419             Mat temp = view.clone();
    420             if (s.useFisheye)
    421               cv::fisheye::undistortImage(temp, view, cameraMatrix, distCoeffs);
    422             else
    423               undistort(temp, view, cameraMatrix, distCoeffs);
    424         }
    425         //! [output_undistorted]
    426         //------------------------------ Show image and check for input commands -------------------
    427         //! [await_input]
    428         imshow("Image View", view);
    429         char key = (char)waitKey(s.inputCapture.isOpened() ? 50 : s.delay);
    430 
    431         if( key  == ESC_KEY )
    432             break;
    433 
    434         if( key == 'u' && mode == CALIBRATED )
    435            s.showUndistorsed = !s.showUndistorsed;
    436 
    437         if( s.inputCapture.isOpened() && key == 'g' )
    438         {
    439             mode = CAPTURING;
    440             imagePoints.clear();
    441         }
    442         //! [await_input]
    443     }
    444 
    445     // -----------------------Show the undistorted image for the image list ------------------------
    446     //! [show_results]
    447     if( s.inputType == Settings::IMAGE_LIST && s.showUndistorsed )
    448     {
    449         Mat view, rview, map1, map2;
    450 
    451         if (s.useFisheye)
    452         {
    453             Mat newCamMat;
    454             fisheye::estimateNewCameraMatrixForUndistortRectify(cameraMatrix, distCoeffs, imageSize,
    455                                                                 Matx33d::eye(), newCamMat, 1);
    456             fisheye::initUndistortRectifyMap(cameraMatrix, distCoeffs, Matx33d::eye(), newCamMat, imageSize,
    457                                              CV_16SC2, map1, map2);
    458         }
    459         else
    460         {
    461             initUndistortRectifyMap(
    462                 cameraMatrix, distCoeffs, Mat(),
    463                 getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0), imageSize,
    464                 CV_16SC2, map1, map2);
    465         }
    466 
    467         for(size_t i = 0; i < s.imageList.size(); i++ )
    468         {
    469             view = imread(s.imageList[i], IMREAD_COLOR);
    470             if(view.empty())
    471                 continue;
    472             remap(view, rview, map1, map2, INTER_LINEAR);
    473             imshow("Image View", rview);
    474             char c = (char)waitKey();
    475             if( c  == ESC_KEY || c == 'q' || c == 'Q' )
    476                 break;
    477         }
    478     }
    479     //! [show_results]
    480 
    481     return 0;
    482 }
    483 
    484 //! [compute_errors]
    485 static double computeReprojectionErrors( const vector<vector<Point3f> >& objectPoints,
    486                                          const vector<vector<Point2f> >& imagePoints,
    487                                          const vector<Mat>& rvecs, const vector<Mat>& tvecs,
    488                                          const Mat& cameraMatrix , const Mat& distCoeffs,
    489                                          vector<float>& perViewErrors, bool fisheye)
    490 {
    491     vector<Point2f> imagePoints2;
    492     size_t totalPoints = 0;
    493     double totalErr = 0, err;
    494     perViewErrors.resize(objectPoints.size());
    495 
    496     for(size_t i = 0; i < objectPoints.size(); ++i )
    497     {
    498         if (fisheye)
    499         {
    500             fisheye::projectPoints(objectPoints[i], imagePoints2, rvecs[i], tvecs[i], cameraMatrix,
    501                                    distCoeffs);
    502         }
    503         else
    504         {
    505             projectPoints(objectPoints[i], rvecs[i], tvecs[i], cameraMatrix, distCoeffs, imagePoints2);
    506         }
    507         err = norm(imagePoints[i], imagePoints2, NORM_L2);
    508 
    509         size_t n = objectPoints[i].size();
    510         perViewErrors[i] = (float) std::sqrt(err*err/n);
    511         totalErr        += err*err;
    512         totalPoints     += n;
    513     }
    514 
    515     return std::sqrt(totalErr/totalPoints);
    516 }
    517 //! [compute_errors]
    518 //! [board_corners]
    519 static void calcBoardCornerPositions(Size boardSize, float squareSize, vector<Point3f>& corners,
    520                                      Settings::Pattern patternType /*= Settings::CHESSBOARD*/)
    521 {
    522     corners.clear();
    523 
    524     switch(patternType)
    525     {
    526     case Settings::CHESSBOARD:
    527     case Settings::CIRCLES_GRID:
    528         for( int i = 0; i < boardSize.height; ++i )
    529             for( int j = 0; j < boardSize.width; ++j )
    530                 corners.push_back(Point3f(j*squareSize, i*squareSize, 0));
    531         break;
    532 
    533     case Settings::ASYMMETRIC_CIRCLES_GRID:
    534         for( int i = 0; i < boardSize.height; i++ )
    535             for( int j = 0; j < boardSize.width; j++ )
    536                 corners.push_back(Point3f((2*j + i % 2)*squareSize, i*squareSize, 0));
    537         break;
    538     default:
    539         break;
    540     }
    541 }
    542 //! [board_corners]
    543 static bool runCalibration( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs,
    544                             vector<vector<Point2f> > imagePoints, vector<Mat>& rvecs, vector<Mat>& tvecs,
    545                             vector<float>& reprojErrs,  double& totalAvgErr, vector<Point3f>& newObjPoints,
    546                             float grid_width, bool release_object)
    547 {
    548     //! [fixed_aspect]
    549     cameraMatrix = Mat::eye(3, 3, CV_64F);
    550     if( s.flag & CALIB_FIX_ASPECT_RATIO )
    551         cameraMatrix.at<double>(0,0) = s.aspectRatio;
    552     //! [fixed_aspect]
    553     if (s.useFisheye) {
    554         distCoeffs = Mat::zeros(4, 1, CV_64F);
    555     } else {
    556         distCoeffs = Mat::zeros(8, 1, CV_64F);
    557     }
    558 
    559     vector<vector<Point3f> > objectPoints(1);
    560     calcBoardCornerPositions(s.boardSize, s.squareSize, objectPoints[0], s.calibrationPattern);
    561     objectPoints[0][s.boardSize.width - 1].x = objectPoints[0][0].x + grid_width;
    562     newObjPoints = objectPoints[0];
    563 
    564     objectPoints.resize(imagePoints.size(),objectPoints[0]);
    565 
    566     //Find intrinsic and extrinsic camera parameters
    567     double rms;
    568 
    569     if (s.useFisheye) {
    570         Mat _rvecs, _tvecs;
    571         rms = fisheye::calibrate(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, _rvecs,
    572                                  _tvecs, s.flag);
    573 
    574         rvecs.reserve(_rvecs.rows);
    575         tvecs.reserve(_tvecs.rows);
    576         for(int i = 0; i < int(objectPoints.size()); i++){
    577             rvecs.push_back(_rvecs.row(i));
    578             tvecs.push_back(_tvecs.row(i));
    579         }
    580     } else {
    581         int iFixedPoint = -1;
    582         if (release_object)
    583             iFixedPoint = s.boardSize.width - 1;
    584         rms = calibrateCameraRO(objectPoints, imagePoints, imageSize, iFixedPoint,
    585                                 cameraMatrix, distCoeffs, rvecs, tvecs, newObjPoints,
    586                                 s.flag | CALIB_USE_LU);
    587     }
    588 
    589     if (release_object) {
    590         cout << "New board corners: " << endl;
    591         cout << newObjPoints[0] << endl;
    592         cout << newObjPoints[s.boardSize.width - 1] << endl;
    593         cout << newObjPoints[s.boardSize.width * (s.boardSize.height - 1)] << endl;
    594         cout << newObjPoints.back() << endl;
    595     }
    596 
    597     cout << "Re-projection error reported by calibrateCamera: "<< rms << endl;
    598 
    599     bool ok = checkRange(cameraMatrix) && checkRange(distCoeffs);
    600 
    601     objectPoints.clear();
    602     objectPoints.resize(imagePoints.size(), newObjPoints);
    603     totalAvgErr = computeReprojectionErrors(objectPoints, imagePoints, rvecs, tvecs, cameraMatrix,
    604                                             distCoeffs, reprojErrs, s.useFisheye);
    605 
    606     return ok;
    607 }
    608 
    609 // Print camera parameters to the output file
    610 static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs,
    611                               const vector<Mat>& rvecs, const vector<Mat>& tvecs,
    612                               const vector<float>& reprojErrs, const vector<vector<Point2f> >& imagePoints,
    613                               double totalAvgErr, const vector<Point3f>& newObjPoints )
    614 {
    615     FileStorage fs( s.outputFileName, FileStorage::WRITE );
    616 
    617     time_t tm;
    618     time( &tm );
    619     struct tm *t2 = localtime( &tm );
    620     char buf[1024];
    621     strftime( buf, sizeof(buf), "%c", t2 );
    622 
    623     fs << "calibration_time" << buf;
    624 
    625     if( !rvecs.empty() || !reprojErrs.empty() )
    626         fs << "nr_of_frames" << (int)std::max(rvecs.size(), reprojErrs.size());
    627     fs << "image_width" << imageSize.width;
    628     fs << "image_height" << imageSize.height;
    629     fs << "board_width" << s.boardSize.width;
    630     fs << "board_height" << s.boardSize.height;
    631     fs << "square_size" << s.squareSize;
    632 
    633     if( s.flag & CALIB_FIX_ASPECT_RATIO )
    634         fs << "fix_aspect_ratio" << s.aspectRatio;
    635 
    636     if (s.flag)
    637     {
    638         std::stringstream flagsStringStream;
    639         if (s.useFisheye)
    640         {
    641             flagsStringStream << "flags:"
    642                 << (s.flag & fisheye::CALIB_FIX_SKEW ? " +fix_skew" : "")
    643                 << (s.flag & fisheye::CALIB_FIX_K1 ? " +fix_k1" : "")
    644                 << (s.flag & fisheye::CALIB_FIX_K2 ? " +fix_k2" : "")
    645                 << (s.flag & fisheye::CALIB_FIX_K3 ? " +fix_k3" : "")
    646                 << (s.flag & fisheye::CALIB_FIX_K4 ? " +fix_k4" : "")
    647                 << (s.flag & fisheye::CALIB_RECOMPUTE_EXTRINSIC ? " +recompute_extrinsic" : "");
    648         }
    649         else
    650         {
    651             flagsStringStream << "flags:"
    652                 << (s.flag & CALIB_USE_INTRINSIC_GUESS ? " +use_intrinsic_guess" : "")
    653                 << (s.flag & CALIB_FIX_ASPECT_RATIO ? " +fix_aspectRatio" : "")
    654                 << (s.flag & CALIB_FIX_PRINCIPAL_POINT ? " +fix_principal_point" : "")
    655                 << (s.flag & CALIB_ZERO_TANGENT_DIST ? " +zero_tangent_dist" : "")
    656                 << (s.flag & CALIB_FIX_K1 ? " +fix_k1" : "")
    657                 << (s.flag & CALIB_FIX_K2 ? " +fix_k2" : "")
    658                 << (s.flag & CALIB_FIX_K3 ? " +fix_k3" : "")
    659                 << (s.flag & CALIB_FIX_K4 ? " +fix_k4" : "")
    660                 << (s.flag & CALIB_FIX_K5 ? " +fix_k5" : "");
    661         }
    662         fs.writeComment(flagsStringStream.str());
    663     }
    664 
    665     fs << "flags" << s.flag;
    666 
    667     fs << "fisheye_model" << s.useFisheye;
    668 
    669     fs << "camera_matrix" << cameraMatrix;
    670     fs << "distortion_coefficients" << distCoeffs;
    671 
    672     fs << "avg_reprojection_error" << totalAvgErr;
    673     if (s.writeExtrinsics && !reprojErrs.empty())
    674         fs << "per_view_reprojection_errors" << Mat(reprojErrs);
    675 
    676     if(s.writeExtrinsics && !rvecs.empty() && !tvecs.empty() )
    677     {
    678         CV_Assert(rvecs[0].type() == tvecs[0].type());
    679         Mat bigmat((int)rvecs.size(), 6, CV_MAKETYPE(rvecs[0].type(), 1));
    680         bool needReshapeR = rvecs[0].depth() != 1 ? true : false;
    681         bool needReshapeT = tvecs[0].depth() != 1 ? true : false;
    682 
    683         for( size_t i = 0; i < rvecs.size(); i++ )
    684         {
    685             Mat r = bigmat(Range(int(i), int(i+1)), Range(0,3));
    686             Mat t = bigmat(Range(int(i), int(i+1)), Range(3,6));
    687 
    688             if(needReshapeR)
    689                 rvecs[i].reshape(1, 1).copyTo(r);
    690             else
    691             {
    692                 //*.t() is MatExpr (not Mat) so we can use assignment operator
    693                 CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1);
    694                 r = rvecs[i].t();
    695             }
    696 
    697             if(needReshapeT)
    698                 tvecs[i].reshape(1, 1).copyTo(t);
    699             else
    700             {
    701                 CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1);
    702                 t = tvecs[i].t();
    703             }
    704         }
    705         fs.writeComment("a set of 6-tuples (rotation vector + translation vector) for each view");
    706         fs << "extrinsic_parameters" << bigmat;
    707     }
    708 
    709     if(s.writePoints && !imagePoints.empty() )
    710     {
    711         Mat imagePtMat((int)imagePoints.size(), (int)imagePoints[0].size(), CV_32FC2);
    712         for( size_t i = 0; i < imagePoints.size(); i++ )
    713         {
    714             Mat r = imagePtMat.row(int(i)).reshape(2, imagePtMat.cols);
    715             Mat imgpti(imagePoints[i]);
    716             imgpti.copyTo(r);
    717         }
    718         fs << "image_points" << imagePtMat;
    719     }
    720 
    721     if( s.writeGrid && !newObjPoints.empty() )
    722     {
    723         fs << "grid_points" << newObjPoints;
    724     }
    725 }
    726 
    727 //! [run_and_save]
    728 bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs,
    729                            vector<vector<Point2f> > imagePoints, float grid_width, bool release_object)
    730 {
    731     vector<Mat> rvecs, tvecs;
    732     vector<float> reprojErrs;
    733     double totalAvgErr = 0;
    734     vector<Point3f> newObjPoints;
    735 
    736     bool ok = runCalibration(s, imageSize, cameraMatrix, distCoeffs, imagePoints, rvecs, tvecs, reprojErrs,
    737                              totalAvgErr, newObjPoints, grid_width, release_object);
    738     cout << (ok ? "Calibration succeeded" : "Calibration failed")
    739          << ". avg re projection error = " << totalAvgErr << endl;
    740 
    741     if (ok)
    742         saveCameraParams(s, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, reprojErrs, imagePoints,
    743                          totalAvgErr, newObjPoints);
    744     return ok;
    745 }
    746 //! [run_and_save]
    View Code

    VID5.xml (外部配置文件,包括了待标定相机采集图像的绝对路径或者相对路径)

    <?xml version="1.0"?>
    <opencv_storage>
    <images>
    images/CameraCalibraation/VID5/xx1.jpg
    images/CameraCalibraation/VID5/xx2.jpg
    images/CameraCalibraation/VID5/xx3.jpg
    images/CameraCalibraation/VID5/xx4.jpg
    images/CameraCalibraation/VID5/xx5.jpg
    images/CameraCalibraation/VID5/xx6.jpg
    images/CameraCalibraation/VID5/xx7.jpg
    images/CameraCalibraation/VID5/xx8.jpg
    </images>
    </opencv_storage>
    View Code

    in_VID5.xml (标定基本参数配置,包括了标定的模式,图像样本的获取方式等等)

    <?xml version="1.0"?>
    <opencv_storage>
    <Settings>
      <!-- Number of inner corners per a item row and column. (square, circle) -->
      <BoardSize_Width> 9</BoardSize_Width>
      <BoardSize_Height>6</BoardSize_Height>
      
      <!-- The size of a square in some user defined metric system (pixel, millimeter)-->
      <Square_Size>50</Square_Size>
      
      <!-- The type of input used for camera calibration. One of: CHESSBOARD CIRCLES_GRID ASYMMETRIC_CIRCLES_GRID -->
      <Calibrate_Pattern>"CHESSBOARD"</Calibrate_Pattern>
      
      <!-- The input to use for calibration. 
            To use an input camera -> give the ID of the camera, like "1"
            To use an input video  -> give the path of the input video, like "/tmp/x.avi"
            To use an image list   -> give the path to the XML or YAML file containing the list of the images, like "/tmp/circles_list.xml"
            -->
      <Input>"images/CameraCalibration/VID5/VID5.xml"</Input>
      <!--  If true (non-zero) we flip the input images around the horizontal axis.-->
      <Input_FlipAroundHorizontalAxis>0</Input_FlipAroundHorizontalAxis>
      
      <!-- Time delay between frames in case of camera. -->
      <Input_Delay>100</Input_Delay>    
      
      <!-- How many frames to use, for calibration. -->
      <Calibrate_NrOfFrameToUse>25</Calibrate_NrOfFrameToUse>
      <!-- Consider only fy as a free parameter, the ratio fx/fy stays the same as in the input cameraMatrix. 
           Use or not setting. 0 - False Non-Zero - True-->
      <Calibrate_FixAspectRatio> 1 </Calibrate_FixAspectRatio>
      <!-- If true (non-zero) tangential distortion coefficients  are set to zeros and stay zero.-->
      <Calibrate_AssumeZeroTangentialDistortion>1</Calibrate_AssumeZeroTangentialDistortion>
      <!-- If true (non-zero) the principal point is not changed during the global optimization.-->
      <Calibrate_FixPrincipalPointAtTheCenter> 1 </Calibrate_FixPrincipalPointAtTheCenter>
      
      <!-- The name of the output log file. -->
      <Write_outputFileName>"out_camera_data.xml"</Write_outputFileName>
      <!-- If true (non-zero) we write to the output file the feature points.-->
      <Write_DetectedFeaturePoints>1</Write_DetectedFeaturePoints>
      <!-- If true (non-zero) we write to the output file the extrinsic camera parameters.-->
      <Write_extrinsicParameters>1</Write_extrinsicParameters>
      <!-- If true (non-zero) we write to the output file the refined 3D target grid points.-->
      <Write_gridPoints>1</Write_gridPoints>
      <!-- If true (non-zero) we show after calibration the undistorted images.-->
      <Show_UndistortedImage>1</Show_UndistortedImage>
      <!-- If true (non-zero) will be used fisheye camera model.-->
      <Calibrate_UseFisheyeModel>0</Calibrate_UseFisheyeModel>
      <!-- If true (non-zero) distortion coefficient k1 will be equals to zero.-->
      <Fix_K1>0</Fix_K1>
      <!-- If true (non-zero) distortion coefficient k2 will be equals to zero.-->
      <Fix_K2>0</Fix_K2>
      <!-- If true (non-zero) distortion coefficient k3 will be equals to zero.-->
      <Fix_K3>0</Fix_K3>
      <!-- If true (non-zero) distortion coefficient k4 will be equals to zero.-->
      <Fix_K4>1</Fix_K4>
      <!-- If true (non-zero) distortion coefficient k5 will be equals to zero.-->
      <Fix_K5>1</Fix_K5>
    </Settings>
    </opencv_storage>
    View Code

    out_camera_data.yml (主程序输出保存的相机基本参数,以方便下次相机的使用)

    %YAML:1.0
    calibration_Time: "08/19/11 20:44:38"
    nrOfFrames: 8
    image_Width: 640
    image_Height: 480
    board_Width: 9
    board_Height: 6
    square_Size: 50.
    FixAspectRatio: 1.
    # flags:  +fix_aspectRatio +fix_principal_point +zero_tangent_dist
    flagValue: 14
    Camera_Matrix: !!opencv-matrix
       rows: 3
       cols: 3
       dt: d
       data: [ 6.5746697810243404e+002, 0., 3.1950000000000000e+002, 0.,
           6.5746697810243404e+002, 2.3950000000000000e+002, 0., 0., 1. ]
    Distortion_Coefficients: !!opencv-matrix
       rows: 5
       cols: 1
       dt: d
       data: [ -4.1802327018241026e-001, 5.0715243805833121e-001, 0., 0.,
           -5.7843596847939704e-001 ]
    Avg_Reprojection_Error: 3.8441346462381665e-001
    Per_View_Reprojection_Errors: !!opencv-matrix
       rows: 8
       cols: 1
       dt: f
       data: [ 5.04357755e-001, 4.85754758e-001, 3.99563968e-001,
           4.13829178e-001, 3.53570908e-001, 3.21116358e-001,
           2.74473161e-001, 2.39761785e-001 ]
    # a set of 6-tuples (rotation vector + translation vector) for each view
    Extrinsic_Parameters: !!opencv-matrix
       rows: 8
       cols: 6
       dt: d
       data: [ -7.8704123655486097e-002, -1.5922384772614945e-001,
           3.1166227207451498e+000, 2.4224388101960471e+002,
           1.1795590397660339e+002, 6.2576484126093249e+002,
           -1.4117480285164308e-001, -1.7917415443804836e-002,
           3.1333182268743949e+000, 2.5943034781849354e+002,
           1.4039780562976958e+002, 6.3848706527260981e+002,
           7.2230525186138789e-002, -7.5445981266787754e-002,
           1.5712860749221762e+000, 1.7426560451795339e+002,
           -1.9309240362258871e+002, 7.0891416556762647e+002,
           2.0367310600105853e-002, 6.8565520026996951e-002,
           -5.4313033031644169e-004, -2.0146314940404827e+002,
           -1.3305643514116997e+002, 7.4933554744027231e+002,
           -3.4468530027734055e-002, 2.1921265175331925e-002,
           -1.5731053528054522e+000, -1.1155718744299284e+002,
           2.0307615364261443e+002, 8.4915903914333899e+002,
           3.7425562109513817e-002, 7.4883169379022230e-002,
           -3.6031632305130512e-002, -2.0094505419395196e+002,
           -1.1627359108310560e+002, 9.2021583518760133e+002,
           6.8105689976949157e-002, 6.4426739692440949e-002,
           -7.0967130057087435e-002, -1.9233852871740035e+002,
           -1.0334652096641923e+002, 1.0755293563503658e+003,
           -5.8017546499862287e-002, -1.6909812666033443e-003,
           -1.5876137659782963e+000, -1.0242234847115104e+002,
           2.2583088401423066e+002, 1.1125972190244058e+003 ]
    Image_points: !!opencv-matrix
       rows: 8
       cols: 54
       dt: "2f"
       data: [ 5.58494690e+002, 3.55650085e+002, 5.13314697e+002,
           3.59107666e+002, 4.65728333e+002, 3.62133911e+002,
           4.15701111e+002, 3.65026459e+002, 3.64399353e+002,
           3.67339203e+002, 3.12101196e+002, 3.69211914e+002,
           2.59208405e+002, 3.70413513e+002, 2.07456192e+002,
           3.71175995e+002, 1.56619507e+002, 3.72176544e+002,
           5.60868713e+002, 3.08104828e+002, 5.15191772e+002,
           3.10485626e+002, 4.67032959e+002, 3.12660004e+002,
           4.16112152e+002, 3.14887177e+002, 3.64010712e+002,
           3.16825775e+002, 3.10712372e+002, 3.18640808e+002,
           2.56853943e+002, 3.20017365e+002, 2.04168182e+002,
           3.20908417e+002, 1.52469528e+002, 3.22105377e+002,
           5.62328369e+002, 2.58646881e+002, 5.16396301e+002,
           2.59919281e+002, 4.67907654e+002, 2.61257874e+002,
           4.16463440e+002, 2.62675537e+002, 3.63546570e+002,
           2.64064117e+002, 3.09528137e+002, 2.65489990e+002,
           2.54765533e+002, 2.66862030e+002, 2.01299225e+002,
           2.67997345e+002, 1.48913437e+002, 2.69627167e+002,
           5.63098022e+002, 2.08423523e+002, 5.16782654e+002,
           2.08424667e+002, 4.68059296e+002, 2.08661697e+002,
           4.16216431e+002, 2.09268982e+002, 3.62888763e+002,
           2.10013397e+002, 3.08458557e+002, 2.11074738e+002,
           2.53267990e+002, 2.12496582e+002, 1.99121384e+002,
           2.14005814e+002, 1.46551376e+002, 2.15851318e+002,
           5.62997437e+002, 1.57966492e+002, 5.16406494e+002,
           1.56580688e+002, 4.67334900e+002, 1.55756500e+002,
           4.15378235e+002, 1.55492874e+002, 3.62096710e+002,
           1.55498734e+002, 3.07522827e+002, 1.56133240e+002,
           2.52235214e+002, 1.57516571e+002, 1.97876328e+002,
           1.59318787e+002, 1.45078247e+002, 1.61638428e+002,
           5.62097168e+002, 1.07469536e+002, 5.15766846e+002,
           1.04902527e+002, 4.66562866e+002, 1.03045807e+002,
           4.14651459e+002, 1.01924713e+002, 3.61240662e+002,
           1.01357826e+002, 3.06746613e+002, 1.01582802e+002,
           2.51568024e+002, 1.02920105e+002, 1.97343307e+002,
           1.04941299e+002, 1.44756821e+002, 1.07737488e+002,
           5.68062500e+002, 3.73591125e+002, 5.25272644e+002,
           3.77019318e+002, 4.79870941e+002, 3.80086578e+002,
           4.31823730e+002, 3.83036652e+002, 3.81995758e+002,
           3.85271759e+002, 3.30728729e+002, 3.86998779e+002,
           2.78071167e+002, 3.88151031e+002, 2.26231567e+002,
           3.88669586e+002, 1.74855331e+002, 3.89197998e+002,
           5.69792542e+002, 3.27097382e+002, 5.26866028e+002,
           3.29362366e+002, 4.81278229e+002, 3.31532928e+002,
           4.32783203e+002, 3.33552185e+002, 3.82408234e+002,
           3.35186554e+002, 3.30427399e+002, 3.36404053e+002,
           2.77138519e+002, 3.37450958e+002, 2.24525131e+002,
           3.37957092e+002, 1.72285507e+002, 3.38503540e+002,
           5.70942749e+002, 2.79243713e+002, 5.27789307e+002,
           2.80073486e+002, 4.82146576e+002, 2.81226410e+002,
           4.33247375e+002, 2.82237427e+002, 3.82503662e+002,
           2.83062286e+002, 3.30138885e+002, 2.83794434e+002,
           2.76433228e+002, 2.84549286e+002, 2.23158783e+002,
           2.84981049e+002, 1.70520218e+002, 2.85720886e+002,
           5.71001953e+002, 2.30928329e+002, 5.27846863e+002,
           2.30519928e+002, 4.82114563e+002, 2.30268906e+002,
           4.33114563e+002, 2.30243515e+002, 3.82384857e+002,
           2.30311340e+002, 3.29870392e+002, 2.30454620e+002,
           2.76012634e+002, 2.30882156e+002, 2.22529434e+002,
           2.31355362e+002, 1.69742065e+002, 2.32063004e+002,
           5.70199036e+002, 1.82609772e+002, 5.27030884e+002,
           1.80973267e+002, 4.81193573e+002, 1.79573792e+002,
           4.32409821e+002, 1.78475616e+002, 3.81855530e+002,
           1.77680283e+002, 3.29641937e+002, 1.77092087e+002,
           2.75895782e+002, 1.77155502e+002, 2.22438889e+002,
           1.77605667e+002, 1.69884583e+002, 1.78365585e+002,
           5.69026245e+002, 1.34654831e+002, 5.26171570e+002,
           1.31798691e+002, 4.80653503e+002, 1.29171509e+002,
           4.31869904e+002, 1.27280067e+002, 3.81419739e+002,
           1.25591202e+002, 3.29466644e+002, 1.24407089e+002,
           2.76225342e+002, 1.24174736e+002, 2.23024109e+002,
           1.24463333e+002, 1.70838898e+002, 1.25398903e+002,
           4.73812897e+002, 6.94673386e+001, 4.74245453e+002,
           1.12387466e+002, 4.74243347e+002, 1.56034164e+002,
           4.73834778e+002, 2.00523651e+002, 4.72891602e+002,
           2.44457306e+002, 4.71412811e+002, 2.87981171e+002,
           4.69708252e+002, 3.30783173e+002, 4.67558228e+002,
           3.71818420e+002, 4.65495667e+002, 4.11996979e+002,
           4.31027649e+002, 6.75546722e+001, 4.31269440e+002,
           1.10960022e+002, 4.31185486e+002, 1.55113556e+002,
           4.30830139e+002, 2.00061066e+002, 4.30168427e+002,
           2.44456863e+002, 4.29107544e+002, 2.88479645e+002,
           4.27829071e+002, 3.31813507e+002, 4.26131653e+002,
           3.73071228e+002, 4.24718811e+002, 4.13476563e+002,
           3.86868805e+002, 6.61982269e+001, 3.86895416e+002,
           1.09904411e+002, 3.86690216e+002, 1.54396423e+002,
           3.86368591e+002, 1.99800369e+002, 3.85792206e+002,
           2.44538574e+002, 3.85117279e+002, 2.88826447e+002,
           3.84405273e+002, 3.32408020e+002, 3.83303772e+002,
           3.74074097e+002, 3.82477448e+002, 4.14638977e+002,
           3.41941437e+002, 6.54462357e+001, 3.41628204e+002,
           1.09383698e+002, 3.41402344e+002, 1.54105545e+002,
           3.41168854e+002, 1.99655045e+002, 3.40816681e+002,
           2.44469910e+002, 3.40516937e+002, 2.88975800e+002,
           3.40365662e+002, 3.32670990e+002, 3.39935211e+002,
           3.74465759e+002, 3.39847626e+002, 4.14742279e+002,
           2.96694000e+002, 6.56859589e+001, 2.96075226e+002,
           1.09505333e+002, 2.95704895e+002, 1.54202652e+002,
           2.95653107e+002, 1.99734131e+002, 2.95589661e+002,
           2.44549530e+002, 2.95629547e+002, 2.88889496e+002,
           2.96138733e+002, 3.32610931e+002, 2.96520905e+002,
           3.74608551e+002, 2.96987091e+002, 4.14774902e+002,
           2.51414978e+002, 6.65755463e+001, 2.50681854e+002,
           1.10189331e+002, 2.50183380e+002, 1.54658005e+002,
           2.50331161e+002, 2.00073761e+002, 2.50590790e+002,
           2.44719513e+002, 2.51083817e+002, 2.88868286e+002,
           2.52134262e+002, 3.32266937e+002, 2.53097809e+002,
           3.74022491e+002, 2.54404007e+002, 4.14018066e+002,
           1.49524078e+002, 1.27699501e+002, 1.89511658e+002,
           1.25816605e+002, 2.31050888e+002, 1.24260918e+002,
           2.74076721e+002, 1.23023209e+002, 3.17643005e+002,
           1.22288109e+002, 3.61785889e+002, 1.22105164e+002,
           4.06142670e+002, 1.22401566e+002, 4.49623962e+002,
           1.23246025e+002, 4.92677216e+002, 1.24087708e+002,
           1.48706085e+002, 1.69077423e+002, 1.88827805e+002,
           1.67750443e+002, 2.30439865e+002, 1.66769333e+002,
           2.73830933e+002, 1.65871170e+002, 3.17596741e+002,
           1.65410919e+002, 3.61983459e+002, 1.65327866e+002,
           4.06748322e+002, 1.65463974e+002, 4.50450226e+002,
           1.66126526e+002, 4.93614655e+002, 1.66970413e+002,
           1.48312607e+002, 2.11499451e+002, 1.88574097e+002,
           2.10860214e+002, 2.30130676e+002, 2.10261612e+002,
           2.73557709e+002, 2.09837143e+002, 3.17542572e+002,
           2.09633057e+002, 3.62091248e+002, 2.09732620e+002,
           4.06934570e+002, 2.09926758e+002, 4.50914612e+002,
           2.10320221e+002, 4.94044495e+002, 2.10900925e+002,
           1.48613831e+002, 2.53997177e+002, 1.88797791e+002,
           2.53912842e+002, 2.30240204e+002, 2.53975067e+002,
           2.73746704e+002, 2.54010208e+002, 3.17718262e+002,
           2.54106003e+002, 3.62188965e+002, 2.54205475e+002,
           4.06908783e+002, 2.54317505e+002, 4.50824951e+002,
           2.54539490e+002, 4.93825714e+002, 2.54753876e+002,
           1.49541687e+002, 2.96404175e+002, 1.89357727e+002,
           2.97117523e+002, 2.30807007e+002, 2.97805603e+002,
           2.74325470e+002, 2.97966522e+002, 3.18042206e+002,
           2.98304535e+002, 3.62105774e+002, 2.98552643e+002,
           4.06672272e+002, 2.98572418e+002, 4.50363068e+002,
           2.98569550e+002, 4.93109894e+002, 2.98516205e+002,
           1.50883698e+002, 3.38493195e+002, 1.90633621e+002,
           3.39862610e+002, 2.31920990e+002, 3.40869415e+002,
           2.74971252e+002, 3.41453766e+002, 3.18235229e+002,
           3.41952637e+002, 3.62063477e+002, 3.42314026e+002,
           4.06098938e+002, 3.42221802e+002, 4.49477386e+002,
           3.42063812e+002, 4.91864716e+002, 3.41727600e+002,
           2.36129852e+002, 3.92798004e+002, 2.34999939e+002,
           3.56118683e+002, 2.34376099e+002, 3.18607025e+002,
           2.33822159e+002, 2.80400696e+002, 2.33565445e+002,
           2.42213104e+002, 2.33583069e+002, 2.03937286e+002,
           2.34028824e+002, 1.65756607e+002, 2.34613373e+002,
           1.28586639e+002, 2.35190308e+002, 9.18279037e+001,
           2.73031616e+002, 3.93267242e+002, 2.72295166e+002,
           3.56342743e+002, 2.71799347e+002, 3.18847412e+002,
           2.71418854e+002, 2.80287872e+002, 2.71161469e+002,
           2.41881134e+002, 2.71248962e+002, 2.03348145e+002,
           2.71379303e+002, 1.64895874e+002, 2.71946045e+002,
           1.27450935e+002, 2.72322418e+002, 9.06900787e+001,
           3.10670715e+002, 3.93568848e+002, 3.10389160e+002,
           3.56545959e+002, 3.10084625e+002, 3.18814514e+002,
           3.09801544e+002, 2.80242737e+002, 3.09678711e+002,
           2.41574814e+002, 3.09779663e+002, 2.02989838e+002,
           3.09842712e+002, 1.64338043e+002, 3.10076782e+002,
           1.26870911e+002, 3.10243286e+002, 8.98413315e+001,
           3.48618134e+002, 3.93563202e+002, 3.48617065e+002,
           3.56472382e+002, 3.48608795e+002, 3.18855621e+002,
           3.48544556e+002, 2.80011017e+002, 3.48556396e+002,
           2.41388168e+002, 3.48585388e+002, 2.02692429e+002,
           3.48435089e+002, 1.64099731e+002, 3.48442902e+002,
           1.26549957e+002, 3.48338043e+002, 8.98002014e+001,
           3.86625610e+002, 3.93188599e+002, 3.87047729e+002,
           3.56377594e+002, 3.87306274e+002, 3.18714752e+002,
           3.87337799e+002, 2.79868896e+002, 3.87402740e+002,
           2.41228760e+002, 3.87295166e+002, 2.02695313e+002,
           3.87030273e+002, 1.64203415e+002, 3.86741211e+002,
           1.26606262e+002, 3.86337311e+002, 8.99655075e+001,
           4.24534088e+002, 3.92702545e+002, 4.25310822e+002,
           3.55900452e+002, 4.25869019e+002, 3.18160614e+002,
           4.25909790e+002, 2.79615753e+002, 4.25977295e+002,
           2.41165100e+002, 4.25826477e+002, 2.02876389e+002,
           4.25331665e+002, 1.64527618e+002, 4.24775787e+002,
           1.27097328e+002, 4.23985138e+002, 9.08176651e+001,
           1.79142670e+002, 1.58573654e+002, 2.12791580e+002,
           1.56291031e+002, 2.47140106e+002, 1.54265656e+002,
           2.82607300e+002, 1.52373688e+002, 3.18175507e+002,
           1.50692184e+002, 3.54185852e+002, 1.49404175e+002,
           3.90455200e+002, 1.48229370e+002, 4.26106689e+002,
           1.47507843e+002, 4.61576141e+002, 1.46712479e+002,
           1.80388336e+002, 1.93027603e+002, 2.14026459e+002,
           1.91128204e+002, 2.48376541e+002, 1.89414978e+002,
           2.83795807e+002, 1.87720856e+002, 3.19472473e+002,
           1.86192383e+002, 3.55483826e+002, 1.84929199e+002,
           3.91970764e+002, 1.83747040e+002, 4.27654572e+002,
           1.82931534e+002, 4.63295227e+002, 1.81977234e+002,
           1.81914261e+002, 2.27955460e+002, 2.15291260e+002,
           2.26512482e+002, 2.49628265e+002, 2.25067520e+002,
           2.85066406e+002, 2.23593185e+002, 3.20846680e+002,
           2.22337708e+002, 3.56862885e+002, 2.21191040e+002,
           3.93279907e+002, 2.19905640e+002, 4.29202271e+002,
           2.18870361e+002, 4.64728424e+002, 2.17972977e+002,
           1.83496948e+002, 2.62963226e+002, 2.16930527e+002,
           2.61755219e+002, 2.51115829e+002, 2.60777222e+002,
           2.86553406e+002, 2.59500336e+002, 3.22299896e+002,
           2.58380737e+002, 3.58307648e+002, 2.57236694e+002,
           3.94551819e+002, 2.56009125e+002, 4.30358948e+002,
           2.54925797e+002, 4.65684998e+002, 2.54021484e+002,
           1.85461685e+002, 2.97687378e+002, 2.18712234e+002,
           2.96999207e+002, 2.52770218e+002, 2.96270752e+002,
           2.88213776e+002, 2.95168213e+002, 3.23698334e+002,
           2.94233032e+002, 3.59477722e+002, 2.93170715e+002,
           3.95647766e+002, 2.91897400e+002, 4.31309845e+002,
           2.90856995e+002, 4.66494110e+002, 2.89726410e+002,
           1.87661331e+002, 3.32186188e+002, 2.20767746e+002,
           3.31906250e+002, 2.54839096e+002, 3.31398651e+002,
           2.89963745e+002, 3.30524139e+002, 3.25207642e+002,
           3.29771820e+002, 3.60686035e+002, 3.28762695e+002,
           3.96576447e+002, 3.27542206e+002, 4.31994415e+002,
           3.26294189e+002, 4.66894653e+002, 3.24949921e+002,
           2.03543015e+002, 1.77473557e+002, 2.32777847e+002,
           1.74712509e+002, 2.62628723e+002, 1.72331970e+002,
           2.93045898e+002, 1.69686768e+002, 3.23527618e+002,
           1.67496246e+002, 3.54206787e+002, 1.65446075e+002,
           3.85180176e+002, 1.63360580e+002, 4.15484253e+002,
           1.61536423e+002, 4.45720947e+002, 1.59896164e+002,
           2.05864395e+002, 2.07228104e+002, 2.35242096e+002,
           2.04699326e+002, 2.64853973e+002, 2.02407455e+002,
           2.95353882e+002, 1.99972321e+002, 3.25811890e+002,
           1.97671921e+002, 3.56471252e+002, 1.95763168e+002,
           3.87280548e+002, 1.93597977e+002, 4.17615814e+002,
           1.91867371e+002, 4.48018677e+002, 1.90067413e+002,
           2.08421249e+002, 2.37166977e+002, 2.37513824e+002,
           2.34982773e+002, 2.67261261e+002, 2.32802841e+002,
           2.97555817e+002, 2.30466080e+002, 3.28118103e+002,
           2.28462463e+002, 3.58699707e+002, 2.26417038e+002,
           3.89468842e+002, 2.24356827e+002, 4.19895996e+002,
           2.22421921e+002, 4.50077850e+002, 2.20683517e+002,
           2.11095444e+002, 2.66940186e+002, 2.40241348e+002,
           2.64970093e+002, 2.69563019e+002, 2.63153290e+002,
           2.99863464e+002, 2.60983551e+002, 3.30282440e+002,
           2.58911560e+002, 3.60724792e+002, 2.56935730e+002,
           3.91487915e+002, 2.54799423e+002, 4.21789093e+002,
           2.52929688e+002, 4.51818481e+002, 2.51059357e+002,
           2.13829117e+002, 2.96591217e+002, 2.42742859e+002,
           2.94884583e+002, 2.72209076e+002, 2.93215668e+002,
           3.02402985e+002, 2.91230591e+002, 3.32536072e+002,
           2.89165192e+002, 3.62860901e+002, 2.87413605e+002,
           3.93481842e+002, 2.85199615e+002, 4.23728851e+002,
           2.83277496e+002, 4.53453094e+002, 2.81229309e+002,
           2.16799316e+002, 3.25975220e+002, 2.45605515e+002,
           3.24619904e+002, 2.74777344e+002, 3.22958679e+002,
           3.04762817e+002, 3.21008057e+002, 3.34797150e+002,
           3.19291443e+002, 3.65005798e+002, 3.17295044e+002,
           3.95311981e+002, 3.15296021e+002, 4.25312592e+002,
           3.13086945e+002, 4.54931152e+002, 3.11027130e+002,
           2.60550232e+002, 3.70739563e+002, 2.59674011e+002,
           3.42115936e+002, 2.58910492e+002, 3.13278015e+002,
           2.58195618e+002, 2.84013580e+002, 2.57727173e+002,
           2.55017166e+002, 2.57326263e+002, 2.25760986e+002,
           2.57096619e+002, 1.96577972e+002, 2.57031860e+002,
           1.68026199e+002, 2.56873383e+002, 1.39550308e+002,
           2.89019318e+002, 3.70481354e+002, 2.88355560e+002,
           3.41833252e+002, 2.87601471e+002, 3.12872925e+002,
           2.87057190e+002, 2.83485535e+002, 2.86599762e+002,
           2.54255096e+002, 2.86174438e+002, 2.25023285e+002,
           2.85775940e+002, 1.95715347e+002, 2.85577087e+002,
           1.66989502e+002, 2.85395477e+002, 1.38597382e+002,
           3.18072754e+002, 3.70118317e+002, 3.17432709e+002,
           3.41398743e+002, 3.16917267e+002, 3.12476044e+002,
           3.16284363e+002, 2.83001587e+002, 3.15799072e+002,
           2.53725845e+002, 3.15411957e+002, 2.24337708e+002,
           3.15070374e+002, 1.95034119e+002, 3.14736847e+002,
           1.66195313e+002, 3.14439789e+002, 1.37797058e+002,
           3.47083588e+002, 3.69678101e+002, 3.46717987e+002,
           3.40949524e+002, 3.46185303e+002, 3.12009857e+002,
           3.45728088e+002, 2.82454071e+002, 3.45226624e+002,
           2.53109863e+002, 3.44883606e+002, 2.23839539e+002,
           3.44373535e+002, 1.94399933e+002, 3.43879852e+002,
           1.65690643e+002, 3.43438629e+002, 1.37252930e+002,
           3.76341522e+002, 3.68972321e+002, 3.76086884e+002,
           3.40412842e+002, 3.75708893e+002, 3.11398376e+002,
           3.75143494e+002, 2.81901520e+002, 3.74762970e+002,
           2.52577988e+002, 3.74223969e+002, 2.23348221e+002,
           3.73600891e+002, 1.93979538e+002, 3.72983917e+002,
           1.65201294e+002, 3.72517273e+002, 1.36871033e+002,
           4.05512115e+002, 3.68243225e+002, 4.05366333e+002,
           3.39678650e+002, 4.05090027e+002, 3.10679108e+002,
           4.04612366e+002, 2.81203522e+002, 4.04152649e+002,
           2.52051605e+002, 4.03539703e+002, 2.22930420e+002,
           4.02903351e+002, 1.93625381e+002, 4.02272827e+002,
           1.65004440e+002, 4.01353333e+002, 1.36796814e+002 ]
    View Code

    (注:我这里使用的是最新版本Opencv4.x,其他版本的标定文件不一定兼容,例如我使用Opencv3中的camera_calibration.cpp在Opencv4.x环境下就无法编译通过)

    编译方式采用Cmake,CMakeLists.txt脚本如下:

    1 cmake_minimum_required(VERSION 2.8)
    2 
    3 project(main_calibration)
    4 
    5 find_package(OpenCV REQUIRED)
    6 include_directories(${OpenCV_INCLUDE_DIRS})
    7 
    8 add_executable(main_calibration camera_calibration.cpp)
    9 target_link_libraries(main_calibration ${OpenCV_LIBS})

    编译流程如下:

    Step1:本地主程序camera_calibration.cpp文件目录下新建编译临时文件夹build.(CMakeLists.txt和主程序文件在同一目录下).

    Step2:切换目录到build文件夹下,使用cmake命令生成对应的Makefile以及预编译临时文件.

    Step3:使用make命令进行编译,编译完成后自动在build文件夹下生成可执行文件main_calibration.

    mkdir build
    cd build
    cmake ..
    make

    接下来修改可执行文件main_calibration可执行文件的参数文件in_VID5.xml

    Line5: <BoardSize_Width>8</BoardSize_Width> # 设置Chess标定板宽度方向角点数.(注意是inner方块的角点数)
    Line6: <BoardSize_Height>6</BoardSize_Height> # 设置Chess标定板高度方向角点数.(注意inner角点表示出了最外侧一圈方格的部分)
    Line9: <Square_Size>40</Square_Size> # 实际物理棋盘上方块的边长(Units:mm)
    Line12: <Calibration_Pattern>"CHESSBARD"</Calibration_Pattern> # 一般这里都设置为棋盘,如果你的是其他标定板请使用其他参数.
    Line19:<Input>"absolute_path/VID5.xml"</Input> # 这里如果设置为1表示使用Camera来现场采集图片进行标定,一般来说可以设置VID5.xml文件路径,程序将会通过VID5.xml文件中标定图片路径读取图片,这里需要配置好VID5.xml文件.
    Line24:<Input_Delay>100</Input_Delay> # 如果使用Camera来实时采集标定图像,则这个参数用来设定两次采集动作之间的时间间隔,如果不采用Camera则不用设置.
    Line27:<Calibrate_NrOfFrameToUse><Calibrate_NrOfFrameToUse> # 设置用来标定的有效图像数量,25表示使用能够找到角点并满足角点要求的25张标定图进行相机标定.
    Line37: <Write_outputFileName>"out_camera_data.yml"</Write_outputFileName> # 设置标定完成后参数保存的路径以及文件,注意文件后缀名为.yml.
    Line47: <Calibrate_UseFisheyeModel>1</Calibrate_UseFishModel> # 如果需要标定的为鱼眼镜头,则需要设置为1.

    根据in_VID5.xml中的设置,如果选用已经拍摄好的照片则需要修改VID5.xml文件内容,添加标定图像的绝对路径:

    如图上所示,一般需要采集足够多的图像,以保证能够找到足够用来标定Camera的图像,如果不满足要求则会出现如下错误(请调整光照等条件重新采集图像):

    完成基本参数文件设置之后开始运行:

    ./main_calibration ../in_VID5.xml

    运行过程截图如下:

     如上左图表示图像角点提取的情况,右图表示矫正之后的结果。

    三、使用标定结果矫正畸变

    参考程序如下,只采用了径向畸变矫正(注:完成了彩色图像畸变校正以及单通道灰度图像矫正):

    在插值过程中使用了最近邻差值算法,如使用其他算法请自行封装调用。

     1 #include <iostream>
     2 #include <string.h>
     3 #include <opencv2/opencv.hpp>
     4 
     5 using namespace std;
     6 using namespace cv;
     7 
     8 #define SHOW 0
     9 int main(void)
    10 {
    11   string img_path = "../CSICamera0-31.jpg";
    12   string res_path = "../undistort.jpg";
    13   cout << "Begin to Calibrate the image file:" << img_path << endl;
    14   double k1=-0.3403,k2=0.1520125;
    15   double fx=784.59,fy=784.59,cx=640,cy=480;
    16 
    17 #if SHOW
    18   namedWindow("OriImage", WINDOW_AUTOSIZE);
    19   namedWindow("ResImage", WINDOW_AUTOSIZE);
    20 #endif
    21 
    22   Mat Ori = imread(img_path);
    23 #if SHOW
    24   imshow("OriImage",Ori);
    25 #endif
    26 
    27   int rows = Ori.rows, cols = Ori.cols,row,col;
    28   double row_undistort,col_undistort,x1,x2,y1,y2,r;
    29   Mat gry_undistort = Mat(rows,cols,CV_8UC1);
    30   Mat Gry = Mat(rows,cols,CV_8UC1);
    31   Mat img_undistort = Mat(rows,cols,CV_8UC3);
    32 
    33   cvtColor(Ori,Gry,COLOR_BGR2GRAY);
    34 
    35   for(row=0;row<rows;row++){
    36     for(col=0;col<cols;col++){
    37       x1 = (col-cx)/fx; // calc center x
    38       y1 = (row-cy)/fy; // calc center y
    39       r = pow(x1,2) + pow(y1,2); // calc center distance
    40       x2 = x1*(1+k1*r+k2*pow(r,2)); // undistort img pos-col
    41       y2 = y1*(1+k1*r+k2*pow(r,2)); // undistort img pos-row
    42       row_undistort = fy*y2 + cy;
    43       col_undistort = fx*x2 + cx;
    44 
    45       if(row_undistort >=0 && col_undistort >= 0 && row_undistort < rows && col_undistort < cols){
    46         gry_undistort.at<uchar>(row,col) = Gry.at<uchar>((int)row_undistort,(int)col_undistort);
    47         img_undistort.at<Vec3b>(row,col)[0] = Ori.at<Vec3b>((int)row_undistort,(int)col_undistort)[0];
    48         img_undistort.at<Vec3b>(row,col)[1] = Ori.at<Vec3b>((int)row_undistort,(int)col_undistort)[1];
    49         img_undistort.at<Vec3b>(row,col)[2] = Ori.at<Vec3b>((int)row_undistort,(int)col_undistort)[2];
    50       }else{
    51         gry_undistort.at<uchar>(row,col) = 0;
    52         img_undistort.at<Vec3b>(row,col)[0] = 0;
    53         img_undistort.at<Vec3b>(row,col)[1] = 0;
    54         img_undistort.at<Vec3b>(row,col)[2] = 0;
    55       }
    56     }
    57   }
    58 
    59 #if SHOW
    60   imshow("ResImage",img_undistort);
    61   while(1){
    62     int keycode = waitKey(30) & 0xff ;
    63     if (keycode == 27) break ;
    64   }
    65   destroyAllWindows();
    66 #else
    67   imwrite(res_path,img_undistort);
    68 #endif
    69 
    70   return 0;
    71 }

    实际处理结果:

    使用cuda加速的畸变矫正算法:传送门

    四、参考资料

    畸变矫正Opencv代码打包Baidu-Pan下载地址:https://pan.baidu.com/s/1icrwvNws2N1j7b7bjGxPNA  提取码:6koe 

    Matlab标定工具箱使用官方参考教程:http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/example.html

    图像矫正及畸变参数使用:https://blog.csdn.net/weixin_38009585/article/details/82356022

  • 相关阅读:
    e家modem共享上网方法
    千里奔丧
    解决dbvisualizer乱码问题Ubuntu手记之软件
    目录结构Ubuntu手记之系统配置
    javaFTP编程
    JAVA运行环境设置
    VPNCUbuntu手记之软件
    清洗节气门
    IPMSGUbuntu手记之软件
    AIX下的JAVA线程监视
  • 原文地址:https://www.cnblogs.com/uestc-mm/p/12703897.html
Copyright © 2020-2023  润新知