omni_calibration.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #include "opencv2/ccalib/omnidir.hpp"
  2. #include "opencv2/core.hpp"
  3. #include "opencv2/imgproc.hpp"
  4. #include "opencv2/calib3d.hpp"
  5. #include "opencv2/highgui.hpp"
  6. #include <vector>
  7. #include <iostream>
  8. #include <string>
  9. #include <time.h>
  10. using namespace cv;
  11. using namespace std;
  12. static void calcChessboardCorners(const Size &boardSize, const Size2d &squareSize, Mat& corners)
  13. {
  14. // corners has type of CV_64FC3
  15. corners.release();
  16. int n = boardSize.width * boardSize.height;
  17. corners.create(n, 1, CV_64FC3);
  18. Vec3d *ptr = corners.ptr<Vec3d>();
  19. for (int i = 0; i < boardSize.height; ++i)
  20. {
  21. for (int j = 0; j < boardSize.width; ++j)
  22. {
  23. ptr[i*boardSize.width + j] = Vec3d(double(j * squareSize.width), double(i * squareSize.height), 0.0);
  24. }
  25. }
  26. }
  27. static bool detecChessboardCorners(const vector<string>& list, vector<string>& list_detected,
  28. vector<Mat>& imagePoints, Size boardSize, Size& imageSize)
  29. {
  30. imagePoints.resize(0);
  31. list_detected.resize(0);
  32. int n_img = (int)list.size();
  33. Mat img;
  34. for(int i = 0; i < n_img; ++i)
  35. {
  36. cout << list[i] << "... ";
  37. Mat points;
  38. img = imread(list[i], IMREAD_GRAYSCALE);
  39. bool found = findChessboardCorners( img, boardSize, points);
  40. if (found)
  41. {
  42. if (points.type() != CV_64FC2)
  43. points.convertTo(points, CV_64FC2);
  44. imagePoints.push_back(points);
  45. list_detected.push_back(list[i]);
  46. }
  47. cout << (found ? "FOUND" : "NO") << endl;
  48. }
  49. if (!img.empty())
  50. imageSize = img.size();
  51. if (imagePoints.size() < 3)
  52. return false;
  53. else
  54. return true;
  55. }
  56. static bool readStringList( const string& filename, vector<string>& l )
  57. {
  58. l.resize(0);
  59. FileStorage fs(filename, FileStorage::READ);
  60. if( !fs.isOpened() )
  61. return false;
  62. FileNode n = fs.getFirstTopLevelNode();
  63. if( n.type() != FileNode::SEQ )
  64. return false;
  65. FileNodeIterator it = n.begin(), it_end = n.end();
  66. for( ; it != it_end; ++it )
  67. l.push_back((string)*it);
  68. return true;
  69. }
  70. static void saveCameraParams( const string & filename, int flags, const Mat& cameraMatrix,
  71. const Mat& distCoeffs, const double xi, const vector<Vec3d>& rvecs, const vector<Vec3d>& tvecs,
  72. vector<string> detec_list, const Mat& idx, const double rms, const vector<Mat>& imagePoints)
  73. {
  74. FileStorage fs( filename, FileStorage::WRITE );
  75. time_t tt;
  76. time( &tt );
  77. struct tm *t2 = localtime( &tt );
  78. char buf[1024];
  79. strftime( buf, sizeof(buf)-1, "%c", t2 );
  80. fs << "calibration_time" << buf;
  81. if ( !rvecs.empty())
  82. fs << "nFrames" << (int)rvecs.size();
  83. if ( flags != 0)
  84. {
  85. sprintf( buf, "flags: %s%s%s%s%s%s%s%s%s",
  86. flags & omnidir::CALIB_USE_GUESS ? "+use_intrinsic_guess" : "",
  87. flags & omnidir::CALIB_FIX_SKEW ? "+fix_skew" : "",
  88. flags & omnidir::CALIB_FIX_K1 ? "+fix_k1" : "",
  89. flags & omnidir::CALIB_FIX_K2 ? "+fix_k2" : "",
  90. flags & omnidir::CALIB_FIX_P1 ? "+fix_p1" : "",
  91. flags & omnidir::CALIB_FIX_P2 ? "+fix_p2" : "",
  92. flags & omnidir::CALIB_FIX_XI ? "+fix_xi" : "",
  93. flags & omnidir::CALIB_FIX_GAMMA ? "+fix_gamma" : "",
  94. flags & omnidir::CALIB_FIX_CENTER ? "+fix_center" : "");
  95. //cvWriteComment( *fs, buf, 0 );
  96. }
  97. fs << "flags" << flags;
  98. fs << "camera_matrix" << cameraMatrix;
  99. fs << "distortion_coefficients" << distCoeffs;
  100. fs << "xi" << xi;
  101. //cvWriteComment( *fs, "names of images that are acturally used in calibration", 0 );
  102. fs << "used_imgs" << "[";
  103. for (int i = 0; i < (int)idx.total(); ++i)
  104. {
  105. fs << detec_list[(int)idx.at<int>(i)];
  106. }
  107. fs << "]";
  108. if ( !rvecs.empty() && !tvecs.empty() )
  109. {
  110. Mat rvec_tvec((int)rvecs.size(), 6, CV_64F);
  111. for (int i = 0; i < (int)rvecs.size(); ++i)
  112. {
  113. Mat(rvecs[i]).reshape(1, 1).copyTo(rvec_tvec(Rect(0, i, 3, 1)));
  114. Mat(tvecs[i]).reshape(1, 1).copyTo(rvec_tvec(Rect(3, i, 3, 1)));
  115. }
  116. //cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
  117. fs << "extrinsic_parameters" << rvec_tvec;
  118. }
  119. fs << "rms" << rms;
  120. if ( !imagePoints.empty() )
  121. {
  122. Mat imageMat((int)imagePoints.size(), (int)imagePoints[0].total(), CV_64FC2);
  123. for (int i = 0; i < (int)imagePoints.size(); ++i)
  124. {
  125. Mat r = imageMat.row(i).reshape(2, imageMat.cols);
  126. Mat imagei(imagePoints[i]);
  127. imagei.copyTo(r);
  128. }
  129. fs << "image_points" << imageMat;
  130. }
  131. }
  132. int main(int argc, char** argv)
  133. {
  134. cv::CommandLineParser parser(argc, argv,
  135. "{w||board width}"
  136. "{h||board height}"
  137. "{sw|1.0|square width}"
  138. "{sh|1.0|square height}"
  139. "{o|out_camera_params.xml|output file}"
  140. "{fs|false|fix skew}"
  141. "{fp|false|fix principal point at the center}"
  142. "{@input||input file - xml file with a list of the images, created with cpp-example-imagelist_creator tool}"
  143. "{help||show help}"
  144. );
  145. parser.about("This is a sample for omnidirectional camera calibration. Example command line:\n"
  146. " omni_calibration -w=6 -h=9 -sw=80 -sh=80 imagelist.xml \n");
  147. if (parser.has("help") || !parser.has("w") || !parser.has("h"))
  148. {
  149. parser.printMessage();
  150. return 0;
  151. }
  152. Size boardSize(parser.get<int>("w"), parser.get<int>("h"));
  153. Size2d squareSize(parser.get<double>("sw"), parser.get<double>("sh"));
  154. int flags = 0;
  155. if (parser.get<bool>("fs"))
  156. flags |= omnidir::CALIB_FIX_SKEW;
  157. if (parser.get<bool>("fp"))
  158. flags |= omnidir::CALIB_FIX_CENTER;
  159. const string outputFilename = parser.get<string>("o");
  160. const string inputFilename = parser.get<string>(0);
  161. if (!parser.check())
  162. {
  163. parser.printErrors();
  164. return -1;
  165. }
  166. // get image name list
  167. vector<string> image_list, detec_list;
  168. if(!readStringList(inputFilename, image_list))
  169. {
  170. cout << "Can not read imagelist" << endl;
  171. return -1;
  172. }
  173. // find corners in images
  174. // some images may be failed in automatic corner detection, passed cases are in detec_list
  175. cout << "Detecting chessboards (" << image_list.size() << ")" << endl;
  176. vector<Mat> imagePoints;
  177. Size imageSize;
  178. if(!detecChessboardCorners(image_list, detec_list, imagePoints, boardSize, imageSize))
  179. {
  180. cout << "Not enough corner detected images" << endl;
  181. return -1;
  182. }
  183. // calculate object coordinates
  184. vector<Mat> objectPoints;
  185. Mat object;
  186. calcChessboardCorners(boardSize, squareSize, object);
  187. for(int i = 0; i < (int)detec_list.size(); ++i)
  188. objectPoints.push_back(object);
  189. // run calibration, some images are discarded in calibration process because they are failed
  190. // in initialization. Retained image indexes are in idx variable.
  191. Mat K, D, xi, idx;
  192. vector<Vec3d> rvecs, tvecs;
  193. double _xi, rms;
  194. TermCriteria criteria(3, 200, 1e-8);
  195. rms = omnidir::calibrate(objectPoints, imagePoints, imageSize, K, xi, D, rvecs, tvecs, flags, criteria, idx);
  196. _xi = xi.at<double>(0);
  197. cout << "Saving camera params to " << outputFilename << endl;
  198. saveCameraParams(outputFilename, flags, K, D, _xi,
  199. rvecs, tvecs, detec_list, idx, rms, imagePoints);
  200. }