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