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