Berkeley SfM
triangulation.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: Erik Nelson ( eanelson@eecs.berkeley.edu )
35  * David Fridovich-Keil ( dfk@eecs.berkeley.edu )
36  */
37 
38 #include "triangulation.h"
39 
40 #include <Eigen/Core>
41 #include <Eigen/SVD>
42 #include <glog/logging.h>
43 
44 #include "../util/types.h"
45 
46 namespace bsfm {
47 
48 using Eigen::MatrixXd;
49 
50 // Triangulates a single 3D point from > 2 views using the inhomogeneous DLT
51 // method from H&Z: Multi-View Geometry, Ch 2.2.
52 bool Triangulate(const FeatureList& features,
53  const std::vector<Camera>& cameras, Point3D& point) {
54  if (features.size() != cameras.size()) {
55  LOG(WARNING)
56  << "Number of features does not match number of cameras.";
57  return false;
58  }
59 
60  if (features.size() < 2) {
61  LOG(WARNING) << "Need at least two features and cameras to triangulate.";
62  return false;
63  }
64 
65  // Construct the A matrix on page 312.
66  MatrixXd A;
67  A.resize(features.size() * 2, 4);
68  for (size_t ii = 0; ii < features.size(); ++ii) {
69  double u = features[ii].u_;
70  double v = features[ii].v_;
71 
72  const Matrix34d P = cameras[ii].P();
73  A.row(2*ii+0) = u * P.row(2) - P.row(0);
74  A.row(2*ii+1) = v * P.row(2) - P.row(1);
75  }
76 
77  // Get svd(A). Save some time and compute a thin U. We still need a full V.
78  Eigen::JacobiSVD<MatrixXd> svd;
79  svd.compute(A, Eigen::ComputeThinU | Eigen::ComputeFullV);
80  if (!svd.computeV()) {
81  VLOG(1) << "Failed to compute a singular value decomposition of A matrix.";
82  return false;
83  }
84 
85  // The 3D point is the eigenvector corresponding to the minimum eigenvalue.
86  point = Point3D(svd.matrixV().block(0, 3, 3, 1) / svd.matrixV()(3,3));
87 
88  // Return false if the point is not visible from all cameras.
89  for (size_t ii = 0; ii < cameras.size(); ++ii) {
90  double u = 0.0, v = 0.0;
91  if (!cameras[ii].WorldToImage(point.X(), point.Y(), point.Z(), &u, &v)) {
92  return false;
93  }
94  }
95 
96  return true;
97 }
98 
99 // Triangulate the 3D position of a point from a 2D correspondence and two sets
100 // of camera extrinsics and intrinsics.
101 bool Triangulate(const FeatureMatch& feature_match, const Camera& camera1,
102  const Camera& camera2, Point3D& point) {
103  FeatureList features;
104  features.push_back(feature_match.feature1_);
105  features.push_back(feature_match.feature2_);
106 
107  std::vector<Camera> cameras;
108  cameras.push_back(camera1);
109  cameras.push_back(camera2);
110 
111  return Triangulate(features, cameras, point);
112 }
113 
114 // Repeats the above function on a list of feature matches, returning a list of
115 // triangulated 3D points, where each point is computed from a single 2D <--> 2D
116 // correspondence.
117 bool Triangulate(const FeatureMatchList& feature_matches, const Camera& camera1,
118  const Camera& camera2, Point3DList& points) {
119  // Clear output.
120  points.clear();
121 
122  bool triangulated_all_points = true;
123  for (size_t ii = 0; ii < feature_matches.size(); ++ii) {
124  Point3D point;
125 
126  // Continue on failure, but store (0, 0, 0).
127  if (!Triangulate(feature_matches[ii], camera1, camera2, point)) {
128  triangulated_all_points = false;
129  point = Point3D();
130  }
131  points.push_back(point);
132  }
133 
134  return triangulated_all_points;
135 }
136 
137 } //\namespace bsfm
std::vector< Point3D > Point3DList
Definition: point_3d.h:100
std::vector< Feature > FeatureList
Definition: feature.h:65
double Y() const
Definition: point_3d.cpp:94
double X() const
Definition: point_3d.cpp:92
Definition: camera.cpp:50
::Eigen::Matrix< double, 3, 4 > Matrix34d
Definition: types.h:87
std::vector< FeatureMatch > FeatureMatchList
Definition: feature_match.h:99
double Z() const
Definition: point_3d.cpp:96
bool Triangulate(const FeatureList &features, const std::vector< Camera > &cameras, Point3D &point)