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