#include "opencv2/ccalib/omnidir.hpp" #include "opencv2/core.hpp" #include "opencv2/imgproc.hpp" #include "opencv2/calib3d.hpp" #include "opencv2/highgui.hpp" #include #include #include #include using namespace cv; using namespace std; static void calcChessboardCorners(const Size &boardSize, const Size2d &squareSize, Mat& corners) { // corners has type of CV_64FC3 corners.release(); int n = boardSize.width * boardSize.height; corners.create(n, 1, CV_64FC3); Vec3d *ptr = corners.ptr(); for (int i = 0; i < boardSize.height; ++i) { for (int j = 0; j < boardSize.width; ++j) { ptr[i*boardSize.width + j] = Vec3d(double(j * squareSize.width), double(i * squareSize.height), 0.0); } } } static bool detecChessboardCorners(const vector& list, vector& list_detected, vector& imagePoints, Size boardSize, Size& imageSize) { imagePoints.resize(0); list_detected.resize(0); int n_img = (int)list.size(); Mat img; for(int i = 0; i < n_img; ++i) { cout << list[i] << "... "; Mat points; img = imread(list[i], IMREAD_GRAYSCALE); bool found = findChessboardCorners( img, boardSize, points); if (found) { if (points.type() != CV_64FC2) points.convertTo(points, CV_64FC2); imagePoints.push_back(points); list_detected.push_back(list[i]); } cout << (found ? "FOUND" : "NO") << endl; } if (!img.empty()) imageSize = img.size(); if (imagePoints.size() < 3) return false; else return true; } static bool readStringList( const string& filename, vector& 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, int flags, const Mat& cameraMatrix, const Mat& distCoeffs, const double xi, const vector& rvecs, const vector& tvecs, vector detec_list, const Mat& idx, const double rms, const vector& imagePoints) { 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(); if ( flags != 0) { sprintf( buf, "flags: %s%s%s%s%s%s%s%s%s", flags & omnidir::CALIB_USE_GUESS ? "+use_intrinsic_guess" : "", flags & omnidir::CALIB_FIX_SKEW ? "+fix_skew" : "", flags & omnidir::CALIB_FIX_K1 ? "+fix_k1" : "", flags & omnidir::CALIB_FIX_K2 ? "+fix_k2" : "", flags & omnidir::CALIB_FIX_P1 ? "+fix_p1" : "", flags & omnidir::CALIB_FIX_P2 ? "+fix_p2" : "", flags & omnidir::CALIB_FIX_XI ? "+fix_xi" : "", flags & omnidir::CALIB_FIX_GAMMA ? "+fix_gamma" : "", flags & omnidir::CALIB_FIX_CENTER ? "+fix_center" : ""); //cvWriteComment( *fs, buf, 0 ); } fs << "flags" << flags; fs << "camera_matrix" << cameraMatrix; fs << "distortion_coefficients" << distCoeffs; fs << "xi" << xi; //cvWriteComment( *fs, "names of images that are acturally used in calibration", 0 ); fs << "used_imgs" << "["; for (int i = 0; i < (int)idx.total(); ++i) { fs << detec_list[(int)idx.at(i)]; } fs << "]"; if ( !rvecs.empty() && !tvecs.empty() ) { Mat rvec_tvec((int)rvecs.size(), 6, CV_64F); for (int i = 0; i < (int)rvecs.size(); ++i) { Mat(rvecs[i]).reshape(1, 1).copyTo(rvec_tvec(Rect(0, i, 3, 1))); Mat(tvecs[i]).reshape(1, 1).copyTo(rvec_tvec(Rect(3, i, 3, 1))); } //cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 ); fs << "extrinsic_parameters" << rvec_tvec; } fs << "rms" << rms; if ( !imagePoints.empty() ) { Mat imageMat((int)imagePoints.size(), (int)imagePoints[0].total(), CV_64FC2); for (int i = 0; i < (int)imagePoints.size(); ++i) { Mat r = imageMat.row(i).reshape(2, imageMat.cols); Mat imagei(imagePoints[i]); imagei.copyTo(r); } fs << "image_points" << imageMat; } } int main(int argc, char** argv) { cv::CommandLineParser parser(argc, argv, "{w||board width}" "{h||board height}" "{sw|1.0|square width}" "{sh|1.0|square height}" "{o|out_camera_params.xml|output file}" "{fs|false|fix skew}" "{fp|false|fix principal point at the center}" "{@input||input file - xml file with a list of the images, created with cpp-example-imagelist_creator tool}" "{help||show help}" ); parser.about("This is a sample for omnidirectional camera calibration. Example command line:\n" " omni_calibration -w=6 -h=9 -sw=80 -sh=80 imagelist.xml \n"); if (parser.has("help") || !parser.has("w") || !parser.has("h")) { parser.printMessage(); return 0; } Size boardSize(parser.get("w"), parser.get("h")); Size2d squareSize(parser.get("sw"), parser.get("sh")); int flags = 0; if (parser.get("fs")) flags |= omnidir::CALIB_FIX_SKEW; if (parser.get("fp")) flags |= omnidir::CALIB_FIX_CENTER; const string outputFilename = parser.get("o"); const string inputFilename = parser.get(0); if (!parser.check()) { parser.printErrors(); return -1; } // get image name list vector image_list, detec_list; if(!readStringList(inputFilename, image_list)) { cout << "Can not read imagelist" << endl; return -1; } // find corners in images // some images may be failed in automatic corner detection, passed cases are in detec_list cout << "Detecting chessboards (" << image_list.size() << ")" << endl; vector imagePoints; Size imageSize; if(!detecChessboardCorners(image_list, detec_list, imagePoints, boardSize, imageSize)) { cout << "Not enough corner detected images" << endl; return -1; } // calculate object coordinates vector objectPoints; Mat object; calcChessboardCorners(boardSize, squareSize, object); for(int i = 0; i < (int)detec_list.size(); ++i) objectPoints.push_back(object); // run calibration, some images are discarded in calibration process because they are failed // in initialization. Retained image indexes are in idx variable. Mat K, D, xi, idx; vector rvecs, tvecs; double _xi, rms; TermCriteria criteria(3, 200, 1e-8); rms = omnidir::calibrate(objectPoints, imagePoints, imageSize, K, xi, D, rvecs, tvecs, flags, criteria, idx); _xi = xi.at(0); cout << "Saving camera params to " << outputFilename << endl; saveCameraParams(outputFilename, flags, K, D, _xi, rvecs, tvecs, detec_list, idx, rms, imagePoints); }