random_pattern_calibration.cpp 5.35 KB
Newer Older
baisheng lai's avatar
baisheng lai committed
1
#include "opencv2/ccalib/randpattern.hpp"
2 3 4 5 6 7 8 9 10
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/calib3d.hpp"
#include <vector>
#include <iostream>
#include <time.h>
using namespace std;
using namespace cv;

baisheng lai's avatar
baisheng lai committed
11
const char * usage =
12
    "\n example command line for calibrate a camera by random pattern. \n"
baisheng lai's avatar
baisheng lai committed
13
    "   random_pattern_calibration -pw 600 -ph 850 -mm 20 image_list.xml \n"
14 15 16 17 18 19
    "\n"
    " the file image_list.xml is generated by imagelist_creator as\n"
    "imagelist_creator image_list.xml *.*";
static void help()
{
    printf("\n This is a sample for camera calibration by a random pattern.\n"
baisheng lai's avatar
baisheng lai committed
20
           "Usage: random_pattern_calibration\n"
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
           "    -pw <pattern_width> # the physical width of random pattern\n"
           "    -ph <pattern_height> # the physical height of random pattern\n"
           "    -mm <minimal_match> # minimal number of matches\n"
           "    [-fp ] # fix the principal point at the center \n"
           "    input_data # input data - text file with a list of the images of the board, which is generated by imagelist_creator"
           );
    printf("\n %s", usage);
}

static bool readStringList( const string& filename, vector<string>& l )
{
    l.resize(0);
    FileStorage fs(filename, FileStorage::READ);
    if( !fs.isOpened() )
        return false;
    FileNode n = fs.getFirstTopLevelNode();
    if( n.type() != FileNode::SEQ )
        return false;
    FileNodeIterator it = n.begin(), it_end = n.end();
    for( ; it != it_end; ++it )
        l.push_back((string)*it);
    return true;
}

static void saveCameraParams(const string& filename, Size imageSize, float patternWidth,
    float patternHeight, int flags, const Mat& cameraMatrix, const Mat& distCoeffs,
    const vector<Mat>& rvecs, const vector<Mat>& tvecs, double rms)
{
    FileStorage fs (filename, FileStorage::WRITE );
    time_t tt;
    time( &tt );
    struct tm *t2 = localtime( &tt );
    char buf[1024];
    strftime( buf, sizeof(buf)-1, "%c", t2 );

    fs << "calibration_time" << buf;

    if( !rvecs.empty())
        fs << "nframes" << (int)rvecs.size();

    fs << "image_width" << imageSize.width;
    fs << "image_height" << imageSize.height;
    fs << "pattern_width" << patternWidth;
    fs << "pattern_height" << patternHeight;

    fs << "flags" <<flags;

    fs << "camera_matrix" << cameraMatrix;
    fs << "distortion_coefficients" << distCoeffs;

    fs << "rms" << rms;

    if( !rvecs.empty() && !tvecs.empty() )
    {
        CV_Assert(rvecs[0].type() == tvecs[0].type());
        Mat bigmat((int)rvecs.size(), 6, rvecs[0].type());
        for( int i = 0; i < (int)rvecs.size(); i++ )
        {
            Mat r = bigmat(Range(i, i+1), Range(0,3));
            Mat t = bigmat(Range(i, i+1), Range(3,6));

            CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1);
            CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1);
            //*.t() is MatExpr (not Mat) so we can use assignment operator
            r = rvecs[i].t();
            t = tvecs[i].t();
        }
        //cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
        fs << "extrinsic_parameters" << bigmat;
    }
}

int main(int argc, char** argv)
{
baisheng lai's avatar
baisheng lai committed
95
    const char* inputFilename = 0;
96 97 98 99
    const char* outputFilename = "out_camera_params.xml";
    vector<string> imglist;
    vector<Mat> vecImg;
    int flags = 0;
baisheng lai's avatar
baisheng lai committed
100 101
    float patternWidth = 0.0f, patternHeight = 0.0f;
    int nMiniMatches = 0;
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
    if(argc < 2)
    {
        help();
        return 1;
    }

    for (int i = 1; i < argc; ++i)
    {
        const char* s = argv[i];
        if(strcmp(s, "-pw") == 0)
        {
            if(sscanf(argv[++i], "%f", &patternWidth) != 1 || patternWidth <= 0)
                return fprintf( stderr, "Invalid pattern width\n"), -1;
        }
        else if(strcmp(s, "-ph") == 0)
        {
            if(sscanf(argv[++i], "%f", &patternHeight) != 1 || patternHeight <= 0)
                return fprintf( stderr, "Invalid pattern height\n"), -1;
        }
        else if (strcmp(s, "-mm") == 0)
        {
baisheng lai's avatar
baisheng lai committed
123
            if (sscanf(argv[++i], "%d", &nMiniMatches) != 1 || nMiniMatches < 15)
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
                return fprintf( stderr, "Invalid number of minimal matches or number is too small"), -1;
        }
        else if( strcmp( s, "-fp" ) == 0 )
        {
            flags |= CALIB_FIX_PRINCIPAL_POINT;
        }
        else if( s[0] != '-')
        {
            inputFilename = s;
        }
        else
        {
            return fprintf( stderr, "Unknown option %s\n", s ), -1;
        }
    }

    readStringList(inputFilename, imglist);
    // the first image is the pattern
    Mat pattern = cv::imread(imglist[0], cv::IMREAD_GRAYSCALE);
    for (int i = 1; i < (int)imglist.size(); ++i)
    {
        Mat img;
        img = cv::imread(imglist[i], cv::IMREAD_GRAYSCALE);
        vecImg.push_back(img);
    }

baisheng lai's avatar
baisheng lai committed
150
    randpattern::RandomPatternCornerFinder finder(patternWidth, patternHeight, nMiniMatches);
151 152 153 154
    finder.loadPattern(pattern);
    finder.computeObjectImagePoints(vecImg);
    vector<Mat> objectPoints = finder.getObjectPoints();
    vector<Mat> imagePoints = finder.getImagePoints();
baisheng lai's avatar
baisheng lai committed
155

156 157 158 159
    Mat K;
    Mat D;
    vector<Mat> rvec, tvec;
    double rms = calibrateCamera(objectPoints, imagePoints, vecImg[0].size(), K, D, rvec, tvec);
baisheng lai's avatar
baisheng lai committed
160
    saveCameraParams(outputFilename, vecImg[0].size(), patternWidth, patternHeight, flags, K, D, rvec, tvec, rms);
161
}