2 #include <opencv2/opencv_modules.hpp>
3 #ifdef HAVE_OPENCV_ARUCO
4 #include <opencv2/opencv.hpp>
5 #include <opencv2/aruco.hpp>
12 enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
14 void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners, Pattern patternType = CHESSBOARD)
18 switch (patternType) {
21 for( int i = 0; i < boardSize.height; i++ )
22 for( int j = 0; j < boardSize.width; j++ )
23 corners.push_back(Point3f(float(j*squareSize),
24 float(i*squareSize), 0));
27 case ASYMMETRIC_CIRCLES_GRID:
28 for( int i = 0; i < boardSize.height; i++ )
29 for( int j = 0; j < boardSize.width; j++ )
30 corners.push_back(Point3f(float((2*j + i % 2)*squareSize),
31 float(i*squareSize), 0));
35 CV_Error(Error::StsBadArg, "Unknown pattern type\n");
39 Mat computeHomography(const Mat &R_1to2, const Mat &tvec_1to2, const double d_inv, const Mat &normal)
41 Mat homography = R_1to2 + d_inv * tvec_1to2*normal.t();
45 void computeC2MC1(const Mat &R1, const Mat &tvec1, const Mat &R2, const Mat &tvec2,
46 Mat &R_1to2, Mat &tvec_1to2)
48 //c2Mc1 = c2Mo * oMc1 = c2Mo * c1Mo.inv()
50 tvec_1to2 = R2 * (-R1.t()*tvec1) + tvec2;
53 void decomposeHomography(const string &img1Path, const string &img2Path, const Size &patternSize,
54 const float squareSize, const string &intrinsicsPath)
56 Mat img1 = imread(img1Path);
57 Mat img2 = imread(img2Path);
59 vector<Point2f> corners1, corners2;
60 bool found1 = findChessboardCorners(img1, patternSize, corners1);
61 bool found2 = findChessboardCorners(img2, patternSize, corners2);
63 if (!found1 || !found2)
65 cout << "Error, cannot find the chessboard corners in both images." << endl;
70 vector<Point3f> objectPoints;
71 calcChessboardCorners(patternSize, squareSize, objectPoints);
73 FileStorage fs(intrinsicsPath, FileStorage::READ);
74 Mat cameraMatrix, distCoeffs;
75 fs["camera_matrix"] >> cameraMatrix;
76 fs["distortion_coefficients"] >> distCoeffs;
79 solvePnP(objectPoints, corners1, cameraMatrix, distCoeffs, rvec1, tvec1);
81 solvePnP(objectPoints, corners2, cameraMatrix, distCoeffs, rvec2, tvec2);
84 //! [compute-camera-displacement]
90 computeC2MC1(R1, tvec1, R2, tvec2, R_1to2, t_1to2);
92 Rodrigues(R_1to2, rvec_1to2);
93 //! [compute-camera-displacement]
95 //! [compute-plane-normal-at-camera-pose-1]
96 Mat normal = (Mat_<double>(3,1) << 0, 0, 1);
97 Mat normal1 = R1*normal;
98 //! [compute-plane-normal-at-camera-pose-1]
100 //! [compute-plane-distance-to-the-camera-frame-1]
101 Mat origin(3, 1, CV_64F, Scalar(0));
102 Mat origin1 = R1*origin + tvec1;
103 double d_inv1 = 1.0 / normal1.dot(origin1);
104 //! [compute-plane-distance-to-the-camera-frame-1]
106 //! [compute-homography-from-camera-displacement]
107 Mat homography_euclidean = computeHomography(R_1to2, t_1to2, d_inv1, normal1);
108 Mat homography = cameraMatrix * homography_euclidean * cameraMatrix.inv();
110 homography /= homography.at<double>(2,2);
111 homography_euclidean /= homography_euclidean.at<double>(2,2);
112 //! [compute-homography-from-camera-displacement]
114 //! [decompose-homography-from-camera-displacement]
115 vector<Mat> Rs_decomp, ts_decomp, normals_decomp;
116 int solutions = decomposeHomographyMat(homography, cameraMatrix, Rs_decomp, ts_decomp, normals_decomp);
117 cout << "Decompose homography matrix computed from the camera displacement:" << endl << endl;
118 for (int i = 0; i < solutions; i++)
120 double factor_d1 = 1.0 / d_inv1;
122 Rodrigues(Rs_decomp[i], rvec_decomp);
123 cout << "Solution " << i << ":" << endl;
124 cout << "rvec from homography decomposition: " << rvec_decomp.t() << endl;
125 cout << "rvec from camera displacement: " << rvec_1to2.t() << endl;
126 cout << "tvec from homography decomposition: " << ts_decomp[i].t() << " and scaled by d: " << factor_d1 * ts_decomp[i].t() << endl;
127 cout << "tvec from camera displacement: " << t_1to2.t() << endl;
128 cout << "plane normal from homography decomposition: " << normals_decomp[i].t() << endl;
129 cout << "plane normal at camera 1 pose: " << normal1.t() << endl << endl;
131 //! [decompose-homography-from-camera-displacement]
133 //! [estimate homography]
134 Mat H = findHomography(corners1, corners2);
135 //! [estimate homography]
137 //! [decompose-homography-estimated-by-findHomography]
138 solutions = decomposeHomographyMat(H, cameraMatrix, Rs_decomp, ts_decomp, normals_decomp);
139 cout << "Decompose homography matrix estimated by findHomography():" << endl << endl;
140 for (int i = 0; i < solutions; i++)
142 double factor_d1 = 1.0 / d_inv1;
144 Rodrigues(Rs_decomp[i], rvec_decomp);
145 cout << "Solution " << i << ":" << endl;
146 cout << "rvec from homography decomposition: " << rvec_decomp.t() << endl;
147 cout << "rvec from camera displacement: " << rvec_1to2.t() << endl;
148 cout << "tvec from homography decomposition: " << ts_decomp[i].t() << " and scaled by d: " << factor_d1 * ts_decomp[i].t() << endl;
149 cout << "tvec from camera displacement: " << t_1to2.t() << endl;
150 cout << "plane normal from homography decomposition: " << normals_decomp[i].t() << endl;
151 cout << "plane normal at camera 1 pose: " << normal1.t() << endl << endl;
153 //! [decompose-homography-estimated-by-findHomography]
157 = "{ help h | | print usage }"
158 "{ image1 | ../data/left02.jpg | path to the source chessboard image }"
159 "{ image2 | ../data/left01.jpg | path to the desired chessboard image }"
160 "{ intrinsics | ../data/left_intrinsics.yml | path to camera intrinsics }"
161 "{ width bw | 9 | chessboard width }"
162 "{ height bh | 6 | chessboard height }"
163 "{ square_size | 0.025 | chessboard square size }";
166 int main(int argc, char *argv[])
168 CommandLineParser parser(argc, argv, params);
170 if ( parser.has("help") )
172 parser.about( "Code for homography tutorial.\n"
173 "Example 4: decompose the homography matrix.\n" );
174 parser.printMessage();
178 Size patternSize(parser.get<int>("width"), parser.get<int>("height"));
179 float squareSize = (float) parser.get<double>("square_size");
180 decomposeHomography(parser.get<String>("image1"),
181 parser.get<String>("image2"),
182 patternSize, squareSize,
183 parser.get<String>("intrinsics"));
190 std::cerr << "FATAL ERROR: This sample requires opencv_aruco module (from opencv_contrib)" << std::endl;