ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
reconstruction_test.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 #define TEST_NAME "base/reconstruction"
33 #include "util/testing.h"
34 
35 #include "base/camera_models.h"
37 #include "base/pose.h"
38 #include "base/reconstruction.h"
40 
41 using namespace colmap;
42 
43 void GenerateReconstruction(const image_t num_images,
44  Reconstruction* reconstruction,
45  CorrespondenceGraph* correspondence_graph) {
46  const size_t kNumPoints2D = 10;
47 
48  Camera camera;
49  camera.SetCameraId(1);
50  camera.InitializeWithName("PINHOLE", 1, 1, 1);
51  reconstruction->AddCamera(camera);
52 
53  for (image_t image_id = 1; image_id <= num_images; ++image_id) {
54  Image image;
55  image.SetImageId(image_id);
56  image.SetCameraId(1);
57  image.SetName("image" + std::to_string(image_id));
58  image.SetPoints2D(
59  std::vector<Eigen::Vector2d>(kNumPoints2D, Eigen::Vector2d::Zero()));
60  reconstruction->AddImage(image);
61  reconstruction->RegisterImage(image_id);
62  correspondence_graph->AddImage(image_id, kNumPoints2D);
63  }
64 
65  reconstruction->SetUp(correspondence_graph);
66 }
67 
69  Reconstruction reconstruction;
70  BOOST_CHECK_EQUAL(reconstruction.NumCameras(), 0);
71  BOOST_CHECK_EQUAL(reconstruction.NumImages(), 0);
72  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 0);
73  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
74  BOOST_CHECK_EQUAL(reconstruction.NumImagePairs(), 0);
75 }
76 
77 BOOST_AUTO_TEST_CASE(TestAddCamera) {
78  Reconstruction reconstruction;
79  Camera camera;
80  camera.SetCameraId(1);
82  reconstruction.AddCamera(camera);
83  BOOST_CHECK(reconstruction.ExistsCamera(camera.CameraId()));
84  BOOST_CHECK_EQUAL(reconstruction.Camera(camera.CameraId()).CameraId(),
85  camera.CameraId());
86  BOOST_CHECK_EQUAL(reconstruction.Cameras().count(camera.CameraId()), 1);
87  BOOST_CHECK_EQUAL(reconstruction.Cameras().size(), 1);
88  BOOST_CHECK_EQUAL(reconstruction.NumCameras(), 1);
89  BOOST_CHECK_EQUAL(reconstruction.NumImages(), 0);
90  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 0);
91  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
92  BOOST_CHECK_EQUAL(reconstruction.NumImagePairs(), 0);
93 }
94 
95 BOOST_AUTO_TEST_CASE(TestAddImage) {
96  Reconstruction reconstruction;
97  Image image;
98  image.SetImageId(1);
99  reconstruction.AddImage(image);
100  BOOST_CHECK(reconstruction.ExistsImage(1));
101  BOOST_CHECK_EQUAL(reconstruction.Image(1).ImageId(), 1);
102  BOOST_CHECK_EQUAL(reconstruction.Image(1).IsRegistered(), false);
103  BOOST_CHECK_EQUAL(reconstruction.Images().count(1), 1);
104  BOOST_CHECK_EQUAL(reconstruction.Images().size(), 1);
105  BOOST_CHECK_EQUAL(reconstruction.NumCameras(), 0);
106  BOOST_CHECK_EQUAL(reconstruction.NumImages(), 1);
107  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 0);
108  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
109  BOOST_CHECK_EQUAL(reconstruction.NumImagePairs(), 0);
110 }
111 
112 BOOST_AUTO_TEST_CASE(TestAddPoint3D) {
113  Reconstruction reconstruction;
114  const point3D_t point3D_id =
115  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
116  BOOST_CHECK(reconstruction.ExistsPoint3D(point3D_id));
117  BOOST_CHECK_EQUAL(reconstruction.Point3D(point3D_id).Track().Length(), 0);
118  BOOST_CHECK_EQUAL(reconstruction.Points3D().count(point3D_id), 1);
119  BOOST_CHECK_EQUAL(reconstruction.Points3D().size(), 1);
120  BOOST_CHECK_EQUAL(reconstruction.NumCameras(), 0);
121  BOOST_CHECK_EQUAL(reconstruction.NumImages(), 0);
122  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 0);
123  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
124  BOOST_CHECK_EQUAL(reconstruction.NumImagePairs(), 0);
125  BOOST_CHECK_EQUAL(reconstruction.Point3DIds().count(point3D_id), 1);
126 }
127 
128 BOOST_AUTO_TEST_CASE(TestAddObservation) {
129  Reconstruction reconstruction;
130  CorrespondenceGraph correspondence_graph;
131  GenerateReconstruction(1, &reconstruction, &correspondence_graph);
132  Track track;
133  track.AddElement(1, 0);
134  const point3D_t point3D_id =
135  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), track);
136  BOOST_CHECK_EQUAL(reconstruction.Image(1).NumPoints3D(), 1);
137  BOOST_CHECK(reconstruction.Image(1).Point2D(0).HasPoint3D());
138  BOOST_CHECK(!reconstruction.Image(1).Point2D(1).HasPoint3D());
139  BOOST_CHECK_EQUAL(reconstruction.Point3D(point3D_id).Track().Length(), 1);
140  reconstruction.AddObservation(point3D_id, TrackElement(1, 1));
141  BOOST_CHECK_EQUAL(reconstruction.Image(1).NumPoints3D(), 2);
142  BOOST_CHECK(reconstruction.Image(1).Point2D(0).HasPoint3D());
143  BOOST_CHECK(reconstruction.Image(1).Point2D(1).HasPoint3D());
144  BOOST_CHECK_EQUAL(reconstruction.Point3D(point3D_id).Track().Length(), 2);
145 }
146 
147 BOOST_AUTO_TEST_CASE(TestMergePoints3D) {
148  Reconstruction reconstruction;
149  CorrespondenceGraph correspondence_graph;
150  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
151  const point3D_t point3D_id1 =
152  reconstruction.AddPoint3D(Eigen::Vector3d(0, 0, 0), Track());
153  reconstruction.AddObservation(point3D_id1, TrackElement(1, 0));
154  reconstruction.AddObservation(point3D_id1, TrackElement(2, 0));
155  reconstruction.Point3D(point3D_id1).Color() =
156  Eigen::Matrix<uint8_t, 3, 1>(0, 0, 0);
157  const point3D_t point3D_id2 =
158  reconstruction.AddPoint3D(Eigen::Vector3d(1, 1, 1), Track());
159  reconstruction.AddObservation(point3D_id2, TrackElement(1, 1));
160  reconstruction.AddObservation(point3D_id2, TrackElement(2, 1));
161  reconstruction.Point3D(point3D_id2).Color() =
162  Eigen::Matrix<uint8_t, 3, 1>(20, 20, 20);
163  const point3D_t merged_point3D_id =
164  reconstruction.MergePoints3D(point3D_id1, point3D_id2);
165  BOOST_CHECK(!reconstruction.ExistsPoint3D(point3D_id1));
166  BOOST_CHECK(!reconstruction.ExistsPoint3D(point3D_id2));
167  BOOST_CHECK(reconstruction.ExistsPoint3D(merged_point3D_id));
168  BOOST_CHECK_EQUAL(reconstruction.Image(1).Point2D(0).Point3DId(),
169  merged_point3D_id);
170  BOOST_CHECK_EQUAL(reconstruction.Image(1).Point2D(1).Point3DId(),
171  merged_point3D_id);
172  BOOST_CHECK_EQUAL(reconstruction.Image(2).Point2D(0).Point3DId(),
173  merged_point3D_id);
174  BOOST_CHECK_EQUAL(reconstruction.Image(2).Point2D(1).Point3DId(),
175  merged_point3D_id);
176  BOOST_CHECK(reconstruction.Point3D(merged_point3D_id)
177  .XYZ()
178  .isApprox(Eigen::Vector3d(0.5, 0.5, 0.5)));
179  BOOST_CHECK_EQUAL(reconstruction.Point3D(merged_point3D_id).Color(),
180  Eigen::Vector3ub(10, 10, 10));
181 }
182 
183 BOOST_AUTO_TEST_CASE(TestDeletePoint3D) {
184  Reconstruction reconstruction;
185  CorrespondenceGraph correspondence_graph;
186  GenerateReconstruction(1, &reconstruction, &correspondence_graph);
187  const point3D_t point3D_id =
188  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
189  reconstruction.AddObservation(point3D_id, TrackElement(1, 0));
190  reconstruction.DeletePoint3D(point3D_id);
191  BOOST_CHECK(!reconstruction.ExistsPoint3D(point3D_id));
192  BOOST_CHECK_EQUAL(reconstruction.Image(1).NumPoints3D(), 0);
193 }
194 
195 BOOST_AUTO_TEST_CASE(TestDeleteObservation) {
196  Reconstruction reconstruction;
197  CorrespondenceGraph correspondence_graph;
198  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
199  const point3D_t point3D_id =
200  reconstruction.AddPoint3D(Eigen::Vector3d(0, 0, 0), Track());
201  reconstruction.AddObservation(point3D_id, TrackElement(1, 0));
202  reconstruction.AddObservation(point3D_id, TrackElement(1, 1));
203  reconstruction.AddObservation(point3D_id, TrackElement(1, 2));
204  reconstruction.DeleteObservation(1, 0);
205  BOOST_CHECK_EQUAL(reconstruction.Point3D(point3D_id).Track().Length(), 2);
206  BOOST_CHECK(!reconstruction.Image(point3D_id).Point2D(0).HasPoint3D());
207  reconstruction.DeleteObservation(1, 1);
208  BOOST_CHECK(!reconstruction.ExistsPoint3D(point3D_id));
209  BOOST_CHECK(!reconstruction.Image(point3D_id).Point2D(1).HasPoint3D());
210  BOOST_CHECK(!reconstruction.Image(point3D_id).Point2D(2).HasPoint3D());
211 }
212 
213 BOOST_AUTO_TEST_CASE(TestRegisterImage) {
214  Reconstruction reconstruction;
215  CorrespondenceGraph correspondence_graph;
216  GenerateReconstruction(1, &reconstruction, &correspondence_graph);
217  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 1);
218  BOOST_CHECK_EQUAL(reconstruction.Image(1).IsRegistered(), true);
219  BOOST_CHECK(reconstruction.IsImageRegistered(1));
220  reconstruction.RegisterImage(1);
221  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 1);
222  BOOST_CHECK_EQUAL(reconstruction.Image(1).IsRegistered(), true);
223  BOOST_CHECK(reconstruction.IsImageRegistered(1));
224  reconstruction.DeRegisterImage(1);
225  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 0);
226  BOOST_CHECK_EQUAL(reconstruction.Image(1).IsRegistered(), false);
227  BOOST_CHECK(!reconstruction.IsImageRegistered(1));
228 }
229 
230 BOOST_AUTO_TEST_CASE(TestNormalize) {
231  Reconstruction reconstruction;
232  CorrespondenceGraph correspondence_graph;
233  GenerateReconstruction(3, &reconstruction, &correspondence_graph);
234  reconstruction.Image(1).Tvec(2) = -10.0;
235  reconstruction.Image(2).Tvec(2) = 0.0;
236  reconstruction.Image(3).Tvec(2) = 10.0;
237  reconstruction.DeRegisterImage(1);
238  reconstruction.DeRegisterImage(2);
239  reconstruction.DeRegisterImage(3);
240  reconstruction.Normalize();
241  BOOST_CHECK_LT(std::abs(reconstruction.Image(1).Tvec(2) + 10), 1e-6);
242  BOOST_CHECK_LT(std::abs(reconstruction.Image(2).Tvec(2)), 1e-6);
243  BOOST_CHECK_LT(std::abs(reconstruction.Image(3).Tvec(2) - 10), 1e-6);
244  reconstruction.RegisterImage(1);
245  reconstruction.RegisterImage(2);
246  reconstruction.RegisterImage(3);
247  reconstruction.Normalize();
248  BOOST_CHECK_LT(std::abs(reconstruction.Image(1).Tvec(2) + 5), 1e-6);
249  BOOST_CHECK_LT(std::abs(reconstruction.Image(2).Tvec(2)), 1e-6);
250  BOOST_CHECK_LT(std::abs(reconstruction.Image(3).Tvec(2) - 5), 1e-6);
251  reconstruction.Normalize(5);
252  BOOST_CHECK_LT(std::abs(reconstruction.Image(1).Tvec(2) + 2.5), 1e-6);
253  BOOST_CHECK_LT(std::abs(reconstruction.Image(2).Tvec(2)), 1e-6);
254  BOOST_CHECK_LT(std::abs(reconstruction.Image(3).Tvec(2) - 2.5), 1e-6);
255  reconstruction.Normalize(10, 0.0, 1.0);
256  BOOST_CHECK_LT(std::abs(reconstruction.Image(1).Tvec(2) + 5), 1e-6);
257  BOOST_CHECK_LT(std::abs(reconstruction.Image(2).Tvec(2)), 1e-6);
258  BOOST_CHECK_LT(std::abs(reconstruction.Image(3).Tvec(2) - 5), 1e-6);
259  reconstruction.Normalize(20);
260  Image image;
261  image.SetImageId(4);
262  reconstruction.AddImage(image);
263  reconstruction.RegisterImage(4);
264  image.SetImageId(5);
265  reconstruction.AddImage(image);
266  reconstruction.RegisterImage(5);
267  image.SetImageId(6);
268  reconstruction.AddImage(image);
269  reconstruction.RegisterImage(6);
270  image.SetImageId(7);
271  reconstruction.AddImage(image);
272  reconstruction.RegisterImage(7);
273  reconstruction.Image(4).Tvec(2) = -7.5;
274  reconstruction.Image(5).Tvec(2) = -5.0;
275  reconstruction.Image(6).Tvec(2) = 5.0;
276  reconstruction.Image(7).Tvec(2) = 7.5;
277  reconstruction.RegisterImage(7);
278  reconstruction.Normalize(10, 0.0, 1.0);
279  BOOST_CHECK_LT(std::abs(reconstruction.Image(1).Tvec(2) + 5), 1e-6);
280  BOOST_CHECK_LT(std::abs(reconstruction.Image(2).Tvec(2)), 1e-6);
281  BOOST_CHECK_LT(std::abs(reconstruction.Image(3).Tvec(2) - 5), 1e-6);
282  BOOST_CHECK_LT(std::abs(reconstruction.Image(4).Tvec(2) + 3.75), 1e-6);
283  BOOST_CHECK_LT(std::abs(reconstruction.Image(5).Tvec(2) + 2.5), 1e-6);
284  BOOST_CHECK_LT(std::abs(reconstruction.Image(6).Tvec(2) - 2.5), 1e-6);
285  BOOST_CHECK_LT(std::abs(reconstruction.Image(7).Tvec(2) - 3.75), 1e-6);
286 }
287 
288 BOOST_AUTO_TEST_CASE(TestComputeBoundsAndCentroid) {
289  Reconstruction reconstruction;
290 
291  // Test emtpy reconstruction first
292  auto centroid = reconstruction.ComputeCentroid(0.0, 1.0);
293  auto bbox = reconstruction.ComputeBoundingBox(0.0, 1.0);
294  BOOST_CHECK_LT(std::abs(centroid(0)), 1e-6);
295  BOOST_CHECK_LT(std::abs(centroid(1)), 1e-6);
296  BOOST_CHECK_LT(std::abs(centroid(2)), 1e-6);
297  BOOST_CHECK_LT(std::abs(bbox.first(0)), 1e-6);
298  BOOST_CHECK_LT(std::abs(bbox.first(1)), 1e-6);
299  BOOST_CHECK_LT(std::abs(bbox.first(2)), 1e-6);
300  BOOST_CHECK_LT(std::abs(bbox.second(0)), 1e-6);
301  BOOST_CHECK_LT(std::abs(bbox.second(1)), 1e-6);
302  BOOST_CHECK_LT(std::abs(bbox.second(2)), 1e-6);
303 
304  // Test reconstruction with 3D points
305  reconstruction.AddPoint3D(Eigen::Vector3d(3.0, 0.0, 0.0), Track());
306  reconstruction.AddPoint3D(Eigen::Vector3d(0.0, 3.0, 0.0), Track());
307  reconstruction.AddPoint3D(Eigen::Vector3d(0.0, 0.0, 3.0), Track());
308  centroid = reconstruction.ComputeCentroid(0.0, 1.0);
309  bbox = reconstruction.ComputeBoundingBox(0.0, 1.0);
310  BOOST_CHECK_LT(std::abs(centroid(0) - 1.0), 1e-6);
311  BOOST_CHECK_LT(std::abs(centroid(1) - 1.0), 1e-6);
312  BOOST_CHECK_LT(std::abs(centroid(2) - 1.0), 1e-6);
313  BOOST_CHECK_LT(std::abs(bbox.first(0)), 1e-6);
314  BOOST_CHECK_LT(std::abs(bbox.first(1)), 1e-6);
315  BOOST_CHECK_LT(std::abs(bbox.first(2)), 1e-6);
316  BOOST_CHECK_LT(std::abs(bbox.second(0) - 3.0), 1e-6);
317  BOOST_CHECK_LT(std::abs(bbox.second(1) - 3.0), 1e-6);
318  BOOST_CHECK_LT(std::abs(bbox.second(2) - 3.0), 1e-6);
319 }
320 
322  Reconstruction reconstruction;
323  CorrespondenceGraph correspondence_graph;
324  GenerateReconstruction(3, &reconstruction, &correspondence_graph);
325  point3D_t point_id =
326  reconstruction.AddPoint3D(Eigen::Vector3d(0.0, 0.0, 0.0), Track());
327  reconstruction.AddObservation(point_id, TrackElement(1, 1));
328  point_id = reconstruction.AddPoint3D(Eigen::Vector3d(0.5, 0.5, 0.0), Track());
329  reconstruction.AddObservation(point_id, TrackElement(1, 2));
330  point_id = reconstruction.AddPoint3D(Eigen::Vector3d(1.0, 1.0, 0.0), Track());
331  reconstruction.AddObservation(point_id, TrackElement(2, 3));
332  point_id = reconstruction.AddPoint3D(Eigen::Vector3d(0.0, 0.0, 0.5), Track());
333  reconstruction.AddObservation(point_id, TrackElement(2, 4));
334  point_id = reconstruction.AddPoint3D(Eigen::Vector3d(0.5, 0.5, 1.0), Track());
335  reconstruction.AddObservation(point_id, TrackElement(3, 5));
336 
337  // Check correct reconstruction setup
338  BOOST_CHECK_EQUAL(reconstruction.NumCameras(), 1);
339  BOOST_CHECK_EQUAL(reconstruction.NumImages(), 3);
340  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 3);
341  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 5);
342 
343  std::pair<Eigen::Vector3d, Eigen::Vector3d> bbox;
344 
345  // Test emtpy reconstruction after cropping
346  bbox.first = Eigen::Vector3d(-1, -1, -1);
347  bbox.second = Eigen::Vector3d(-0.5, -0.5, -0.5);
348  Reconstruction recon1 = reconstruction.Crop(bbox);
349  BOOST_CHECK_EQUAL(recon1.NumCameras(), 1);
350  BOOST_CHECK_EQUAL(recon1.NumImages(), 3);
351  BOOST_CHECK_EQUAL(recon1.NumRegImages(), 0);
352  BOOST_CHECK_EQUAL(recon1.NumPoints3D(), 0);
353 
354  // Test reconstruction with contents after cropping
355  bbox.first = Eigen::Vector3d(0.0, 0.0, 0.0);
356  bbox.second = Eigen::Vector3d(0.75, 0.75, 0.75);
357  Reconstruction recon2 = reconstruction.Crop(bbox);
358  BOOST_CHECK_EQUAL(recon2.NumCameras(), 1);
359  BOOST_CHECK_EQUAL(recon2.NumImages(), 3);
360  BOOST_CHECK_EQUAL(recon2.NumRegImages(), 2);
361  BOOST_CHECK_EQUAL(recon2.NumPoints3D(), 3);
362  BOOST_CHECK(recon2.IsImageRegistered(1));
363  BOOST_CHECK(recon2.IsImageRegistered(2));
364  BOOST_CHECK(!recon2.IsImageRegistered(3));
365 }
366 
367 BOOST_AUTO_TEST_CASE(TestTransform) {
368  Reconstruction reconstruction;
369  CorrespondenceGraph correspondence_graph;
370  GenerateReconstruction(3, &reconstruction, &correspondence_graph);
371  const point3D_t point3D_id =
372  reconstruction.AddPoint3D(Eigen::Vector3d(1, 1, 1), Track());
373  reconstruction.AddObservation(point3D_id, TrackElement(1, 1));
374  reconstruction.AddObservation(point3D_id, TrackElement(2, 1));
376  Eigen::Vector3d(0, 1, 2)));
377  BOOST_CHECK_EQUAL(reconstruction.Image(1).ProjectionCenter(),
378  Eigen::Vector3d(0, 1, 2));
379  BOOST_CHECK_EQUAL(reconstruction.Point3D(point3D_id).XYZ(),
380  Eigen::Vector3d(2, 3, 4));
381 }
382 
383 BOOST_AUTO_TEST_CASE(TestFindImageWithName) {
384  Reconstruction reconstruction;
385  CorrespondenceGraph correspondence_graph;
386  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
387  BOOST_CHECK_EQUAL(reconstruction.FindImageWithName("image1"),
388  &reconstruction.Image(1));
389  BOOST_CHECK_EQUAL(reconstruction.FindImageWithName("image2"),
390  &reconstruction.Image(2));
391  BOOST_CHECK(reconstruction.FindImageWithName("image3") == nullptr);
392 }
393 
394 BOOST_AUTO_TEST_CASE(TestFilterPoints3D) {
395  Reconstruction reconstruction;
396  CorrespondenceGraph correspondence_graph;
397  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
398  const point3D_t point3D_id1 =
399  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
400  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
401  reconstruction.FilterPoints3D(0.0, 0.0, std::unordered_set<point3D_t>{});
402  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
403  reconstruction.FilterPoints3D(0.0, 0.0,
404  std::unordered_set<point3D_t>{point3D_id1 + 1});
405  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
406  reconstruction.FilterPoints3D(0.0, 0.0,
407  std::unordered_set<point3D_t>{point3D_id1});
408  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
409  const point3D_t point3D_id2 =
410  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
411  reconstruction.AddObservation(point3D_id2, TrackElement(1, 0));
412  reconstruction.FilterPoints3D(0.0, 0.0,
413  std::unordered_set<point3D_t>{point3D_id2});
414  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
415  const point3D_t point3D_id3 =
416  reconstruction.AddPoint3D(Eigen::Vector3d(-0.5, -0.5, 1), Track());
417  reconstruction.AddObservation(point3D_id3, TrackElement(1, 0));
418  reconstruction.AddObservation(point3D_id3, TrackElement(2, 0));
419  reconstruction.FilterPoints3D(0.0, 0.0,
420  std::unordered_set<point3D_t>{point3D_id3});
421  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
422  reconstruction.FilterPoints3D(0.0, 1e-3,
423  std::unordered_set<point3D_t>{point3D_id3});
424  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
425  const point3D_t point3D_id4 =
426  reconstruction.AddPoint3D(Eigen::Vector3d(-0.6, -0.5, 1), Track());
427  reconstruction.AddObservation(point3D_id4, TrackElement(1, 0));
428  reconstruction.AddObservation(point3D_id4, TrackElement(2, 0));
429  reconstruction.FilterPoints3D(0.1, 0.0,
430  std::unordered_set<point3D_t>{point3D_id4});
431  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
432  reconstruction.FilterPoints3D(0.09, 0.0,
433  std::unordered_set<point3D_t>{point3D_id4});
434  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
435 }
436 
437 BOOST_AUTO_TEST_CASE(TestFilterPoints3DInImages) {
438  Reconstruction reconstruction;
439  CorrespondenceGraph correspondence_graph;
440  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
441  const point3D_t point3D_id1 =
442  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
443  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
444  reconstruction.FilterPoints3DInImages(0.0, 0.0,
445  std::unordered_set<image_t>{});
446  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
447  reconstruction.FilterPoints3DInImages(0.0, 0.0,
448  std::unordered_set<image_t>{1});
449  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
450  reconstruction.AddObservation(point3D_id1, TrackElement(1, 0));
451  reconstruction.FilterPoints3DInImages(0.0, 0.0,
452  std::unordered_set<image_t>{2});
453  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
454  reconstruction.FilterPoints3DInImages(0.0, 0.0,
455  std::unordered_set<image_t>{1});
456  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
457  const point3D_t point3D_id3 =
458  reconstruction.AddPoint3D(Eigen::Vector3d(-0.5, -0.5, 1), Track());
459  reconstruction.AddObservation(point3D_id3, TrackElement(1, 0));
460  reconstruction.AddObservation(point3D_id3, TrackElement(2, 0));
461  reconstruction.FilterPoints3DInImages(0.0, 0.0,
462  std::unordered_set<image_t>{1});
463  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
464  reconstruction.FilterPoints3DInImages(0.0, 1e-3,
465  std::unordered_set<image_t>{1});
466  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
467  const point3D_t point3D_id4 =
468  reconstruction.AddPoint3D(Eigen::Vector3d(-0.6, -0.5, 1), Track());
469  reconstruction.AddObservation(point3D_id4, TrackElement(1, 0));
470  reconstruction.AddObservation(point3D_id4, TrackElement(2, 0));
471  reconstruction.FilterPoints3DInImages(0.1, 0.0,
472  std::unordered_set<image_t>{1});
473  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
474  reconstruction.FilterPoints3DInImages(0.09, 0.0,
475  std::unordered_set<image_t>{1});
476  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
477 }
478 
479 BOOST_AUTO_TEST_CASE(TestFilterAllPoints) {
480  Reconstruction reconstruction;
481  CorrespondenceGraph correspondence_graph;
482  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
483  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
484  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
485  reconstruction.FilterAllPoints3D(0.0, 0.0);
486  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
487  const point3D_t point3D_id2 =
488  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
489  reconstruction.AddObservation(point3D_id2, TrackElement(1, 0));
490  reconstruction.FilterAllPoints3D(0.0, 0.0);
491  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
492  const point3D_t point3D_id3 =
493  reconstruction.AddPoint3D(Eigen::Vector3d(-0.5, -0.5, 1), Track());
494  reconstruction.AddObservation(point3D_id3, TrackElement(1, 0));
495  reconstruction.AddObservation(point3D_id3, TrackElement(2, 0));
496  reconstruction.FilterAllPoints3D(0.0, 0.0);
497  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
498  reconstruction.FilterAllPoints3D(0.0, 1e-3);
499  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
500  const point3D_t point3D_id4 =
501  reconstruction.AddPoint3D(Eigen::Vector3d(-0.6, -0.5, 1), Track());
502  reconstruction.AddObservation(point3D_id4, TrackElement(1, 0));
503  reconstruction.AddObservation(point3D_id4, TrackElement(2, 0));
504  reconstruction.FilterAllPoints3D(0.1, 0.0);
505  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
506  reconstruction.FilterAllPoints3D(0.09, 0.0);
507  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
508 }
509 
510 BOOST_AUTO_TEST_CASE(TestFilterObservationsWithNegativeDepth) {
511  Reconstruction reconstruction;
512  CorrespondenceGraph correspondence_graph;
513  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
514  const point3D_t point3D_id1 =
515  reconstruction.AddPoint3D(Eigen::Vector3d(0, 0, 1), Track());
516  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
517  reconstruction.FilterObservationsWithNegativeDepth();
518  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
519  reconstruction.Point3D(point3D_id1).XYZ(2) = 0.001;
520  reconstruction.FilterObservationsWithNegativeDepth();
521  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
522  reconstruction.Point3D(point3D_id1).XYZ(2) = 0.0;
523  reconstruction.FilterObservationsWithNegativeDepth();
524  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
525  reconstruction.AddObservation(point3D_id1, TrackElement(1, 0));
526  reconstruction.Point3D(point3D_id1).XYZ(2) = 0.001;
527  reconstruction.FilterObservationsWithNegativeDepth();
528  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 1);
529  reconstruction.Point3D(point3D_id1).XYZ(2) = 0.0;
530  reconstruction.FilterObservationsWithNegativeDepth();
531  BOOST_CHECK_EQUAL(reconstruction.NumPoints3D(), 0);
532 }
533 
534 BOOST_AUTO_TEST_CASE(TestFilterImages) {
535  Reconstruction reconstruction;
536  CorrespondenceGraph correspondence_graph;
537  GenerateReconstruction(4, &reconstruction, &correspondence_graph);
538  const point3D_t point3D_id1 =
539  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
540  reconstruction.AddObservation(point3D_id1, TrackElement(1, 0));
541  reconstruction.AddObservation(point3D_id1, TrackElement(2, 0));
542  reconstruction.AddObservation(point3D_id1, TrackElement(3, 0));
543  reconstruction.FilterImages(0.0, 10.0, 1.0);
544  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 3);
545  reconstruction.DeleteObservation(3, 0);
546  reconstruction.FilterImages(0.0, 10.0, 1.0);
547  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 2);
548  reconstruction.FilterImages(0.0, 0.9, 1.0);
549  BOOST_CHECK_EQUAL(reconstruction.NumRegImages(), 0);
550 }
551 
552 BOOST_AUTO_TEST_CASE(TestComputeNumObservations) {
553  Reconstruction reconstruction;
554  CorrespondenceGraph correspondence_graph;
555  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
556  const point3D_t point3D_id1 =
557  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
558  BOOST_CHECK_EQUAL(reconstruction.ComputeNumObservations(), 0);
559  reconstruction.AddObservation(point3D_id1, TrackElement(1, 0));
560  BOOST_CHECK_EQUAL(reconstruction.ComputeNumObservations(), 1);
561  reconstruction.AddObservation(point3D_id1, TrackElement(1, 1));
562  BOOST_CHECK_EQUAL(reconstruction.ComputeNumObservations(), 2);
563  reconstruction.AddObservation(point3D_id1, TrackElement(2, 0));
564  BOOST_CHECK_EQUAL(reconstruction.ComputeNumObservations(), 3);
565 }
566 
567 BOOST_AUTO_TEST_CASE(TestComputeMeanTrackLength) {
568  Reconstruction reconstruction;
569  CorrespondenceGraph correspondence_graph;
570  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
571  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanTrackLength(), 0);
572  const point3D_t point3D_id1 =
573  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
574  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanTrackLength(), 0);
575  reconstruction.AddObservation(point3D_id1, TrackElement(1, 0));
576  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanTrackLength(), 1);
577  reconstruction.AddObservation(point3D_id1, TrackElement(1, 1));
578  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanTrackLength(), 2);
579  reconstruction.AddObservation(point3D_id1, TrackElement(2, 0));
580  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanTrackLength(), 3);
581 }
582 
583 BOOST_AUTO_TEST_CASE(TestComputeMeanObservationsPerRegImage) {
584  Reconstruction reconstruction;
585  CorrespondenceGraph correspondence_graph;
586  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
587  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanObservationsPerRegImage(), 0);
588  const point3D_t point3D_id1 =
589  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
590  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanObservationsPerRegImage(), 0);
591  reconstruction.AddObservation(point3D_id1, TrackElement(1, 0));
592  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanObservationsPerRegImage(), 0.5);
593  reconstruction.AddObservation(point3D_id1, TrackElement(1, 1));
594  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanObservationsPerRegImage(), 1.0);
595  reconstruction.AddObservation(point3D_id1, TrackElement(2, 0));
596  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanObservationsPerRegImage(), 1.5);
597 }
598 
599 BOOST_AUTO_TEST_CASE(TestComputeMeanReprojectionError) {
600  Reconstruction reconstruction;
601  CorrespondenceGraph correspondence_graph;
602  GenerateReconstruction(2, &reconstruction, &correspondence_graph);
603  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanReprojectionError(), 0);
604  const point3D_t point3D_id1 =
605  reconstruction.AddPoint3D(Eigen::Vector3d::Random(), Track());
606  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanReprojectionError(), 0);
607  reconstruction.Point3D(point3D_id1).SetError(0.0);
608  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanReprojectionError(), 0);
609  reconstruction.Point3D(point3D_id1).SetError(1.0);
610  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanReprojectionError(), 1);
611  reconstruction.Point3D(point3D_id1).SetError(2.0);
612  BOOST_CHECK_EQUAL(reconstruction.ComputeMeanReprojectionError(), 2.0);
613 }
std::shared_ptr< core::Tensor > image
void InitializeWithName(const std::string &model_name, const double focal_length, const size_t width, const size_t height)
Definition: camera.cc:212
void InitializeWithId(const int model_id, const double focal_length, const size_t width, const size_t height)
Definition: camera.cc:203
camera_t CameraId() const
Definition: camera.h:154
void SetCameraId(const camera_t camera_id)
Definition: camera.h:156
void AddImage(const image_t image_id, const size_t num_points2D)
point2D_t NumPoints3D() const
Definition: image.h:265
image_t ImageId() const
Definition: image.h:238
const Eigen::Vector3d & Tvec() const
Definition: image.h:325
const class Point2D & Point2D(const point2D_t point2D_idx) const
Definition: image.h:349
bool IsRegistered() const
Definition: image.h:257
Eigen::Vector3d ProjectionCenter() const
Definition: image.cc:152
point3D_t Point3DId() const
Definition: point2d.h:63
bool HasPoint3D() const
Definition: point2d.h:65
void SetError(const double error)
Definition: point3d.h:104
const Eigen::Vector3d & XYZ() const
Definition: point3d.h:74
const class Track & Track() const
Definition: point3d.h:106
const Eigen::Vector3ub & Color() const
Definition: point3d.h:90
size_t NumImages() const
size_t FilterAllPoints3D(const double max_reproj_error, const double min_tri_angle)
Reconstruction Crop(const std::pair< Eigen::Vector3d, Eigen::Vector3d > &bbox) const
double ComputeMeanTrackLength() const
point3D_t MergePoints3D(const point3D_t point3D_id1, const point3D_t point3D_id2)
size_t NumRegImages() const
void Transform(const SimilarityTransform3 &tform)
std::pair< Eigen::Vector3d, Eigen::Vector3d > ComputeBoundingBox(const double p0=0.0, const double p1=1.0) const
size_t FilterObservationsWithNegativeDepth()
void Normalize(const double extent=10.0, const double p0=0.1, const double p1=0.9, const bool use_images=true)
bool IsImageRegistered(const image_t image_id) const
void AddImage(const class Image &image)
const std::unordered_map< image_t, class Image > & Images() const
void AddCamera(const class Camera &camera)
std::vector< image_t > FilterImages(const double min_focal_length_ratio, const double max_focal_length_ratio, const double max_extra_param)
void DeleteObservation(const image_t image_id, const point2D_t point2D_idx)
size_t ComputeNumObservations() const
Eigen::Vector3d ComputeCentroid(const double p0=0.1, const double p1=0.9) const
const class Image & Image(const image_t image_id) const
std::unordered_set< point3D_t > Point3DIds() const
size_t NumPoints3D() const
const class Camera & Camera(const camera_t camera_id) const
const std::unordered_map< camera_t, class Camera > & Cameras() const
const std::unordered_map< point3D_t, class Point3D > & Points3D() const
bool ExistsCamera(const camera_t camera_id) const
void AddObservation(const point3D_t point3D_id, const TrackElement &track_el)
const class Image * FindImageWithName(const std::string &name) const
void DeRegisterImage(const image_t image_id)
size_t FilterPoints3D(const double max_reproj_error, const double min_tri_angle, const std::unordered_set< point3D_t > &point3D_ids)
size_t NumImagePairs() const
void DeletePoint3D(const point3D_t point3D_id)
double ComputeMeanReprojectionError() const
bool ExistsImage(const image_t image_id) const
double ComputeMeanObservationsPerRegImage() const
void RegisterImage(const image_t image_id)
size_t FilterPoints3DInImages(const double max_reproj_error, const double min_tri_angle, const std::unordered_set< image_t > &image_ids)
size_t NumCameras() const
const class Point3D & Point3D(const point3D_t point3D_id) const
point3D_t AddPoint3D(const Eigen::Vector3d &xyz, const Track &track, const Eigen::Vector3ub &color=Eigen::Vector3ub::Zero())
void SetUp(const CorrespondenceGraph *correspondence_graph)
bool ExistsPoint3D(const point3D_t point3D_id) const
void AddElement(const TrackElement &element)
Definition: track.h:103
size_t Length() const
Definition: track.h:82
const double * e
Matrix< uint8_t, 3, 1 > Vector3ub
Definition: types.h:42
uint64_t point3D_t
Definition: types.h:72
Eigen::Vector4d ComposeIdentityQuaternion()
Definition: pose.h:209
uint32_t image_t
Definition: types.h:61
std::string to_string(const T &n)
Definition: Common.h:20
BOOST_AUTO_TEST_CASE(TestEmpty)
void GenerateReconstruction(const image_t num_images, Reconstruction *reconstruction, CorrespondenceGraph *correspondence_graph)