decompose_homography.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #include <iostream>
  2. #include <opencv2/core.hpp>
  3. #include <opencv2/highgui.hpp>
  4. #include <opencv2/calib3d.hpp>
  5. using namespace std;
  6. using namespace cv;
  7. namespace
  8. {
  9. enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
  10. void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners, Pattern patternType = CHESSBOARD)
  11. {
  12. corners.resize(0);
  13. switch (patternType) {
  14. case CHESSBOARD:
  15. case CIRCLES_GRID:
  16. for( int i = 0; i < boardSize.height; i++ )
  17. for( int j = 0; j < boardSize.width; j++ )
  18. corners.push_back(Point3f(float(j*squareSize),
  19. float(i*squareSize), 0));
  20. break;
  21. case ASYMMETRIC_CIRCLES_GRID:
  22. for( int i = 0; i < boardSize.height; i++ )
  23. for( int j = 0; j < boardSize.width; j++ )
  24. corners.push_back(Point3f(float((2*j + i % 2)*squareSize),
  25. float(i*squareSize), 0));
  26. break;
  27. default:
  28. CV_Error(Error::StsBadArg, "Unknown pattern type\n");
  29. }
  30. }
  31. Mat computeHomography(const Mat &R_1to2, const Mat &tvec_1to2, const double d_inv, const Mat &normal)
  32. {
  33. Mat homography = R_1to2 + d_inv * tvec_1to2*normal.t();
  34. return homography;
  35. }
  36. void computeC2MC1(const Mat &R1, const Mat &tvec1, const Mat &R2, const Mat &tvec2,
  37. Mat &R_1to2, Mat &tvec_1to2)
  38. {
  39. //c2Mc1 = c2Mo * oMc1 = c2Mo * c1Mo.inv()
  40. R_1to2 = R2 * R1.t();
  41. tvec_1to2 = R2 * (-R1.t()*tvec1) + tvec2;
  42. }
  43. void decomposeHomography(const string &img1Path, const string &img2Path, const Size &patternSize,
  44. const float squareSize, const string &intrinsicsPath)
  45. {
  46. Mat img1 = imread( samples::findFile( img1Path) );
  47. Mat img2 = imread( samples::findFile( img2Path) );
  48. vector<Point2f> corners1, corners2;
  49. bool found1 = findChessboardCorners(img1, patternSize, corners1);
  50. bool found2 = findChessboardCorners(img2, patternSize, corners2);
  51. if (!found1 || !found2)
  52. {
  53. cout << "Error, cannot find the chessboard corners in both images." << endl;
  54. return;
  55. }
  56. //! [compute-poses]
  57. vector<Point3f> objectPoints;
  58. calcChessboardCorners(patternSize, squareSize, objectPoints);
  59. FileStorage fs( samples::findFile( intrinsicsPath ), FileStorage::READ);
  60. Mat cameraMatrix, distCoeffs;
  61. fs["camera_matrix"] >> cameraMatrix;
  62. fs["distortion_coefficients"] >> distCoeffs;
  63. Mat rvec1, tvec1;
  64. solvePnP(objectPoints, corners1, cameraMatrix, distCoeffs, rvec1, tvec1);
  65. Mat rvec2, tvec2;
  66. solvePnP(objectPoints, corners2, cameraMatrix, distCoeffs, rvec2, tvec2);
  67. //! [compute-poses]
  68. //! [compute-camera-displacement]
  69. Mat R1, R2;
  70. Rodrigues(rvec1, R1);
  71. Rodrigues(rvec2, R2);
  72. Mat R_1to2, t_1to2;
  73. computeC2MC1(R1, tvec1, R2, tvec2, R_1to2, t_1to2);
  74. Mat rvec_1to2;
  75. Rodrigues(R_1to2, rvec_1to2);
  76. //! [compute-camera-displacement]
  77. //! [compute-plane-normal-at-camera-pose-1]
  78. Mat normal = (Mat_<double>(3,1) << 0, 0, 1);
  79. Mat normal1 = R1*normal;
  80. //! [compute-plane-normal-at-camera-pose-1]
  81. //! [compute-plane-distance-to-the-camera-frame-1]
  82. Mat origin(3, 1, CV_64F, Scalar(0));
  83. Mat origin1 = R1*origin + tvec1;
  84. double d_inv1 = 1.0 / normal1.dot(origin1);
  85. //! [compute-plane-distance-to-the-camera-frame-1]
  86. //! [compute-homography-from-camera-displacement]
  87. Mat homography_euclidean = computeHomography(R_1to2, t_1to2, d_inv1, normal1);
  88. Mat homography = cameraMatrix * homography_euclidean * cameraMatrix.inv();
  89. homography /= homography.at<double>(2,2);
  90. homography_euclidean /= homography_euclidean.at<double>(2,2);
  91. //! [compute-homography-from-camera-displacement]
  92. //! [decompose-homography-from-camera-displacement]
  93. vector<Mat> Rs_decomp, ts_decomp, normals_decomp;
  94. int solutions = decomposeHomographyMat(homography, cameraMatrix, Rs_decomp, ts_decomp, normals_decomp);
  95. cout << "Decompose homography matrix computed from the camera displacement:" << endl << endl;
  96. for (int i = 0; i < solutions; i++)
  97. {
  98. double factor_d1 = 1.0 / d_inv1;
  99. Mat rvec_decomp;
  100. Rodrigues(Rs_decomp[i], rvec_decomp);
  101. cout << "Solution " << i << ":" << endl;
  102. cout << "rvec from homography decomposition: " << rvec_decomp.t() << endl;
  103. cout << "rvec from camera displacement: " << rvec_1to2.t() << endl;
  104. cout << "tvec from homography decomposition: " << ts_decomp[i].t() << " and scaled by d: " << factor_d1 * ts_decomp[i].t() << endl;
  105. cout << "tvec from camera displacement: " << t_1to2.t() << endl;
  106. cout << "plane normal from homography decomposition: " << normals_decomp[i].t() << endl;
  107. cout << "plane normal at camera 1 pose: " << normal1.t() << endl << endl;
  108. }
  109. //! [decompose-homography-from-camera-displacement]
  110. //! [estimate homography]
  111. Mat H = findHomography(corners1, corners2);
  112. //! [estimate homography]
  113. //! [decompose-homography-estimated-by-findHomography]
  114. solutions = decomposeHomographyMat(H, cameraMatrix, Rs_decomp, ts_decomp, normals_decomp);
  115. cout << "Decompose homography matrix estimated by findHomography():" << endl << endl;
  116. for (int i = 0; i < solutions; i++)
  117. {
  118. double factor_d1 = 1.0 / d_inv1;
  119. Mat rvec_decomp;
  120. Rodrigues(Rs_decomp[i], rvec_decomp);
  121. cout << "Solution " << i << ":" << endl;
  122. cout << "rvec from homography decomposition: " << rvec_decomp.t() << endl;
  123. cout << "rvec from camera displacement: " << rvec_1to2.t() << endl;
  124. cout << "tvec from homography decomposition: " << ts_decomp[i].t() << " and scaled by d: " << factor_d1 * ts_decomp[i].t() << endl;
  125. cout << "tvec from camera displacement: " << t_1to2.t() << endl;
  126. cout << "plane normal from homography decomposition: " << normals_decomp[i].t() << endl;
  127. cout << "plane normal at camera 1 pose: " << normal1.t() << endl << endl;
  128. }
  129. //! [decompose-homography-estimated-by-findHomography]
  130. }
  131. const char* params
  132. = "{ help h | | print usage }"
  133. "{ image1 | left02.jpg | path to the source chessboard image }"
  134. "{ image2 | left01.jpg | path to the desired chessboard image }"
  135. "{ intrinsics | left_intrinsics.yml | path to camera intrinsics }"
  136. "{ width bw | 9 | chessboard width }"
  137. "{ height bh | 6 | chessboard height }"
  138. "{ square_size | 0.025 | chessboard square size }";
  139. }
  140. int main(int argc, char *argv[])
  141. {
  142. CommandLineParser parser(argc, argv, params);
  143. if ( parser.has("help") )
  144. {
  145. parser.about( "Code for homography tutorial.\n"
  146. "Example 4: decompose the homography matrix.\n" );
  147. parser.printMessage();
  148. return 0;
  149. }
  150. Size patternSize(parser.get<int>("width"), parser.get<int>("height"));
  151. float squareSize = (float) parser.get<double>("square_size");
  152. decomposeHomography(parser.get<String>("image1"),
  153. parser.get<String>("image2"),
  154. patternSize, squareSize,
  155. parser.get<String>("intrinsics"));
  156. return 0;
  157. }