Berkeley SfM
essential_matrix_solver.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, The Regents of the University of California (Regents).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer in the documentation and/or other materials provided
15  * with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Please contact the author(s) of this library if you have any questions.
34  * Authors: David Fridovich-Keil ( dfk@eecs.berkeley.edu )
35  * Erik Nelson ( eanelson@eecs.berkeley.edu )
36  */
37 
38 ///////////////////////////////////////////////////////////////////////////////
39 //
40 // This header defines a set of functions for converting a fundamental matrix
41 // and a pair of camera intrinsics into an essential matrix, and from an
42 // essential matrix to and a set of camera extrinsics.
43 //
44 ///////////////////////////////////////////////////////////////////////////////
45 
47 
48 #include <Eigen/Core>
49 #include <Eigen/LU>
50 #include <gflags/gflags.h>
51 #include <glog/logging.h>
52 #include <vector>
53 
54 #include "point_3d.h"
55 #include "triangulation.h"
56 #include "../camera/camera.h"
57 
58 DEFINE_double(min_points_visible_ratio, 0.8,
59  "Fraction of keypoint matches whose triangulation must be "
60  "visible from both cameras. This value should be lowered if you "
61  "expect lots of noisy matches.");
62 
63 namespace bsfm {
64 
65 // Compute the essential matrix from a fundamental matrix and camera intrinsics.
67  const Matrix3d& F, const CameraIntrinsics& intrinsics1,
68  const CameraIntrinsics& intrinsics2) {
69  // Extract intrinsics matrices.
70  Matrix3d K1(intrinsics1.K());
71  Matrix3d K2(intrinsics2.K());
72 
73  // Calculate the essential matrix.
74  return K2.transpose() * F * K1;
75 }
76 
77 // Compute the relative transformation between two cameras from an essential
78 // matrix and a list of keypoint matches. Note that translation can only be
79 // computed up to a scale factor.
80 // NOTE: this implementation is based on Hartley & Zisserman's MVG, pg. 258.
82  const Matrix3d& E, const FeatureMatchList& matches,
83  const CameraIntrinsics& intrinsics1, const CameraIntrinsics& intrinsics2,
84  Pose& relative_pose) {
85  // Initialize the W matrix.
86  Matrix3d W;
87  W << 0.0, -1.0, 0.0,
88  1.0, 0.0, 0.0,
89  0.0, 0.0, 1.0;
90 
91  // Perform an SVD on the essential matrix.
92  Eigen::JacobiSVD<Matrix3d> svd;
93  svd.compute(E, Eigen::ComputeFullU | Eigen::ComputeFullV);
94  if (!svd.computeU() || !svd.computeV()) {
95  VLOG(1) << "Failed to compute a singular value decomposition of "
96  << "the essential matrix.";
97  return false;
98  }
99 
100  // The essential matrix must satisfy E = U * diag(1, 1, 0) * V^T. Use U and V
101  // to get a new E, run another SVD, and get the normalized U and V.
102  Matrix3d sigma(Matrix3d::Identity());
103  sigma(2, 2) = 0;
104  Matrix3d E_augmented = svd.matrixU() * sigma * svd.matrixV().transpose();
105 
106  svd.compute(E_augmented, Eigen::ComputeFullU | Eigen::ComputeFullV);
107  if (!svd.computeU() || !svd.computeV()) {
108  VLOG(1) << "Failed to compute a singular value decomposition of "
109  << "the essential matrix.";
110  return false;
111  }
112 
113  // Compute two possibilities for rotation.
114  Matrix3d R1 = svd.matrixU() * W * svd.matrixV().transpose();
115  Matrix3d R2 = svd.matrixU() * W.transpose() * svd.matrixV().transpose();
116 
117  // Ensure positive determinants.
118  if (R1.determinant() < 0)
119  R1 = -R1;
120  if (R2.determinant() < 0)
121  R2 = -R2;
122 
123  // Compute two possibilities for translation
124  Vector3d t1, t2;
125  t1 = svd.matrixU().col(2);
126  t2 = -t1;
127 
128  // Build four possible Poses.
129  std::vector<Pose> poses;
130  poses.push_back(Pose(R1, t1));
131  poses.push_back(Pose(R1, t2));
132  poses.push_back(Pose(R2, t1));
133  poses.push_back(Pose(R2, t2));
134 
135  // Set the first camera's position to identity in rotation and translation.
136  CameraExtrinsics extrinsics1;
137  extrinsics1.SetWorldToCamera(Pose());
138 
139  Camera camera1;
140  camera1.SetExtrinsics(extrinsics1);
141  camera1.SetIntrinsics(intrinsics1);
142 
143  // Test how many points are in front of each pose and the identity pose.
144  Pose best_pose;
145  int best_num_points = -1;
146 
147  double u = 0.0, v = 0.0;
148  for (int ii = 0; ii < poses.size(); ii++) {
149  int num_points = 0;
150 
151  CameraExtrinsics extrinsics2;
152  extrinsics2.SetWorldToCamera(poses[ii]);
153 
154  Camera camera2;
155  camera2.SetExtrinsics(extrinsics2);
156  camera2.SetIntrinsics(intrinsics2);
157 
158  for (int jj = 0; jj < matches.size(); jj++) {
159  // Triangulate points and test if the 3D estimate is in front of both
160  // cameras.
161  Point3D point;
162  if (!Triangulate(matches[jj], camera1, camera2, point)) {
163  continue;
164  }
165 
166  num_points++;
167  }
168 
169  // Update best_cnt and best_pose.
170  if (num_points > best_num_points) {
171  best_num_points = num_points;
172  best_pose = poses[ii];
173  }
174  }
175 
176  // Return with false if not enough points found in front of the cameras.
177  if (best_num_points < FLAGS_min_points_visible_ratio * matches.size()) {
178  VLOG(1) << "Did not find enough points in front of both cameras.";
179  return false;
180  }
181 
182  relative_pose = best_pose;
183 
184  return true;
185 }
186 
187 } //\namespace bsfm
void SetIntrinsics(const CameraIntrinsics &)
Definition: camera.cpp:62
DEFINE_double(min_points_visible_ratio, 0.8,"Fraction of keypoint matches whose triangulation must be ""visible from both cameras. This value should be lowered if you ""expect lots of noisy matches.")
bool ComputeExtrinsics(const Matrix3d &E, const FeatureMatchList &matches, const CameraIntrinsics &intrinsics1, const CameraIntrinsics &intrinsics2, Pose &relative_pose)
void SetExtrinsics(const CameraExtrinsics &)
Definition: camera.cpp:57
void SetWorldToCamera(const Pose &world_to_camera)
Matrix3d ComputeEssentialMatrix(const Matrix3d &F, const CameraIntrinsics &intrinsics1, const CameraIntrinsics &intrinsics2)
Definition: camera.cpp:50
std::vector< FeatureMatch > FeatureMatchList
Definition: feature_match.h:99
bool Triangulate(const FeatureList &features, const std::vector< Camera > &cameras, Point3D &point)