Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
testImageWarp.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Test image warping.
32  */
33 
40 #include <visp3/core/vpConfig.h>
41 
42 #if defined(VISP_HAVE_CATCH2) && (VISP_HAVE_DATASET_VERSION >= 0x030300)
43 #define CATCH_CONFIG_RUNNER
44 #include <catch.hpp>
45 
46 #include <iostream>
47 #include <visp3/core/vpImageTools.h>
48 #include <visp3/core/vpIoTools.h>
49 #include <visp3/io/vpImageIo.h>
50 
51 #ifdef ENABLE_VISP_NAMESPACE
52 using namespace VISP_NAMESPACE_NAME;
53 #endif
54 
55 namespace
56 {
57 static const double g_threshold_value = 0.5;
58 static const double g_threshold_percentage = 0.9;
59 static const double g_threshold_percentage_bilinear = 0.75;
60 static const double g_threshold_percentage_pers = 0.75;
61 static const double g_threshold_percentage_pers_bilinear = 0.65;
62 
63 static const std::vector<vpImageTools::vpImageInterpolationType> interp_methods = { vpImageTools::INTERPOLATION_NEAREST,
65 static const std::vector<std::string> interp_names = { "Nearest Neighbor", "Bilinear" };
66 static const std::vector<std::string> suffixes = { "_NN.png", "_bilinear.png" };
67 
68 bool almostEqual(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2, double threshold_val,
69  double threshold_percentage, double &percentage)
70 {
71  double nb_valid = 0;
72 
73  if (I1.getHeight() != I2.getHeight() || I1.getWidth() != I2.getWidth()) {
74  return false;
75  }
76 
77  for (unsigned int i = 0; i < I1.getHeight(); i++) {
78  for (unsigned int j = 0; j < I1.getWidth(); j++) {
79  nb_valid += vpMath::abs(I1[i][j] - I2[i][j]) < threshold_val ? 1 : 0;
80  }
81  }
82 
83  percentage = nb_valid / I1.getSize();
84  return percentage >= threshold_percentage;
85 }
86 
87 bool almostEqual(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2, double threshold_val,
88  double threshold_percentage, double &percentage)
89 {
90  double nb_valid = 0;
91 
92  if (I1.getHeight() != I2.getHeight() || I1.getWidth() != I2.getWidth()) {
93  return false;
94  }
95 
96  for (unsigned int i = 0; i < I1.getHeight(); i++) {
97  for (unsigned int j = 0; j < I1.getWidth(); j++) {
98  if (vpMath::abs(I1[i][j].R - I2[i][j].R) < threshold_val) {
99  nb_valid++;
100  }
101  if (vpMath::abs(I1[i][j].G - I2[i][j].G) < threshold_val) {
102  nb_valid++;
103  }
104  if (vpMath::abs(I1[i][j].B - I2[i][j].B) < threshold_val) {
105  nb_valid++;
106  }
107  }
108  }
109 
110  percentage = nb_valid / (3 * I1.getSize());
111  return percentage >= threshold_percentage;
112 }
113 } // namespace
114 
115 TEST_CASE("Affine warp on grayscale", "[warp_image]")
116 {
117  const std::string imgPath = vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Klimt/Klimt.pgm");
118  REQUIRE(vpIoTools::checkFilename(imgPath));
119 
121  vpImageIo::read(I, imgPath);
122  REQUIRE(I.getSize() > 0);
123 
124  SECTION("Identity")
125  {
126  vpMatrix M(2, 3);
127  M.eye();
128 
129  for (size_t i = 0; i < interp_methods.size(); i++) {
130  SECTION(interp_names[i])
131  {
132  SECTION("Empty destination")
133  {
134  vpImage<unsigned char> I_affine;
135  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
136  CHECK((I == I_affine));
137  }
138 
139  SECTION("Initialized destination")
140  {
141  vpImage<unsigned char> I_affine(I.getHeight(), I.getWidth(), 0);
142  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
143  CHECK((I == I_affine));
144  }
145  }
146  }
147  }
148 
149  SECTION("Rotation 45 deg")
150  {
151  vpMatrix M(2, 3);
152  M.eye();
153 
154  const double theta = vpMath::rad(45);
155  M[0][0] = cos(theta);
156  M[0][1] = -sin(theta);
157  M[0][2] = I.getWidth() / 2.0;
158  M[1][0] = sin(theta);
159  M[1][1] = cos(theta);
160  M[1][2] = I.getHeight() / 2.0;
161 
162  for (size_t i = 0; i < interp_methods.size(); i++) {
163  SECTION(interp_names[i])
164  {
165  SECTION("Against reference implementation")
166  {
168  vpImageTools::warpImage(I, M, I_ref, interp_methods[i], false);
169 
170  vpImage<unsigned char> I_affine;
171  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
172 
173  double percentage = 0.0;
174  bool equal = almostEqual(I_ref, I_affine, g_threshold_value, g_threshold_percentage, percentage);
175  std::cout << "Percentage valid pixels (45 deg " << interp_names[i] << " Ref): " << percentage << std::endl;
176  CHECK(equal);
177  }
178 
179  SECTION("Against OpenCV")
180  {
181  const std::string refImgPath = vpIoTools::createFilePath(
182  vpIoTools::getViSPImagesDataPath(), std::string("warp/cv_warp_affine_rot_45_gray" + suffixes[i]));
183  REQUIRE(vpIoTools::checkFilename(refImgPath));
184  vpImage<unsigned char> I_ref_opencv;
185 
186  vpImageIo::read(I_ref_opencv, refImgPath);
187 
188  vpImage<unsigned char> I_affine;
189  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
190 
191  double percentage = 0.0;
192  bool equal = almostEqual(I_ref_opencv, I_affine, g_threshold_value,
193  (i == 0) ? g_threshold_percentage : g_threshold_percentage_bilinear, percentage);
194  std::cout << "Percentage valid pixels (45 deg " << interp_names[i] << " OpenCV): " << percentage << std::endl;
195  CHECK(equal);
196  }
197 
198  SECTION("Against PIL")
199  {
200  const std::string refImgPath = vpIoTools::createFilePath(
201  vpIoTools::getViSPImagesDataPath(), std::string("warp/pil_warp_affine_rot_45_gray" + suffixes[i]));
202  REQUIRE(vpIoTools::checkFilename(refImgPath));
203  vpImage<unsigned char> I_ref_pil;
204  vpImageIo::read(I_ref_pil, refImgPath);
205 
206  vpImage<unsigned char> I_affine;
207  vpImageTools::warpImage(I, M, I_affine, interp_methods[i], false, true);
208 
209  double percentage = 0.0;
210  bool equal = almostEqual(I_ref_pil, I_affine, g_threshold_value,
211  (i == 0) ? g_threshold_percentage : g_threshold_percentage_bilinear, percentage);
212  std::cout << "Percentage valid pixels (45 deg " << interp_names[i] << " PIL): " << percentage << std::endl;
213  CHECK(equal);
214  }
215  }
216  }
217  }
218 
219  SECTION("SRT")
220  {
221  vpMatrix M(2, 3);
222  M.eye();
223 
224  const double theta = vpMath::rad(-67);
225  const double scale = 0.83;
226  M[0][0] = scale * cos(theta);
227  M[0][1] = -scale * sin(theta);
228  M[0][2] = I.getWidth() / 2.0 + 17;
229  M[1][0] = scale * sin(theta);
230  M[1][1] = scale * cos(theta);
231  M[1][2] = I.getHeight() / 2.0 - 23;
232 
233  for (size_t i = 0; i < interp_methods.size(); i++) {
234  SECTION(interp_names[i])
235  {
236  SECTION("Against reference implementation")
237  {
239  vpImageTools::warpImage(I, M, I_ref, interp_methods[i], false);
240 
241  vpImage<unsigned char> I_affine;
242  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
243 
244  double percentage = 0.0;
245  bool equal = almostEqual(I_ref, I_affine, g_threshold_value, g_threshold_percentage, percentage);
246  std::cout << "Percentage valid pixels (SRT " << interp_names[i] << " Ref): " << percentage << std::endl;
247  CHECK(equal);
248  }
249 
250  SECTION("Against OpenCV")
251  {
252  const std::string refImgPath = vpIoTools::createFilePath(
253  vpIoTools::getViSPImagesDataPath(), std::string("warp/cv_warp_affine_SRT_gray" + suffixes[i]));
254  REQUIRE(vpIoTools::checkFilename(refImgPath));
255  vpImage<unsigned char> I_ref_opencv;
256  vpImageIo::read(I_ref_opencv, refImgPath);
257 
258  vpImage<unsigned char> I_affine;
259  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
260 
261  double percentage = 0.0;
262  bool equal = almostEqual(I_ref_opencv, I_affine, g_threshold_value,
263  (i == 0) ? g_threshold_percentage : g_threshold_percentage_bilinear, percentage);
264  std::cout << "Percentage valid pixels (SRT " << interp_names[i] << " OpenCV): " << percentage << std::endl;
265  CHECK(equal);
266  }
267 
268  SECTION("Against PIL")
269  {
270  const std::string refImgPath = vpIoTools::createFilePath(
271  vpIoTools::getViSPImagesDataPath(), std::string("warp/pil_warp_affine_SRT_gray" + suffixes[i]));
272  REQUIRE(vpIoTools::checkFilename(refImgPath));
273  vpImage<unsigned char> I_ref_pil;
274  vpImageIo::read(I_ref_pil, refImgPath);
275 
276  vpImage<unsigned char> I_affine;
277  vpImageTools::warpImage(I, M, I_affine, interp_methods[i], false, true);
278 
279  double percentage = 0.0;
280  bool equal = almostEqual(I_ref_pil, I_affine, g_threshold_value,
281  (i == 0) ? g_threshold_percentage : g_threshold_percentage_bilinear, percentage);
282  std::cout << "Percentage valid pixels (SRT " << interp_names[i] << " PIL): " << percentage << std::endl;
283  CHECK(equal);
284  }
285  }
286  }
287  }
288 }
289 
290 TEST_CASE("Affine warp on color", "[warp_image]")
291 {
292  const std::string imgPath = vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Klimt/Klimt.ppm");
293  REQUIRE(vpIoTools::checkFilename(imgPath));
294 
295  vpImage<vpRGBa> I;
296  vpImageIo::read(I, imgPath);
297  REQUIRE(I.getSize() > 0);
298 
299  SECTION("Identity")
300  {
301  vpMatrix M(2, 3);
302  M.eye();
303 
304  for (size_t i = 0; i < interp_methods.size(); i++) {
305  SECTION(interp_names[i])
306  {
307  SECTION("Empty destination")
308  {
309  vpImage<vpRGBa> I_affine;
310  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
311  CHECK((I == I_affine));
312  }
313 
314  SECTION("Initialized destination")
315  {
316  vpImage<vpRGBa> I_affine(I.getHeight(), I.getWidth(), vpRGBa(0));
317  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
318  CHECK((I == I_affine));
319  }
320  }
321  }
322  }
323 
324  SECTION("Rotation 45 deg")
325  {
326  vpMatrix M(2, 3);
327  M.eye();
328 
329  const double theta = vpMath::rad(45);
330  M[0][0] = cos(theta);
331  M[0][1] = -sin(theta);
332  M[0][2] = I.getWidth() / 2.0;
333  M[1][0] = sin(theta);
334  M[1][1] = cos(theta);
335  M[1][2] = I.getHeight() / 2.0;
336 
337  for (size_t i = 0; i < interp_methods.size(); i++) {
338  SECTION(interp_names[i])
339  {
340  SECTION("Against reference implementation")
341  {
342  vpImage<vpRGBa> I_ref;
343  vpImageTools::warpImage(I, M, I_ref, interp_methods[i], false);
344 
345  vpImage<vpRGBa> I_affine;
346  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
347 
348  double percentage = 0.0;
349  bool equal = almostEqual(I_ref, I_affine, g_threshold_value, g_threshold_percentage, percentage);
350  std::cout << "Percentage valid pixels (45 deg " << interp_names[i] << " Ref): " << percentage << std::endl;
351  CHECK(equal);
352  }
353 
354  SECTION("Against OpenCV")
355  {
356  const std::string refImgPath = vpIoTools::createFilePath(
357  vpIoTools::getViSPImagesDataPath(), std::string("warp/cv_warp_affine_rot_45_color" + suffixes[i]));
358  REQUIRE(vpIoTools::checkFilename(refImgPath));
359  vpImage<vpRGBa> I_ref_opencv;
360  vpImageIo::read(I_ref_opencv, refImgPath);
361 
362  vpImage<vpRGBa> I_affine;
363  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
364 
365  double percentage = 0.0;
366  bool equal = almostEqual(I_ref_opencv, I_affine, g_threshold_value,
367  (i == 0) ? g_threshold_percentage : g_threshold_percentage_bilinear, percentage);
368  std::cout << "Percentage valid pixels (45 deg " << interp_names[i] << " OpenCV): " << percentage << std::endl;
369  CHECK(equal);
370  }
371 
372  SECTION("Against PIL")
373  {
374  const std::string refImgPath = vpIoTools::createFilePath(
375  vpIoTools::getViSPImagesDataPath(), std::string("warp/pil_warp_affine_rot_45_color" + suffixes[i]));
376  REQUIRE(vpIoTools::checkFilename(refImgPath));
377  vpImage<vpRGBa> I_ref_pil;
378  vpImageIo::read(I_ref_pil, refImgPath);
379 
380  vpImage<vpRGBa> I_affine;
381  vpImageTools::warpImage(I, M, I_affine, interp_methods[i], false, true);
382 
383  double percentage = 0.0;
384  bool equal = almostEqual(I_ref_pil, I_affine, g_threshold_value,
385  (i == 0) ? g_threshold_percentage : g_threshold_percentage_bilinear, percentage);
386  std::cout << "Percentage valid pixels (45 deg " << interp_names[i] << " PIL): " << percentage << std::endl;
387  CHECK(equal);
388  }
389  }
390  }
391  }
392 
393  SECTION("SRT")
394  {
395  vpMatrix M(2, 3);
396  M.eye();
397 
398  const double theta = vpMath::rad(-67);
399  const double scale = 0.83;
400  M[0][0] = scale * cos(theta);
401  M[0][1] = -scale * sin(theta);
402  M[0][2] = I.getWidth() / 2.0 + 17;
403  M[1][0] = scale * sin(theta);
404  M[1][1] = scale * cos(theta);
405  M[1][2] = I.getHeight() / 2.0 - 23;
406 
407  for (size_t i = 0; i < interp_methods.size(); i++) {
408  SECTION(interp_names[i])
409  {
410  SECTION("Against reference implementation")
411  {
412  vpImage<vpRGBa> I_ref;
413  vpImageTools::warpImage(I, M, I_ref, interp_methods[i], false);
414 
415  vpImage<vpRGBa> I_affine;
416  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
417 
418  double percentage = 0.0;
419  bool equal = almostEqual(I_ref, I_affine, g_threshold_value,
420  (i == 0) ? g_threshold_percentage : g_threshold_percentage_bilinear, percentage);
421  std::cout << "Percentage valid pixels (SRT " << interp_names[i] << " Ref): " << percentage << std::endl;
422  CHECK(equal);
423  }
424 
425  SECTION("Against OpenCV")
426  {
427  const std::string refImgPath = vpIoTools::createFilePath(
428  vpIoTools::getViSPImagesDataPath(), std::string("warp/cv_warp_affine_SRT_color" + suffixes[i]));
429  REQUIRE(vpIoTools::checkFilename(refImgPath));
430  vpImage<vpRGBa> I_ref_opencv;
431  vpImageIo::read(I_ref_opencv, refImgPath);
432 
433  vpImage<vpRGBa> I_affine;
434  vpImageTools::warpImage(I, M, I_affine, interp_methods[i]);
435 
436  double percentage = 0.0;
437  bool equal = almostEqual(I_ref_opencv, I_affine, g_threshold_value,
438  (i == 0) ? g_threshold_percentage : g_threshold_percentage_bilinear, percentage);
439  std::cout << "Percentage valid pixels (SRT " << interp_names[i] << " OpenCV): " << percentage << std::endl;
440  CHECK(equal);
441  }
442 
443  SECTION("Against PIL")
444  {
445  const std::string refImgPath = vpIoTools::createFilePath(
446  vpIoTools::getViSPImagesDataPath(), std::string("warp/pil_warp_affine_SRT_color" + suffixes[i]));
447  REQUIRE(vpIoTools::checkFilename(refImgPath));
448  vpImage<vpRGBa> I_ref_pil;
449  vpImageIo::read(I_ref_pil, refImgPath);
450 
451  vpImage<vpRGBa> I_affine;
452  vpImageTools::warpImage(I, M, I_affine, interp_methods[i], false, true);
453 
454  double percentage = 0.0;
455  bool equal = almostEqual(I_ref_pil, I_affine, g_threshold_value,
456  (i == 0) ? g_threshold_percentage : g_threshold_percentage_bilinear, percentage);
457  std::cout << "Percentage valid pixels (SRT " << interp_names[i] << " PIL): " << percentage << std::endl;
458  CHECK(equal);
459  }
460  }
461  }
462  }
463 }
464 
465 TEST_CASE("Perspective warp on grayscale", "[warp_image]")
466 {
467  const std::string imgPath = vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Klimt/Klimt.pgm");
468  REQUIRE(vpIoTools::checkFilename(imgPath));
469 
471  vpImageIo::read(I, imgPath);
472  REQUIRE(I.getSize() > 0);
473 
474  SECTION("Identity")
475  {
476  vpMatrix M(3, 3);
477  M.eye();
478 
479  for (size_t i = 0; i < interp_methods.size(); i++) {
480  SECTION(interp_names[i])
481  {
482  SECTION("Empty destination")
483  {
484  vpImage<unsigned char> I_perspective;
485  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i]);
486  CHECK((I == I_perspective));
487  }
488 
489  SECTION("Initialized destination")
490  {
491  vpImage<unsigned char> I_perspective(I.getHeight(), I.getWidth(), 0);
492  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i]);
493  CHECK((I == I_perspective));
494  }
495  }
496  }
497  }
498 
499  SECTION("Rotation 45 deg")
500  {
501  vpMatrix M(3, 3);
502  M.eye();
503 
504  const double theta = vpMath::rad(45);
505  M[0][0] = cos(theta);
506  M[0][1] = -sin(theta);
507  M[0][2] = I.getWidth() / 2.0;
508  M[1][0] = sin(theta);
509  M[1][1] = cos(theta);
510  M[1][2] = I.getHeight() / 2.0;
511 
512  SECTION("Nearest Neighbor")
513  {
516 
517  vpImage<unsigned char> I_perspective;
519 
520  double percentage = 0.0;
521  bool equal = almostEqual(I_ref, I_perspective, g_threshold_value, g_threshold_percentage, percentage);
522  std::cout << "Percentage valid pixels (persp 45 deg): " << percentage << std::endl;
523  CHECK(equal);
524  }
525  }
526 
527  SECTION("Homography")
528  {
529  vpMatrix M(3, 3);
530  M.eye();
531 
532  M[0][0] = 1.8548;
533  M[0][1] = -0.0402;
534  M[0][2] = 114.9;
535  M[1][0] = 1.1209;
536  M[1][1] = 4.0106;
537  M[1][2] = 111;
538  M[2][0] = 0.0022;
539  M[2][1] = 0.0064;
540 
541  for (size_t i = 0; i < interp_methods.size(); i++) {
542  SECTION(interp_names[i])
543  {
544  SECTION("Against reference implementation")
545  {
547  vpImageTools::warpImage(I, M, I_ref, interp_methods[i], false);
548 
549  vpImage<unsigned char> I_perspective;
550  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i]);
551 
552  double percentage = 0.0;
553  bool equal =
554  almostEqual(I_ref, I_perspective, g_threshold_value,
555  (i == 0) ? g_threshold_percentage_pers : g_threshold_percentage_pers_bilinear, percentage);
556  std::cout << "Percentage valid pixels (Homography " << interp_names[i] << " Ref): " << percentage
557  << std::endl;
558  CHECK(equal);
559  }
560 
561  SECTION("Against OpenCV")
562  {
563  const std::string refImgPath = vpIoTools::createFilePath(
564  vpIoTools::getViSPImagesDataPath(), std::string("warp/cv_warp_perspective_gray" + suffixes[i]));
565  REQUIRE(vpIoTools::checkFilename(refImgPath));
566  vpImage<unsigned char> I_ref_opencv;
567  vpImageIo::read(I_ref_opencv, refImgPath);
568 
569  vpImage<unsigned char> I_perspective;
570  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i]);
571 
572  double percentage = 0.0;
573  bool equal =
574  almostEqual(I_ref_opencv, I_perspective, g_threshold_value,
575  (i == 0) ? g_threshold_percentage_pers : g_threshold_percentage_pers_bilinear, percentage);
576  std::cout << "Percentage valid pixels (Homography " << interp_names[i] << " OpenCV): " << percentage
577  << std::endl;
578  CHECK(equal);
579  }
580 
581  SECTION("Against PIL")
582  {
583  const std::string refImgPath = vpIoTools::createFilePath(
584  vpIoTools::getViSPImagesDataPath(), std::string("warp/pil_warp_perspective_gray" + suffixes[i]));
585  REQUIRE(vpIoTools::checkFilename(refImgPath));
586  vpImage<unsigned char> I_ref_pil;
587  vpImageIo::read(I_ref_pil, refImgPath);
588 
589  vpImage<unsigned char> I_perspective;
590  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i], false, true);
591 
592  double percentage = 0.0;
593  bool equal =
594  almostEqual(I_ref_pil, I_perspective, g_threshold_value,
595  (i == 0) ? g_threshold_percentage_pers : g_threshold_percentage_pers_bilinear, percentage);
596  std::cout << "Percentage valid pixels (Homography " << interp_names[i] << " PIL): " << percentage
597  << std::endl;
598  CHECK(equal);
599  }
600  }
601  }
602  }
603 }
604 
605 TEST_CASE("Perspective warp on color", "[warp_image]")
606 {
607  const std::string imgPath = vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "Klimt/Klimt.ppm");
608  REQUIRE(vpIoTools::checkFilename(imgPath));
609 
610  vpImage<vpRGBa> I;
611  vpImageIo::read(I, imgPath);
612  REQUIRE(I.getSize() > 0);
613 
614  SECTION("Identity")
615  {
616  vpMatrix M(3, 3);
617  M.eye();
618 
619  for (size_t i = 0; i < interp_methods.size(); i++) {
620  SECTION(interp_names[i])
621  {
622  SECTION("Empty destination")
623  {
624  vpImage<vpRGBa> I_perspective;
625  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i]);
626  CHECK((I == I_perspective));
627  }
628 
629  SECTION("Initialized destination")
630  {
631  vpImage<vpRGBa> I_perspective(I.getHeight(), I.getWidth(), vpRGBa(0));
632  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i]);
633  CHECK((I == I_perspective));
634  }
635  }
636  }
637  }
638 
639  SECTION("Homography")
640  {
641  vpMatrix M(3, 3);
642  M.eye();
643 
644  M[0][0] = 1.8548;
645  M[0][1] = -0.0402;
646  M[0][2] = 114.9;
647  M[1][0] = 1.1209;
648  M[1][1] = 4.0106;
649  M[1][2] = 111;
650  M[2][0] = 0.0022;
651  M[2][1] = 0.0064;
652 
653  for (size_t i = 0; i < interp_methods.size(); i++) {
654  SECTION(interp_names[i])
655  {
656  SECTION("Against reference implementation")
657  {
658  vpImage<vpRGBa> I_ref;
659  vpImageTools::warpImage(I, M, I_ref, interp_methods[i], false);
660 
661  vpImage<vpRGBa> I_perspective;
662  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i]);
663 
664  double percentage = 0.0;
665  bool equal =
666  almostEqual(I_ref, I_perspective, g_threshold_value,
667  (i == 0) ? g_threshold_percentage_pers : g_threshold_percentage_pers_bilinear, percentage);
668  std::cout << "Percentage valid pixels (Homography " << interp_names[i] << " Ref): " << percentage
669  << std::endl;
670  CHECK(equal);
671  }
672 
673  SECTION("Against OpenCV")
674  {
675  const std::string refImgPath = vpIoTools::createFilePath(
676  vpIoTools::getViSPImagesDataPath(), std::string("warp/cv_warp_perspective_color" + suffixes[i]));
677  REQUIRE(vpIoTools::checkFilename(refImgPath));
678  vpImage<vpRGBa> I_ref_opencv;
679  vpImageIo::read(I_ref_opencv, refImgPath);
680 
681  vpImage<vpRGBa> I_perspective;
682  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i]);
683 
684  double percentage = 0.0;
685  bool equal =
686  almostEqual(I_ref_opencv, I_perspective, g_threshold_value,
687  (i == 0) ? g_threshold_percentage_pers : g_threshold_percentage_pers_bilinear, percentage);
688  std::cout << "Percentage valid pixels (Homography " << interp_names[i] << " OpenCV): " << percentage
689  << std::endl;
690  CHECK(equal);
691  }
692 
693  SECTION("Against PIL")
694  {
695  const std::string refImgPath = vpIoTools::createFilePath(
696  vpIoTools::getViSPImagesDataPath(), std::string("warp/pil_warp_perspective_color" + suffixes[i]));
697  REQUIRE(vpIoTools::checkFilename(refImgPath));
698  vpImage<vpRGBa> I_ref_pil;
699  vpImageIo::read(I_ref_pil, refImgPath);
700 
701  vpImage<vpRGBa> I_perspective;
702  vpImageTools::warpImage(I, M, I_perspective, interp_methods[i], false, true);
703 
704  double percentage = 0.0;
705  bool equal =
706  almostEqual(I_ref_pil, I_perspective, g_threshold_value,
707  (i == 0) ? g_threshold_percentage_pers : g_threshold_percentage_pers_bilinear, percentage);
708  std::cout << "Percentage valid pixels (Homography " << interp_names[i] << " PIL): " << percentage
709  << std::endl;
710  CHECK(equal);
711  }
712  }
713  }
714  }
715 }
716 
717 int main(int argc, char *argv[])
718 {
719  Catch::Session session; // There must be exactly one instance
720 
721  // Let Catch (using Clara) parse the command line
722  session.applyCommandLine(argc, argv);
723 
724  int numFailed = session.run();
725 
726  // numFailed is clamped to 255 as some unices only use the lower 8 bits.
727  // This clamping has already been applied, so just return it here
728  // You can also do any post run clean-up here
729  return numFailed;
730 }
731 #else
732 int main() { return EXIT_SUCCESS; }
733 #endif
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:147
static void warpImage(const vpImage< Type > &src, const vpMatrix &T, vpImage< Type > &dst, const vpImageInterpolationType &interpolation=INTERPOLATION_NEAREST, bool fixedPointArithmetic=true, bool pixelCenter=false)
@ INTERPOLATION_LINEAR
Definition: vpImageTools.h:81
@ INTERPOLATION_NEAREST
Definition: vpImageTools.h:80
unsigned int getWidth() const
Definition: vpImage.h:242
unsigned int getSize() const
Definition: vpImage.h:221
unsigned int getHeight() const
Definition: vpImage.h:181
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1053
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:786
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1427
static double rad(double deg)
Definition: vpMath.h:129
static Type abs(const Type &x)
Definition: vpMath.h:269
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:169
Definition: vpRGBa.h:65