ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
undistortion_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/undistortion"
33 #include "util/testing.h"
34 
35 #include "base/pose.h"
36 #include "base/undistortion.h"
37 
38 using namespace colmap;
39 
40 BOOST_AUTO_TEST_CASE(TestUndistortCamera) {
41  UndistortCameraOptions options;
42  Camera distorted_camera;
43  Camera undistorted_camera;
44 
45  distorted_camera.InitializeWithName("SIMPLE_PINHOLE", 1, 1, 1);
46  undistorted_camera = UndistortCamera(options, distorted_camera);
47  BOOST_CHECK_EQUAL(undistorted_camera.ModelName(), "PINHOLE");
48  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthX(), 1);
49  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthY(), 1);
50  BOOST_CHECK_EQUAL(undistorted_camera.Width(), 1);
51  BOOST_CHECK_EQUAL(undistorted_camera.Height(), 1);
52 
53  distorted_camera.InitializeWithName("SIMPLE_RADIAL", 1, 1, 1);
54  undistorted_camera = UndistortCamera(options, distorted_camera);
55  BOOST_CHECK_EQUAL(undistorted_camera.ModelName(), "PINHOLE");
56  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthX(), 1);
57  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthY(), 1);
58  BOOST_CHECK_EQUAL(undistorted_camera.Width(), 1);
59  BOOST_CHECK_EQUAL(undistorted_camera.Height(), 1);
60 
61  distorted_camera.InitializeWithName("SIMPLE_RADIAL", 100, 100, 100);
62  distorted_camera.Params(3) = 0.5;
63  undistorted_camera = UndistortCamera(options, distorted_camera);
64  BOOST_CHECK_EQUAL(undistorted_camera.ModelName(), "PINHOLE");
65  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthX(), 100);
66  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthY(), 100);
67  BOOST_CHECK_EQUAL(undistorted_camera.PrincipalPointX(), 84.0 / 2.0);
68  BOOST_CHECK_EQUAL(undistorted_camera.PrincipalPointY(), 84.0 / 2.0);
69  BOOST_CHECK_EQUAL(undistorted_camera.Width(), 84);
70  BOOST_CHECK_EQUAL(undistorted_camera.Height(), 84);
71 
72  options.blank_pixels = 1;
73  undistorted_camera = UndistortCamera(options, distorted_camera);
74  BOOST_CHECK_EQUAL(undistorted_camera.ModelName(), "PINHOLE");
75  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthX(), 100);
76  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthY(), 100);
77  BOOST_CHECK_EQUAL(undistorted_camera.Width(), 90);
78  BOOST_CHECK_EQUAL(undistorted_camera.Height(), 90);
79 
80  options.max_scale = 0.75;
81  undistorted_camera = UndistortCamera(options, distorted_camera);
82  BOOST_CHECK_EQUAL(undistorted_camera.ModelName(), "PINHOLE");
83  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthX(), 100);
84  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthY(), 100);
85  BOOST_CHECK_EQUAL(undistorted_camera.Width(), 75);
86  BOOST_CHECK_EQUAL(undistorted_camera.Height(), 75);
87 
88  options.max_scale = 1.0;
89  options.roi_min_x = 0.1;
90  options.roi_min_y = 0.2;
91  options.roi_max_x = 0.9;
92  options.roi_max_y = 0.8;
93  undistorted_camera = UndistortCamera(options, distorted_camera);
94  BOOST_CHECK_EQUAL(undistorted_camera.ModelName(), "PINHOLE");
95  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthX(), 100);
96  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthY(), 100);
97  BOOST_CHECK_EQUAL(undistorted_camera.Width(), 80);
98  BOOST_CHECK_EQUAL(undistorted_camera.Height(), 60);
99  BOOST_CHECK_EQUAL(undistorted_camera.PrincipalPointX(), 40);
100  BOOST_CHECK_EQUAL(undistorted_camera.PrincipalPointY(), 30);
101 }
102 
103 BOOST_AUTO_TEST_CASE(TestUndistortCameraBlankPixels) {
104  UndistortCameraOptions options;
105  options.blank_pixels = 1;
106 
107  Camera distorted_camera;
108  distorted_camera.InitializeWithName("SIMPLE_RADIAL", 100, 100, 100);
109  distorted_camera.Params(3) = 0.5;
110 
111  Bitmap distorted_image;
112  distorted_image.Allocate(100, 100, false);
113  distorted_image.Fill(BitmapColor<uint8_t>(255));
114 
115  Bitmap undistorted_image;
116  Camera undistorted_camera;
117  UndistortImage(options, distorted_image, distorted_camera, &undistorted_image,
118  &undistorted_camera);
119 
120  BOOST_CHECK_EQUAL(undistorted_camera.ModelName(), "PINHOLE");
121  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthX(), 100);
122  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthY(), 100);
123  BOOST_CHECK_EQUAL(undistorted_camera.PrincipalPointX(), 90.0 / 2.0);
124  BOOST_CHECK_EQUAL(undistorted_camera.PrincipalPointY(), 90.0 / 2.0);
125  BOOST_CHECK_EQUAL(undistorted_camera.Width(), 90);
126  BOOST_CHECK_EQUAL(undistorted_camera.Height(), 90);
127 
128  // Make sure that there is no blank pixel.
129  size_t num_blank_pixels = 0;
130  for (int y = 0; y < undistorted_image.Height(); ++y) {
131  for (int x = 0; x < undistorted_image.Width(); ++x) {
133  BOOST_CHECK(undistorted_image.GetPixel(x, y, &color));
134  if (color == BitmapColor<uint8_t>(0)) {
135  num_blank_pixels += 1;
136  }
137  }
138  }
139 
140  BOOST_CHECK_GT(num_blank_pixels, 0);
141 }
142 
143 BOOST_AUTO_TEST_CASE(TestUndistortCameraNoBlankPixels) {
144  UndistortCameraOptions options;
145  options.blank_pixels = 0;
146 
147  Camera distorted_camera;
148  distorted_camera.InitializeWithName("SIMPLE_RADIAL", 100, 100, 100);
149  distorted_camera.Params(3) = 0.5;
150 
151  Bitmap distorted_image;
152  distorted_image.Allocate(100, 100, false);
153  distorted_image.Fill(BitmapColor<uint8_t>(255));
154 
155  Bitmap undistorted_image;
156  Camera undistorted_camera;
157  UndistortImage(options, distorted_image, distorted_camera, &undistorted_image,
158  &undistorted_camera);
159 
160  BOOST_CHECK_EQUAL(undistorted_camera.ModelName(), "PINHOLE");
161  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthX(), 100);
162  BOOST_CHECK_EQUAL(undistorted_camera.FocalLengthY(), 100);
163  BOOST_CHECK_EQUAL(undistorted_camera.PrincipalPointX(), 84.0 / 2.0);
164  BOOST_CHECK_EQUAL(undistorted_camera.PrincipalPointY(), 84.0 / 2.0);
165  BOOST_CHECK_EQUAL(undistorted_camera.Width(), 84);
166  BOOST_CHECK_EQUAL(undistorted_camera.Height(), 84);
167 
168  // Make sure that there is no blank pixel.
169  for (int y = 0; y < undistorted_image.Height(); ++y) {
170  for (int x = 0; x < undistorted_image.Width(); ++x) {
172  BOOST_CHECK(undistorted_image.GetPixel(x, y, &color));
173  BOOST_CHECK_NE(color.r, 0);
174  BOOST_CHECK_EQUAL(color.g, 0);
175  BOOST_CHECK_EQUAL(color.b, 0);
176  }
177  }
178 }
179 
180 BOOST_AUTO_TEST_CASE(TestUndistortReconstruction) {
181  const size_t kNumImages = 10;
182  const size_t kNumPoints2D = 10;
183 
184  Reconstruction reconstruction;
185 
186  Camera camera;
187  camera.SetCameraId(1);
188  camera.InitializeWithName("OPENCV", 1, 1, 1);
189  camera.Params(4) = 1.0;
190  reconstruction.AddCamera(camera);
191 
192  for (image_t image_id = 1; image_id <= kNumImages; ++image_id) {
193  Image image;
194  image.SetImageId(image_id);
195  image.SetCameraId(1);
196  image.SetName("image" + std::to_string(image_id));
197  image.SetPoints2D(
198  std::vector<Eigen::Vector2d>(kNumPoints2D, Eigen::Vector2d::Ones()));
199  reconstruction.AddImage(image);
200  reconstruction.RegisterImage(image_id);
201  }
202 
203  UndistortCameraOptions options;
204  UndistortReconstruction(options, &reconstruction);
205  for (const auto& camera : reconstruction.Cameras()) {
206  BOOST_CHECK_EQUAL(camera.second.ModelName(), "PINHOLE");
207  }
208 
209  for (const auto& image : reconstruction.Images()) {
210  for (const auto& point2D : image.second.Points2D()) {
211  BOOST_CHECK_NE(point2D.XY(), Eigen::Vector2d::Ones());
212  }
213  }
214 }
215 
216 BOOST_AUTO_TEST_CASE(TestRectifyStereoCameras) {
217  Camera camera1;
218  camera1.SetCameraId(1);
219  camera1.InitializeWithName("PINHOLE", 1, 1, 1);
220 
221  Camera camera2;
222  camera2.SetCameraId(1);
223  camera2.InitializeWithName("PINHOLE", 1, 1, 1);
224 
225  const Eigen::Vector4d qvec =
227  const Eigen::Vector3d tvec(0.1, 0.2, 0.3);
228 
229  Camera rectified_camera1;
230  Camera rectified_camera2;
231  Eigen::Matrix3d H1;
232  Eigen::Matrix3d H2;
233  Eigen::Matrix4d Q;
234  RectifyStereoCameras(camera1, camera2, qvec, tvec, &H1, &H2, &Q);
235 
236  Eigen::Matrix3d H1_ref;
237  H1_ref << -0.202759, -0.815848, -0.897034, 0.416329, 0.733069, -0.199657,
238  0.910839, -0.175408, 0.942638;
239  BOOST_CHECK(H1.isApprox(H1_ref.transpose(), 1e-5));
240 
241  Eigen::Matrix3d H2_ref;
242  H2_ref << -0.082173, -1.01288, -0.698868, 0.301854, 0.472844, -0.465336,
243  0.963533, 0.292411, 1.12528;
244  BOOST_CHECK(H2.isApprox(H2_ref.transpose(), 1e-5));
245 
246  Eigen::Matrix4d Q_ref;
247  Q_ref << 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -2.67261, -0.5, -0.5, 1, 0;
248  BOOST_CHECK(Q.isApprox(Q_ref, 1e-5));
249 }
std::shared_ptr< core::Tensor > image
math::float4 color
bool GetPixel(const int x, const int y, BitmapColor< uint8_t > *color) const
Definition: bitmap.cc:178
void Fill(const BitmapColor< uint8_t > &color)
Definition: bitmap.cc:226
bool Allocate(const int width, const int height, const bool as_rgb)
Definition: bitmap.cc:104
int Width() const
Definition: bitmap.h:249
int Height() const
Definition: bitmap.h:250
void InitializeWithName(const std::string &model_name, const double focal_length, const size_t width, const size_t height)
Definition: camera.cc:212
double FocalLengthY() const
Definition: camera.cc:121
const std::vector< double > & Params() const
Definition: camera.h:176
std::string ModelName() const
Definition: camera.cc:49
void SetCameraId(const camera_t camera_id)
Definition: camera.h:156
double FocalLengthX() const
Definition: camera.cc:115
double PrincipalPointX() const
Definition: camera.cc:146
size_t Width() const
Definition: camera.h:160
double PrincipalPointY() const
Definition: camera.cc:152
size_t Height() const
Definition: camera.h:162
void AddImage(const class Image &image)
const std::unordered_map< image_t, class Image > & Images() const
void AddCamera(const class Camera &camera)
const std::unordered_map< camera_t, class Camera > & Cameras() const
void RegisterImage(const image_t image_id)
const double * e
normal_z y
normal_z x
void RectifyStereoCameras(const Camera &camera1, const Camera &camera2, const Eigen::Vector4d &qvec, const Eigen::Vector3d &tvec, Eigen::Matrix3d *H1, Eigen::Matrix3d *H2, Eigen::Matrix4d *Q)
void UndistortImage(const UndistortCameraOptions &options, const Bitmap &distorted_bitmap, const Camera &distorted_camera, Bitmap *undistorted_bitmap, Camera *undistorted_camera)
Eigen::Matrix3d EulerAnglesToRotationMatrix(const double rx, const double ry, const double rz)
Definition: pose.cc:59
Eigen::Vector4d RotationMatrixToQuaternion(const Eigen::Matrix3d &rot_mat)
Definition: pose.cc:70
void UndistortReconstruction(const UndistortCameraOptions &options, Reconstruction *reconstruction)
Camera UndistortCamera(const UndistortCameraOptions &options, const Camera &camera)
uint32_t image_t
Definition: types.h:61
std::string to_string(const T &n)
Definition: Common.h:20
BOOST_AUTO_TEST_CASE(TestUndistortCamera)