ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
utils.cc
Go to the documentation of this file.
1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 //
14 // * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 // its contributors may be used to endorse or promote products derived
16 // from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31 
32 #include "estimators/utils.h"
33 
34 #include "util/logging.h"
35 
36 namespace colmap {
37 
38 void CenterAndNormalizeImagePoints(const std::vector<Eigen::Vector2d>& points,
39  std::vector<Eigen::Vector2d>* normed_points,
40  Eigen::Matrix3d* matrix) {
41  // Calculate centroid
42  Eigen::Vector2d centroid(0, 0);
43  for (const Eigen::Vector2d& point : points) {
44  centroid += point;
45  }
46  centroid /= points.size();
47 
48  // Root mean square error to centroid of all points
49  double rms_mean_dist = 0;
50  for (const Eigen::Vector2d& point : points) {
51  rms_mean_dist += (point - centroid).squaredNorm();
52  }
53  rms_mean_dist = std::sqrt(rms_mean_dist / points.size());
54 
55  // Compose normalization matrix
56  const double norm_factor = std::sqrt(2.0) / rms_mean_dist;
57  *matrix << norm_factor, 0, -norm_factor * centroid(0), 0, norm_factor,
58  -norm_factor * centroid(1), 0, 0, 1;
59 
60  // Apply normalization matrix
61  normed_points->resize(points.size());
62 
63  const double M_00 = (*matrix)(0, 0);
64  const double M_01 = (*matrix)(0, 1);
65  const double M_02 = (*matrix)(0, 2);
66  const double M_10 = (*matrix)(1, 0);
67  const double M_11 = (*matrix)(1, 1);
68  const double M_12 = (*matrix)(1, 2);
69  const double M_20 = (*matrix)(2, 0);
70  const double M_21 = (*matrix)(2, 1);
71  const double M_22 = (*matrix)(2, 2);
72 
73  for (size_t i = 0; i < points.size(); ++i) {
74  const double p_0 = points[i](0);
75  const double p_1 = points[i](1);
76 
77  const double np_0 = M_00 * p_0 + M_01 * p_1 + M_02;
78  const double np_1 = M_10 * p_0 + M_11 * p_1 + M_12;
79  const double np_2 = M_20 * p_0 + M_21 * p_1 + M_22;
80 
81  const double inv_np_2 = 1.0 / np_2;
82  (*normed_points)[i](0) = np_0 * inv_np_2;
83  (*normed_points)[i](1) = np_1 * inv_np_2;
84  }
85 }
86 
87 void ComputeSquaredSampsonError(const std::vector<Eigen::Vector2d>& points1,
88  const std::vector<Eigen::Vector2d>& points2,
89  const Eigen::Matrix3d& E,
90  std::vector<double>* residuals) {
91  CHECK_EQ(points1.size(), points2.size());
92 
93  residuals->resize(points1.size());
94 
95  // Note that this code might not be as nice as Eigen expressions,
96  // but it is significantly faster in various tests
97 
98  const double E_00 = E(0, 0);
99  const double E_01 = E(0, 1);
100  const double E_02 = E(0, 2);
101  const double E_10 = E(1, 0);
102  const double E_11 = E(1, 1);
103  const double E_12 = E(1, 2);
104  const double E_20 = E(2, 0);
105  const double E_21 = E(2, 1);
106  const double E_22 = E(2, 2);
107 
108  for (size_t i = 0; i < points1.size(); ++i) {
109  const double x1_0 = points1[i](0);
110  const double x1_1 = points1[i](1);
111  const double x2_0 = points2[i](0);
112  const double x2_1 = points2[i](1);
113 
114  // Ex1 = E * points1[i].homogeneous();
115  const double Ex1_0 = E_00 * x1_0 + E_01 * x1_1 + E_02;
116  const double Ex1_1 = E_10 * x1_0 + E_11 * x1_1 + E_12;
117  const double Ex1_2 = E_20 * x1_0 + E_21 * x1_1 + E_22;
118 
119  // Etx2 = E.transpose() * points2[i].homogeneous();
120  const double Etx2_0 = E_00 * x2_0 + E_10 * x2_1 + E_20;
121  const double Etx2_1 = E_01 * x2_0 + E_11 * x2_1 + E_21;
122 
123  // x2tEx1 = points2[i].homogeneous().transpose() * Ex1;
124  const double x2tEx1 = x2_0 * Ex1_0 + x2_1 * Ex1_1 + Ex1_2;
125 
126  // Sampson distance
127  (*residuals)[i] =
128  x2tEx1 * x2tEx1 /
129  (Ex1_0 * Ex1_0 + Ex1_1 * Ex1_1 + Etx2_0 * Etx2_0 + Etx2_1 * Etx2_1);
130  }
131 }
132 
134  const std::vector<Eigen::Vector2d>& points2D,
135  const std::vector<Eigen::Vector3d>& points3D,
136  const Eigen::Matrix3x4d& proj_matrix, std::vector<double>* residuals) {
137  CHECK_EQ(points2D.size(), points3D.size());
138 
139  residuals->resize(points2D.size());
140 
141  // Note that this code might not be as nice as Eigen expressions,
142  // but it is significantly faster in various tests.
143 
144  const double P_00 = proj_matrix(0, 0);
145  const double P_01 = proj_matrix(0, 1);
146  const double P_02 = proj_matrix(0, 2);
147  const double P_03 = proj_matrix(0, 3);
148  const double P_10 = proj_matrix(1, 0);
149  const double P_11 = proj_matrix(1, 1);
150  const double P_12 = proj_matrix(1, 2);
151  const double P_13 = proj_matrix(1, 3);
152  const double P_20 = proj_matrix(2, 0);
153  const double P_21 = proj_matrix(2, 1);
154  const double P_22 = proj_matrix(2, 2);
155  const double P_23 = proj_matrix(2, 3);
156 
157  for (size_t i = 0; i < points2D.size(); ++i) {
158  const double X_0 = points3D[i](0);
159  const double X_1 = points3D[i](1);
160  const double X_2 = points3D[i](2);
161 
162  // Project 3D point from world to camera.
163  const double px_2 = P_20 * X_0 + P_21 * X_1 + P_22 * X_2 + P_23;
164 
165  // Check if 3D point is in front of camera.
166  if (px_2 > std::numeric_limits<double>::epsilon()) {
167  const double px_0 = P_00 * X_0 + P_01 * X_1 + P_02 * X_2 + P_03;
168  const double px_1 = P_10 * X_0 + P_11 * X_1 + P_12 * X_2 + P_13;
169 
170  const double x_0 = points2D[i](0);
171  const double x_1 = points2D[i](1);
172 
173  const double inv_px_2 = 1.0 / px_2;
174  const double dx_0 = x_0 - px_0 * inv_px_2;
175  const double dx_1 = x_1 - px_1 * inv_px_2;
176 
177  (*residuals)[i] = dx_0 * dx_0 + dx_1 * dx_1;
178  } else {
179  (*residuals)[i] = std::numeric_limits<double>::max();
180  }
181  }
182 }
183 
184 } // namespace colmap
int points
Matrix< double, 3, 4 > Matrix3x4d
Definition: types.h:39
void CenterAndNormalizeImagePoints(const std::vector< Eigen::Vector2d > &points, std::vector< Eigen::Vector2d > *normed_points, Eigen::Matrix3d *matrix)
Definition: utils.cc:38
void ComputeSquaredReprojectionError(const std::vector< Eigen::Vector2d > &points2D, const std::vector< Eigen::Vector3d > &points3D, const Eigen::Matrix3x4d &proj_matrix, std::vector< double > *residuals)
Definition: utils.cc:133
void ComputeSquaredSampsonError(const std::vector< Eigen::Vector2d > &points1, const std::vector< Eigen::Vector2d > &points2, const Eigen::Matrix3d &E, std::vector< double > *residuals)
Definition: utils.cc:87