ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
coordinate_frame_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 "estimators/coordinate_frame"
33 #include "util/testing.h"
34 
36 #include "base/gps.h"
37 
38 using namespace colmap;
39 
40 BOOST_AUTO_TEST_CASE(TestEstimateGravityVectorFromImageOrientation) {
41  Reconstruction reconstruction;
42  BOOST_CHECK_EQUAL(EstimateGravityVectorFromImageOrientation(reconstruction),
43  Eigen::Vector3d::Zero());
44 }
45 
46 BOOST_AUTO_TEST_CASE(TestEstimateManhattanWorldFrame) {
47  Reconstruction reconstruction;
48  std::string image_path;
49  BOOST_CHECK_EQUAL(
51  reconstruction, image_path),
52  Eigen::Matrix3d::Zero());
53 }
54 
55 BOOST_AUTO_TEST_CASE(TestAlignToPrincipalPlane) {
56  // Start with reconstruction containing points on the Y-Z plane and cameras
57  // "above" the plane on the positive X axis. After alignment the points should
58  // be on the X-Y plane and the cameras "above" the plane on the positive Z
59  // axis.
61  Reconstruction reconstruction;
62  // Setup image with projection center at (1, 0, 0)
63  Image image;
64  image.SetImageId(1);
65  image.Qvec() = Eigen::Vector4d(1.0, 0.0, 0.0, 0.0);
66  image.Tvec() = Eigen::Vector3d(-1.0, 0.0, 0.0);
67  reconstruction.AddImage(image);
68  // Setup 4 points on the Y-Z plane
69  point3D_t p1 =
70  reconstruction.AddPoint3D(Eigen::Vector3d(0.0, -1.0, 0.0), Track());
71  point3D_t p2 =
72  reconstruction.AddPoint3D(Eigen::Vector3d(0.0, 1.0, 0.0), Track());
73  point3D_t p3 =
74  reconstruction.AddPoint3D(Eigen::Vector3d(0.0, 0.0, -1.0), Track());
75  point3D_t p4 =
76  reconstruction.AddPoint3D(Eigen::Vector3d(0.0, 0.0, 1.0), Track());
77  AlignToPrincipalPlane(&reconstruction, &tform);
78  // Note that the final X and Y axes may be inverted after alignment, so we
79  // need to account for both cases when checking for correctness
80  const bool inverted = tform.Rotation()(2) < 0;
81 
82  // Verify that points lie on the correct locations of the X-Y plane
83  BOOST_CHECK_LE((reconstruction.Point3D(p1).XYZ() -
84  Eigen::Vector3d(inverted ? 1.0 : -1.0, 0.0, 0.0))
85  .norm(),
86  1e-6);
87  BOOST_CHECK_LE((reconstruction.Point3D(p2).XYZ() -
88  Eigen::Vector3d(inverted ? -1.0 : 1.0, 0.0, 0.0))
89  .norm(),
90  1e-6);
91  BOOST_CHECK_LE((reconstruction.Point3D(p3).XYZ() -
92  Eigen::Vector3d(0.0, inverted ? 1.0 : -1.0, 0.0))
93  .norm(),
94  1e-6);
95  BOOST_CHECK_LE((reconstruction.Point3D(p4).XYZ() -
96  Eigen::Vector3d(0.0, inverted ? -1.0 : 1.0, 0.0))
97  .norm(),
98  1e-6);
99  // Verify that projection center is at (0, 0, 1)
100  BOOST_CHECK_LE((reconstruction.Image(1).ProjectionCenter() -
101  Eigen::Vector3d(0.0, 0.0, 1.0))
102  .norm(),
103  1e-6);
104  // Verify that transform matrix does shuffling of axes
105  Eigen::Matrix4d mat;
106  if (inverted) {
107  mat << 0, -1, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 1;
108  } else {
109  mat << 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1;
110  }
111  std::cout << tform.Matrix() << std::endl;
112  BOOST_CHECK_LE((tform.Matrix() - mat).norm(), 1e-6);
113 }
114 
115 BOOST_AUTO_TEST_CASE(TestAlignToENUPlane) {
116  // Create reconstruction with 4 points with known LLA coordinates. After the
117  // ENU transform all 4 points should land approximately on the X-Y plane.
118  GPSTransform gps;
119  auto points = gps.EllToXYZ(
120  {Eigen::Vector3d(50, 10.1, 100), Eigen::Vector3d(50.1, 10, 100),
121  Eigen::Vector3d(50.1, 10.1, 100), Eigen::Vector3d(50, 10, 100)});
122  SimilarityTransform3 tform;
123  Reconstruction reconstruction;
124  std::vector<point3D_t> point_ids;
125  for (size_t i = 0; i < points.size(); ++i) {
126  point_ids.push_back(reconstruction.AddPoint3D(points[i], Track()));
127  std::cout << points[i].transpose() << std::endl;
128  }
129  AlignToENUPlane(&reconstruction, &tform, false);
130  // Verify final locations of points
131  BOOST_CHECK_LE((reconstruction.Point3D(point_ids[0]).XYZ() -
132  Eigen::Vector3d(3584.8565215, -5561.5336506, 0.0742643))
133  .norm(),
134  1e-6);
135  BOOST_CHECK_LE((reconstruction.Point3D(point_ids[1]).XYZ() -
136  Eigen::Vector3d(-3577.3888622, 5561.6397107, 0.0783761))
137  .norm(),
138  1e-6);
139  BOOST_CHECK_LE((reconstruction.Point3D(point_ids[2]).XYZ() -
140  Eigen::Vector3d(3577.4152111, 5561.6397283, 0.0783613))
141  .norm(),
142  1e-6);
143  BOOST_CHECK_LE((reconstruction.Point3D(point_ids[3]).XYZ() -
144  Eigen::Vector3d(-3584.8301178, -5561.5336683, 0.0742791))
145  .norm(),
146  1e-6);
147 
148  // Verify that straight line distance between points is preserved
149  for (size_t i = 1; i < points.size(); ++i) {
150  const double dist_orig = (points[i] - points[i - 1]).norm();
151  const double dist_tform = (reconstruction.Point3D(point_ids[i]).XYZ() -
152  reconstruction.Point3D(point_ids[i - 1]).XYZ())
153  .norm();
154  BOOST_CHECK_LE(std::abs(dist_orig - dist_tform), 1e-6);
155  }
156 
157 }
std::shared_ptr< core::Tensor > image
int points
std::vector< Eigen::Vector3d > EllToXYZ(const std::vector< Eigen::Vector3d > &ell) const
Definition: gps.cc:57
Eigen::Vector3d ProjectionCenter() const
Definition: image.cc:152
const Eigen::Vector3d & XYZ() const
Definition: point3d.h:74
void AddImage(const class Image &image)
const class Image & Image(const image_t image_id) 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())
Eigen::Matrix4d Matrix() const
Eigen::Vector4d Rotation() const
BOOST_AUTO_TEST_CASE(TestEstimateGravityVectorFromImageOrientation)
const double * e
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
uint64_t point3D_t
Definition: types.h:72
Eigen::Matrix3d EstimateManhattanWorldFrame(const ManhattanWorldFrameEstimationOptions &options, const Reconstruction &reconstruction, const std::string &image_path)
Eigen::Vector3d EstimateGravityVectorFromImageOrientation(const Reconstruction &reconstruction, const double max_axis_distance)
void AlignToENUPlane(Reconstruction *recon, SimilarityTransform3 *tform, bool unscaled)
void AlignToPrincipalPlane(Reconstruction *recon, SimilarityTransform3 *tform)