Berkeley SfM
normalization.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 "normalization.h"
39 
40 #include <glog/logging.h>
41 
42 namespace bsfm {
43 
44 Matrix3d ComputeNormalization(const FeatureMatchList& matched_features,
45  bool use_feature_set1) {
46  if (matched_features.empty()) {
47  LOG(WARNING) << "Received no data to normalize. Returning identity.";
48  return MatrixXd::Identity(3, 3);
49  }
50 
51  // Compute a mean translation from the origin.
52  double mean_u = 0.0;
53  double mean_v = 0.0;
54  for (size_t ii = 0; ii < matched_features.size(); ++ii) {
55  if (use_feature_set1) {
56  mean_u += matched_features[ii].feature1_.u_;
57  mean_v += matched_features[ii].feature1_.v_;
58  } else {
59  mean_u += matched_features[ii].feature2_.u_;
60  mean_v += matched_features[ii].feature2_.v_;
61  }
62  }
63  mean_u /= static_cast<double>(matched_features.size());
64  mean_v /= static_cast<double>(matched_features.size());
65 
66  // Compute a scale factor such that after translation, all points will be an
67  // average distance of sqrt(2) away from the origin.
68  // This uses Eqs. 1.28 - 1.37 from here:
69  // http://www.ecse.rpi.edu/Homepages/qji/CV/8point.pdf
70  double scale = 0.0;
71  for (size_t ii = 0; ii < matched_features.size(); ++ii) {
72  double u = 0.0, v = 0.0;
73  if (use_feature_set1) {
74  u = matched_features[ii].feature1_.u_;
75  v = matched_features[ii].feature1_.v_;
76  } else {
77  u = matched_features[ii].feature2_.u_;
78  v = matched_features[ii].feature2_.v_;
79  }
80 
81  scale += sqrt((u - mean_u) * (u - mean_u) + (v - mean_v) * (v - mean_v));
82  }
83  scale /= static_cast<double>(matched_features.size());
84  scale /= sqrt(2.0);
85 
86  // If the calculated scale, for some reason, is ridiculously small (i.e.
87  // dividing by zero), return an identity output matrix. This will make us not
88  // normalize the data, but we should still get an okay fundamental matrix.
89  if (scale < 1e-4) {
90  LOG(WARNING)
91  << "When normalizing feature coordinates scale factor was nearly zero. "
92  "Proceeding without normalizing data.";
93  return MatrixXd::Identity(3, 3);
94  }
95 
96  // Populate the output matrix.
97  Matrix3d T(MatrixXd::Identity(3, 3));
98  T(0, 0) = 1.0 / scale;
99  T(1, 1) = 1.0 / scale;
100  T(0, 2) = -mean_u / scale;
101  T(1, 2) = -mean_v / scale;
102 
103  return T;
104 }
105 
106 Matrix3d ComputeNormalization(const FeatureList& features) {
107  if (features.empty()) {
108  LOG(WARNING) << "Received no data to normalize. Returning identity.";
109  return MatrixXd::Identity(3, 3);
110  }
111 
112  // Compute a mean translation from the origin.
113  double mean_u = 0.0;
114  double mean_v = 0.0;
115  for (size_t ii = 0; ii < features.size(); ++ii) {
116  mean_u += features[ii].u_;
117  mean_v += features[ii].v_;
118  }
119  mean_u /= static_cast<double>(features.size());
120  mean_v /= static_cast<double>(features.size());
121 
122  // Compute a scale factor such that after translation, all points will be an
123  // average distance of sqrt(2) away from the origin.
124  // This uses Eqs. 1.28 - 1.37 from here:
125  // http://www.ecse.rpi.edu/Homepages/qji/CV/8point.pdf
126  double scale = 0.0;
127  for (size_t ii = 0; ii < features.size(); ++ii) {
128  double u = 0.0, v = 0.0;
129  u = features[ii].u_;
130  v = features[ii].v_;
131 
132  scale += sqrt((u - mean_u) * (u - mean_u) + (v - mean_v) * (v - mean_v));
133  }
134  scale /= static_cast<double>(features.size());
135  scale /= sqrt(2.0);
136 
137  // If the calculated scale, for some reason, is ridiculously small (i.e.
138  // dividing by zero), return an identity output matrix. This will make us not
139  // normalize the data, but we should still get an okay fundamental matrix.
140  if (scale < 1e-4) {
141  LOG(WARNING)
142  << "When normalizing feature coordinates scale factor was nearly zero. "
143  "Proceeding without normalizing data.";
144  return MatrixXd::Identity(3, 3);
145  }
146 
147  // Populate the output matrix.
148  Matrix3d T(MatrixXd::Identity(3, 3));
149  T(0, 0) = 1.0 / scale;
150  T(1, 1) = 1.0 / scale;
151  T(0, 2) = -mean_u / scale;
152  T(1, 2) = -mean_v / scale;
153 
154  return T;
155 }
156 
157 Matrix4d ComputeNormalization(const Point3DList& points) {
158  if (points.empty()) {
159  LOG(WARNING) << "Received no data to normalize. Returning identity.";
160  return MatrixXd::Identity(4, 4);
161  }
162 
163  // Compute a mean translation from the origin.
164  double mean_x = 0.0;
165  double mean_y = 0.0;
166  double mean_z = 0.0;
167  for (size_t ii = 0; ii < points.size(); ++ii) {
168  mean_x += points[ii].X();
169  mean_y += points[ii].Y();
170  mean_z += points[ii].Z();
171  }
172  mean_x /= static_cast<double>(points.size());
173  mean_y /= static_cast<double>(points.size());
174  mean_z /= static_cast<double>(points.size());
175 
176  // Compute a scale factor such that after translation, all points will be an
177  // average distance of sqrt(2) away from the origin.
178  // This uses Eqs. 1.28 - 1.37 from here:
179  // http://www.ecse.rpi.edu/Homepages/qji/CV/8point.pdf
180  double scale = 0.0;
181  for (size_t ii = 0; ii < points.size(); ++ii) {
182  double x = 0.0, y = 0.0, z = 0.0;
183  x = points[ii].X();
184  y = points[ii].Y();
185  z = points[ii].Z();
186 
187  scale += sqrt((x - mean_x) * (x - mean_x)
188  + (y - mean_y) * (y - mean_y)
189  + (z - mean_z) * (z - mean_z));
190  }
191  scale /= static_cast<double>(points.size());
192  scale /= sqrt(2.0);
193 
194  // If the calculated scale, for some reason, is ridiculously small (i.e.
195  // dividing by zero), return an identity output matrix. This will make us not
196  // normalize the data, but we should still get an okay fundamental matrix.
197  if (scale < 1e-4) {
198  LOG(WARNING)
199  << "When normalizing feature coordinates scale factor was nearly zero. "
200  "Proceeding without normalizing data.";
201  return MatrixXd::Identity(4, 4);
202  }
203 
204  // Populate the output matrix.
205  Matrix4d T(MatrixXd::Identity(4, 4));
206  T(0, 0) = 1.0 / scale;
207  T(1, 1) = 1.0 / scale;
208  T(2, 2) = 1.0 / scale;
209  T(0, 3) = -mean_x / scale;
210  T(1, 3) = -mean_y / scale;
211  T(2, 3) = -mean_z / scale;
212 
213  return T;
214 }
215 
216 } //\namespace bsfm
std::vector< Point3D > Point3DList
Definition: point_3d.h:100
Matrix3d ComputeNormalization(const FeatureMatchList &matched_features, bool use_feature_set1)
std::vector< Feature > FeatureList
Definition: feature.h:65
Definition: camera.cpp:50
std::vector< FeatureMatch > FeatureMatchList
Definition: feature_match.h:99