1 // This file is part of OpenMVG, an Open Multiple View Geometry C++ library.
2
3 // Copyright (c) 2015 Pierre MOULON.
4
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
9 //-----------------
10 // Test summary:
11 //-----------------
12 // - Create features points and matching from the synthetic dataset
13 // - Init a SfM_Data scene View and Intrinsic from a synthetic dataset
14 // - Perform Global SfM on the data
15 // - Assert that:
16 // - mean residual error is below the gaussian noise added to observation
17 // - the desired number of tracks are found,
18 // - the desired number of poses are found.
19 //-----------------
20
21 #include "openMVG/sfm/pipelines/pipelines_test.hpp"
22 #include "openMVG/sfm/sfm.hpp"
23
24 #include "testing/testing.h"
25
26 #include <cmath>
27 #include <cstdio>
28 #include <iostream>
29
30 using namespace openMVG;
31 using namespace openMVG::cameras;
32 using namespace openMVG::geometry;
33 using namespace openMVG::sfm;
34
35
TEST(GLOBAL_SFM,RotationAveragingL2_TranslationAveragingL1)36 TEST(GLOBAL_SFM, RotationAveragingL2_TranslationAveragingL1) {
37
38 const int nviews = 6;
39 const int npoints = 64;
40 const nViewDatasetConfigurator config;
41 const NViewDataSet d = NRealisticCamerasRing(nviews, npoints, config);
42
43 // Translate the input dataset to a SfM_Data scene
44 const SfM_Data sfm_data = getInputScene(d, config, PINHOLE_CAMERA);
45
46 // Remove poses and structure
47 SfM_Data sfm_data_2 = sfm_data;
48 sfm_data_2.poses.clear();
49 sfm_data_2.structure.clear();
50
51 GlobalSfMReconstructionEngine_RelativeMotions sfmEngine(
52 sfm_data_2,
53 "./",
54 stlplus::create_filespec("./", "Reconstruction_Report.html"));
55
56 // Configure the features_provider & the matches_provider from the synthetic dataset
57 std::shared_ptr<Features_Provider> feats_provider =
58 std::make_shared<Synthetic_Features_Provider>();
59 // Add a tiny noise in 2D observations to make data more realistic
60 std::normal_distribution<double> distribution(0.0,0.5);
61 dynamic_cast<Synthetic_Features_Provider*>(feats_provider.get())->load(d,distribution);
62
63 std::shared_ptr<Matches_Provider> matches_provider =
64 std::make_shared<Synthetic_Matches_Provider>();
65 dynamic_cast<Synthetic_Matches_Provider*>(matches_provider.get())->load(d);
66
67 // Configure data provider (Features and Matches)
68 sfmEngine.SetFeaturesProvider(feats_provider.get());
69 sfmEngine.SetMatchesProvider(matches_provider.get());
70
71 // Configure reconstruction parameters (intrinsic parameters are held constant)
72 sfmEngine.Set_Intrinsics_Refinement_Type(cameras::Intrinsic_Parameter_Type::NONE);
73
74 // Configure motion averaging methods
75 sfmEngine.SetRotationAveragingMethod(ROTATION_AVERAGING_L2);
76 sfmEngine.SetTranslationAveragingMethod(TRANSLATION_AVERAGING_L1);
77
78 EXPECT_TRUE (sfmEngine.Process());
79
80 const double dResidual = RMSE(sfmEngine.Get_SfM_Data());
81 std::cout << "RMSE residual: " << dResidual << std::endl;
82 EXPECT_TRUE( dResidual < 0.5);
83 EXPECT_EQ( nviews, sfmEngine.Get_SfM_Data().GetPoses().size());
84 EXPECT_EQ( npoints, sfmEngine.Get_SfM_Data().GetLandmarks().size());
85 EXPECT_TRUE( IsTracksOneCC(sfmEngine.Get_SfM_Data()));
86 }
87
TEST(GLOBAL_SFM,RotationAveragingL1_TranslationAveragingL1)88 TEST(GLOBAL_SFM, RotationAveragingL1_TranslationAveragingL1) {
89
90 const int nviews = 6;
91 const int npoints = 64;
92 const nViewDatasetConfigurator config;
93 const NViewDataSet d = NRealisticCamerasRing(nviews, npoints, config);
94
95 // Translate the input dataset to a SfM_Data scene
96 const SfM_Data sfm_data = getInputScene(d, config, PINHOLE_CAMERA);
97
98 // Remove poses and structure
99 SfM_Data sfm_data_2 = sfm_data;
100 sfm_data_2.poses.clear();
101 sfm_data_2.structure.clear();
102
103 GlobalSfMReconstructionEngine_RelativeMotions sfmEngine(
104 sfm_data_2,
105 "./",
106 stlplus::create_filespec("./", "Reconstruction_Report.html"));
107
108 // Configure the features_provider & the matches_provider from the synthetic dataset
109 std::shared_ptr<Features_Provider> feats_provider =
110 std::make_shared<Synthetic_Features_Provider>();
111 // Add a tiny noise in 2D observations to make data more realistic
112 std::normal_distribution<double> distribution(0.0,0.5);
113 dynamic_cast<Synthetic_Features_Provider*>(feats_provider.get())->load(d,distribution);
114
115 std::shared_ptr<Matches_Provider> matches_provider =
116 std::make_shared<Synthetic_Matches_Provider>();
117 dynamic_cast<Synthetic_Matches_Provider*>(matches_provider.get())->load(d);
118
119 // Configure data provider (Features and Matches)
120 sfmEngine.SetFeaturesProvider(feats_provider.get());
121 sfmEngine.SetMatchesProvider(matches_provider.get());
122
123 // Configure reconstruction parameters (intrinsic parameters are held constant)
124 sfmEngine.Set_Intrinsics_Refinement_Type(cameras::Intrinsic_Parameter_Type::NONE);
125
126 // Configure motion averaging methods
127 sfmEngine.SetRotationAveragingMethod(ROTATION_AVERAGING_L1);
128 sfmEngine.SetTranslationAveragingMethod(TRANSLATION_AVERAGING_L1);
129
130 EXPECT_TRUE (sfmEngine.Process());
131
132 const double dResidual = RMSE(sfmEngine.Get_SfM_Data());
133 std::cout << "RMSE residual: " << dResidual << std::endl;
134 EXPECT_TRUE( dResidual < 0.5);
135 EXPECT_EQ( nviews, sfmEngine.Get_SfM_Data().GetPoses().size());
136 EXPECT_EQ( npoints, sfmEngine.Get_SfM_Data().GetLandmarks().size());
137 EXPECT_TRUE( IsTracksOneCC(sfmEngine.Get_SfM_Data()));
138 }
139
140
TEST(GLOBAL_SFM,RotationAveragingL2_TranslationAveragingL2_Chordal)141 TEST(GLOBAL_SFM, RotationAveragingL2_TranslationAveragingL2_Chordal) {
142
143 const int nviews = 6;
144 const int npoints = 64;
145 const nViewDatasetConfigurator config;
146 const NViewDataSet d = NRealisticCamerasRing(nviews, npoints, config);
147
148 // Translate the input dataset to a SfM_Data scene
149 const SfM_Data sfm_data = getInputScene(d, config, PINHOLE_CAMERA);
150
151 // Remove poses and structure
152 SfM_Data sfm_data_2 = sfm_data;
153 sfm_data_2.poses.clear();
154 sfm_data_2.structure.clear();
155
156 GlobalSfMReconstructionEngine_RelativeMotions sfmEngine(
157 sfm_data_2,
158 "./",
159 stlplus::create_filespec("./", "Reconstruction_Report.html"));
160
161 // Configure the features_provider & the matches_provider from the synthetic dataset
162 std::shared_ptr<Features_Provider> feats_provider =
163 std::make_shared<Synthetic_Features_Provider>();
164 // Add a tiny noise in 2D observations to make data more realistic
165 std::normal_distribution<double> distribution(0.0,0.5);
166 dynamic_cast<Synthetic_Features_Provider*>(feats_provider.get())->load(d,distribution);
167
168 std::shared_ptr<Matches_Provider> matches_provider =
169 std::make_shared<Synthetic_Matches_Provider>();
170 dynamic_cast<Synthetic_Matches_Provider*>(matches_provider.get())->load(d);
171
172 // Configure data provider (Features and Matches)
173 sfmEngine.SetFeaturesProvider(feats_provider.get());
174 sfmEngine.SetMatchesProvider(matches_provider.get());
175
176 // Configure reconstruction parameters (intrinsic parameters are held constant)
177 sfmEngine.Set_Intrinsics_Refinement_Type(cameras::Intrinsic_Parameter_Type::NONE);
178
179 // Configure motion averaging method
180 sfmEngine.SetRotationAveragingMethod(ROTATION_AVERAGING_L2);
181 sfmEngine.SetTranslationAveragingMethod(TRANSLATION_AVERAGING_L2_DISTANCE_CHORDAL);
182
183 EXPECT_TRUE (sfmEngine.Process());
184
185 const double dResidual = RMSE(sfmEngine.Get_SfM_Data());
186 std::cout << "RMSE residual: " << dResidual << std::endl;
187 EXPECT_TRUE( dResidual < 0.5);
188 EXPECT_EQ( nviews, sfmEngine.Get_SfM_Data().GetPoses().size());
189 EXPECT_EQ( npoints, sfmEngine.Get_SfM_Data().GetLandmarks().size());
190 EXPECT_TRUE( IsTracksOneCC(sfmEngine.Get_SfM_Data()));
191 }
192
TEST(GLOBAL_SFM,RotationAveragingL2_TranslationAveragingSoftL1)193 TEST(GLOBAL_SFM, RotationAveragingL2_TranslationAveragingSoftL1) {
194
195 const int nviews = 6;
196 const int npoints = 64;
197 const nViewDatasetConfigurator config;
198 const NViewDataSet d = NRealisticCamerasRing(nviews, npoints, config);
199
200 // Translate the input dataset to a SfM_Data scene
201 const SfM_Data sfm_data = getInputScene(d, config, PINHOLE_CAMERA);
202
203 // Remove poses and structure
204 SfM_Data sfm_data_2 = sfm_data;
205 sfm_data_2.poses.clear();
206 sfm_data_2.structure.clear();
207
208 GlobalSfMReconstructionEngine_RelativeMotions sfmEngine(
209 sfm_data_2,
210 "./",
211 stlplus::create_filespec("./", "Reconstruction_Report.html"));
212
213 // Configure the features_provider & the matches_provider from the synthetic dataset
214 std::shared_ptr<Features_Provider> feats_provider =
215 std::make_shared<Synthetic_Features_Provider>();
216 // Add a tiny noise in 2D observations to make data more realistic
217 std::normal_distribution<double> distribution(0.0,0.5);
218 dynamic_cast<Synthetic_Features_Provider*>(feats_provider.get())->load(d,distribution);
219
220 std::shared_ptr<Matches_Provider> matches_provider =
221 std::make_shared<Synthetic_Matches_Provider>();
222 dynamic_cast<Synthetic_Matches_Provider*>(matches_provider.get())->load(d);
223
224 // Configure data provider (Features and Matches)
225 sfmEngine.SetFeaturesProvider(feats_provider.get());
226 sfmEngine.SetMatchesProvider(matches_provider.get());
227
228 // Configure reconstruction parameters (intrinsic parameters are held constant)
229 sfmEngine.Set_Intrinsics_Refinement_Type(cameras::Intrinsic_Parameter_Type::NONE);
230
231 // Configure motion averaging methods
232 sfmEngine.SetRotationAveragingMethod(ROTATION_AVERAGING_L2);
233 sfmEngine.SetTranslationAveragingMethod(TRANSLATION_AVERAGING_SOFTL1);
234
235 EXPECT_TRUE (sfmEngine.Process());
236
237 const double dResidual = RMSE(sfmEngine.Get_SfM_Data());
238 std::cout << "RMSE residual: " << dResidual << std::endl;
239 EXPECT_TRUE( dResidual < 0.5);
240 EXPECT_EQ( nviews, sfmEngine.Get_SfM_Data().GetPoses().size());
241 EXPECT_EQ( npoints, sfmEngine.Get_SfM_Data().GetLandmarks().size());
242 EXPECT_TRUE( IsTracksOneCC(sfmEngine.Get_SfM_Data()));
243 }
244
245 /* ************************************************************************* */
main()246 int main() { TestResult tr; return TestRegistry::runAllTests(tr);}
247 /* ************************************************************************* */
248