162 lines
5.3 KiB
C++
162 lines
5.3 KiB
C++
|
#include "opencv2/ccalib/randpattern.hpp"
|
||
|
#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;
|
||
|
|
||
|
const char * usage =
|
||
|
"\n example command line for calibrate a camera by random pattern. \n"
|
||
|
" random_pattern_calibration -pw 600 -ph 850 -mm 20 image_list.xml \n"
|
||
|
"\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"
|
||
|
"Usage: random_pattern_calibration\n"
|
||
|
" -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)
|
||
|
{
|
||
|
const char* inputFilename = 0;
|
||
|
const char* outputFilename = "out_camera_params.xml";
|
||
|
vector<string> imglist;
|
||
|
vector<Mat> vecImg;
|
||
|
int flags = 0;
|
||
|
float patternWidth = 0.0f, patternHeight = 0.0f;
|
||
|
int nMiniMatches = 0;
|
||
|
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)
|
||
|
{
|
||
|
if (sscanf(argv[++i], "%d", &nMiniMatches) != 1 || nMiniMatches < 15)
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
randpattern::RandomPatternCornerFinder finder(patternWidth, patternHeight, nMiniMatches);
|
||
|
finder.loadPattern(pattern);
|
||
|
finder.computeObjectImagePoints(vecImg);
|
||
|
vector<Mat> objectPoints = finder.getObjectPoints();
|
||
|
vector<Mat> imagePoints = finder.getImagePoints();
|
||
|
|
||
|
Mat K;
|
||
|
Mat D;
|
||
|
vector<Mat> rvec, tvec;
|
||
|
double rms = calibrateCamera(objectPoints, imagePoints, vecImg[0].size(), K, D, rvec, tvec);
|
||
|
saveCameraParams(outputFilename, vecImg[0].size(), patternWidth, patternHeight, flags, K, D, rvec, tvec, rms);
|
||
|
}
|