ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
warp_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/warp"
33 #include "util/testing.h"
34 
35 #include "base/warp.h"
36 #include "util/random.h"
37 
38 using namespace colmap;
39 namespace {
40 
41 void GenerateRandomBitmap(const int width, const int height, const bool as_rgb,
42  Bitmap* bitmap) {
43  bitmap->Allocate(width, height, as_rgb);
44  for (int x = 0; x < width; ++x) {
45  for (int y = 0; y < height; ++y) {
47  color.r = RandomInteger<int>(0, 255);
48  color.g = RandomInteger<int>(0, 255);
49  color.b = RandomInteger<int>(0, 255);
50  bitmap->SetPixel(x, y, color);
51  }
52  }
53 }
54 
55 // Check that the two bitmaps are equal, ignoring a 1px boundary.
56 void CheckBitmapsEqual(const Bitmap& bitmap1, const Bitmap& bitmap2) {
57  BOOST_REQUIRE_EQUAL(bitmap1.IsGrey(), bitmap2.IsGrey());
58  BOOST_REQUIRE_EQUAL(bitmap1.IsRGB(), bitmap2.IsRGB());
59  BOOST_REQUIRE_EQUAL(bitmap1.Width(), bitmap2.Width());
60  BOOST_REQUIRE_EQUAL(bitmap1.Height(), bitmap2.Height());
61  for (int x = 1; x < bitmap1.Width() - 1; ++x) {
62  for (int y = 1; y < bitmap1.Height() - 1; ++y) {
63  BitmapColor<uint8_t> color1;
64  BitmapColor<uint8_t> color2;
65  BOOST_CHECK(bitmap1.GetPixel(x, y, &color1));
66  BOOST_CHECK(bitmap2.GetPixel(x, y, &color2));
67  BOOST_CHECK_EQUAL(color1, color2);
68  }
69  }
70 }
71 
72 // Check that the two bitmaps are equal, ignoring a 1px boundary.
73 void CheckBitmapsTransposed(const Bitmap& bitmap1, const Bitmap& bitmap2) {
74  BOOST_REQUIRE_EQUAL(bitmap1.IsGrey(), bitmap2.IsGrey());
75  BOOST_REQUIRE_EQUAL(bitmap1.IsRGB(), bitmap2.IsRGB());
76  BOOST_REQUIRE_EQUAL(bitmap1.Width(), bitmap2.Width());
77  BOOST_REQUIRE_EQUAL(bitmap1.Height(), bitmap2.Height());
78  for (int x = 1; x < bitmap1.Width() - 1; ++x) {
79  for (int y = 1; y < bitmap1.Height() - 1; ++y) {
80  BitmapColor<uint8_t> color1;
81  BitmapColor<uint8_t> color2;
82  BOOST_CHECK(bitmap1.GetPixel(x, y, &color1));
83  BOOST_CHECK(bitmap2.GetPixel(y, x, &color2));
84  BOOST_CHECK_EQUAL(color1, color2);
85  }
86  }
87 }
88 
89 } // namespace
90 
91 BOOST_AUTO_TEST_CASE(TestIdenticalCameras) {
92  Camera source_camera;
93  source_camera.InitializeWithName("PINHOLE", 1, 100, 100);
94  Camera target_camera = source_camera;
95  Bitmap source_image_gray;
96  GenerateRandomBitmap(100, 100, false, &source_image_gray);
97  Bitmap target_image_gray;
98  WarpImageBetweenCameras(source_camera, target_camera, source_image_gray,
99  &target_image_gray);
100  CheckBitmapsEqual(source_image_gray, target_image_gray);
101  Bitmap source_image_rgb;
102  GenerateRandomBitmap(100, 100, true, &source_image_rgb);
103  Bitmap target_image_rgb;
104  WarpImageBetweenCameras(source_camera, target_camera, source_image_rgb,
105  &target_image_rgb);
106  CheckBitmapsEqual(source_image_rgb, target_image_rgb);
107 }
108 
109 BOOST_AUTO_TEST_CASE(TestShiftedCameras) {
110  Camera source_camera;
111  source_camera.InitializeWithName("PINHOLE", 1, 100, 100);
112  Camera target_camera = source_camera;
113  target_camera.SetPrincipalPointX(0.0);
114  Bitmap source_image_gray;
115  GenerateRandomBitmap(100, 100, true, &source_image_gray);
116  Bitmap target_image_gray;
117  WarpImageBetweenCameras(source_camera, target_camera, source_image_gray,
118  &target_image_gray);
119  for (int x = 0; x < target_image_gray.Width(); ++x) {
120  for (int y = 0; y < target_image_gray.Height(); ++y) {
122  BOOST_CHECK(target_image_gray.GetPixel(x, y, &color));
123  if (x >= 50) {
124  BOOST_CHECK_EQUAL(color, BitmapColor<uint8_t>(0));
125  } else {
126  BitmapColor<uint8_t> source_color;
127  if (source_image_gray.GetPixel(x + 50, y, &source_color) &&
128  color != BitmapColor<uint8_t>(0)) {
129  BOOST_CHECK_EQUAL(color, source_color);
130  }
131  }
132  }
133  }
134 }
135 
136 BOOST_AUTO_TEST_CASE(TestWarpImageWithHomographyIdentity) {
137  Bitmap source_image_gray;
138  GenerateRandomBitmap(100, 100, false, &source_image_gray);
139  Bitmap target_image_gray;
140  target_image_gray.Allocate(100, 100, false);
141  WarpImageWithHomography(Eigen::Matrix3d::Identity(), source_image_gray,
142  &target_image_gray);
143  CheckBitmapsEqual(source_image_gray, target_image_gray);
144 
145  Bitmap source_image_rgb;
146  GenerateRandomBitmap(100, 100, true, &source_image_rgb);
147  Bitmap target_image_rgb;
148  target_image_rgb.Allocate(100, 100, true);
149  WarpImageWithHomography(Eigen::Matrix3d::Identity(), source_image_rgb,
150  &target_image_rgb);
151  CheckBitmapsEqual(source_image_rgb, target_image_rgb);
152 }
153 
154 BOOST_AUTO_TEST_CASE(TestWarpImageWithHomographyTransposed) {
155  Eigen::Matrix3d H;
156  H << 0, 1, 0, 1, 0, 0, 0, 0, 1;
157 
158  Bitmap source_image_gray;
159  GenerateRandomBitmap(100, 100, false, &source_image_gray);
160  Bitmap target_image_gray;
161  target_image_gray.Allocate(100, 100, false);
162  WarpImageWithHomography(H, source_image_gray, &target_image_gray);
163  CheckBitmapsTransposed(source_image_gray, target_image_gray);
164 
165  Bitmap source_image_rgb;
166  GenerateRandomBitmap(100, 100, true, &source_image_rgb);
167  Bitmap target_image_rgb;
168  target_image_rgb.Allocate(100, 100, true);
169  WarpImageWithHomography(H, source_image_rgb, &target_image_rgb);
170  CheckBitmapsTransposed(source_image_rgb, target_image_rgb);
171 }
172 
173 BOOST_AUTO_TEST_CASE(TestWarpImageWithHomographyBetweenCamerasIdentity) {
174  Camera source_camera;
175  source_camera.InitializeWithName("PINHOLE", 1, 100, 100);
176  Camera target_camera = source_camera;
177 
178  Bitmap source_image_gray;
179  GenerateRandomBitmap(100, 100, false, &source_image_gray);
180  Bitmap target_image_gray;
181  target_image_gray.Allocate(100, 100, false);
182  WarpImageWithHomographyBetweenCameras(Eigen::Matrix3d::Identity(),
183  source_camera, target_camera,
184  source_image_gray, &target_image_gray);
185  CheckBitmapsEqual(source_image_gray, target_image_gray);
186 
187  Bitmap source_image_rgb;
188  GenerateRandomBitmap(100, 100, true, &source_image_rgb);
189  Bitmap target_image_rgb;
190  target_image_rgb.Allocate(100, 100, true);
191  WarpImageWithHomographyBetweenCameras(Eigen::Matrix3d::Identity(),
192  source_camera, target_camera,
193  source_image_rgb, &target_image_rgb);
194  CheckBitmapsEqual(source_image_rgb, target_image_rgb);
195 }
196 
197 BOOST_AUTO_TEST_CASE(TestWarpImageWithHomographyBetweenCamerasTransposed) {
198  Camera source_camera;
199  source_camera.InitializeWithName("PINHOLE", 1, 100, 100);
200  Camera target_camera = source_camera;
201 
202  Eigen::Matrix3d H;
203  H << 0, 1, 0, 1, 0, 0, 0, 0, 1;
204 
205  Bitmap source_image_gray;
206  GenerateRandomBitmap(100, 100, false, &source_image_gray);
207  Bitmap target_image_gray;
208  target_image_gray.Allocate(100, 100, false);
209  WarpImageWithHomographyBetweenCameras(H, source_camera, target_camera,
210  source_image_gray, &target_image_gray);
211  CheckBitmapsTransposed(source_image_gray, target_image_gray);
212 
213  Bitmap source_image_rgb;
214  GenerateRandomBitmap(100, 100, true, &source_image_rgb);
215  Bitmap target_image_rgb;
216  target_image_rgb.Allocate(100, 100, true);
217  WarpImageWithHomographyBetweenCameras(H, source_camera, target_camera,
218  source_image_rgb, &target_image_rgb);
219  CheckBitmapsTransposed(source_image_rgb, target_image_rgb);
220 }
221 
222 BOOST_AUTO_TEST_CASE(TestResampleImageBilinear) {
223  std::vector<float> image(16);
224  for (size_t i = 0; i < image.size(); ++i) {
225  image[i] = i;
226  }
227 
228  std::vector<float> resampled(4);
229  ResampleImageBilinear(image.data(), 4, 4, 2, 2, resampled.data());
230 
231  BOOST_CHECK_EQUAL(resampled[0], 2.5);
232  BOOST_CHECK_EQUAL(resampled[1], 4.5);
233  BOOST_CHECK_EQUAL(resampled[2], 10.5);
234  BOOST_CHECK_EQUAL(resampled[3], 12.5);
235 }
236 
237 BOOST_AUTO_TEST_CASE(TestSmoothImage) {
238  std::vector<float> image(16);
239  for (size_t i = 0; i < image.size(); ++i) {
240  image[i] = i;
241  }
242 
243  std::vector<float> smoothed(16);
244  SmoothImage(image.data(), 4, 4, 1, 1, smoothed.data());
245 
246  BOOST_CHECK_CLOSE(smoothed[0], 1.81673253, 1e-3);
247  BOOST_CHECK_CLOSE(smoothed[1], 2.51182437, 1e-3);
248  BOOST_CHECK_CLOSE(smoothed[2], 3.39494729, 1e-3);
249  BOOST_CHECK_CLOSE(smoothed[3], 4.09003973, 1e-3);
250  BOOST_CHECK_CLOSE(smoothed[4], 4.59710073, 1e-3);
251  BOOST_CHECK_CLOSE(smoothed[5], 5.29219341, 1e-3);
252  BOOST_CHECK_CLOSE(smoothed[6], 6.17531633, 1e-3);
253  BOOST_CHECK_CLOSE(smoothed[7], 6.87040806, 1e-3);
254 }
255 
256 BOOST_AUTO_TEST_CASE(TestDownsampleImage) {
257  std::vector<float> image(16);
258  for (size_t i = 0; i < image.size(); ++i) {
259  image[i] = i;
260  }
261 
262  std::vector<float> downsampled(4);
263  DownsampleImage(image.data(), 4, 4, 2, 2, downsampled.data());
264 
265  BOOST_CHECK_CLOSE(downsampled[0], 2.76810598, 1e-3);
266  BOOST_CHECK_CLOSE(downsampled[1], 4.66086388, 1e-3);
267  BOOST_CHECK_CLOSE(downsampled[2], 10.3391361, 1e-3);
268  BOOST_CHECK_CLOSE(downsampled[3], 12.2318935, 1e-3);
269 }
std::shared_ptr< core::Tensor > image
int width
int height
math::float4 color
bool SetPixel(const int x, const int y, const BitmapColor< uint8_t > &color)
Definition: bitmap.cc:199
bool GetPixel(const int x, const int y, BitmapColor< uint8_t > *color) const
Definition: bitmap.cc:178
bool IsRGB() const
Definition: bitmap.h:261
bool Allocate(const int width, const int height, const bool as_rgb)
Definition: bitmap.cc:104
int Width() const
Definition: bitmap.h:249
bool IsGrey() const
Definition: bitmap.h:263
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
void SetPrincipalPointX(const double ppx)
Definition: camera.cc:158
const double * e
normal_z y
normal_z x
void WarpImageBetweenCameras(const Camera &source_camera, const Camera &target_camera, const Bitmap &source_image, Bitmap *target_image)
Definition: warp.cc:51
void ResampleImageBilinear(const float *data, const int rows, const int cols, const int new_rows, const int new_cols, float *resampled)
Definition: warp.cc:174
void SmoothImage(const float *data, const int rows, const int cols, const float sigma_r, const float sigma_c, float *smoothed)
Definition: warp.cc:215
void WarpImageWithHomography(const Eigen::Matrix3d &H, const Bitmap &source_image, Bitmap *target_image)
Definition: warp.cc:98
void WarpImageWithHomographyBetweenCameras(const Eigen::Matrix3d &H, const Camera &source_camera, const Camera &target_camera, const Bitmap &source_image, Bitmap *target_image)
Definition: warp.cc:124
void DownsampleImage(const float *data, const int rows, const int cols, const int new_rows, const int new_cols, float *downsampled)
Definition: warp.cc:226
BOOST_AUTO_TEST_CASE(TestIdenticalCameras)
Definition: warp_test.cc:91