Visual Servoing Platform  version 3.6.1 under development (2024-03-28)
perfImageWarp.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  * Benchmark image warping.
33  *
34 *****************************************************************************/
35 
36 #include <visp3/core/vpConfig.h>
37 
38 #ifdef VISP_HAVE_CATCH2
39 #define CATCH_CONFIG_ENABLE_BENCHMARKING
40 #define CATCH_CONFIG_RUNNER
41 #include <catch.hpp>
42 
43 #include <visp3/core/vpImageTools.h>
44 #include <visp3/core/vpIoTools.h>
45 #include <visp3/io/vpImageIo.h>
46 
47 namespace
48 {
49 static std::string ipath = vpIoTools::getViSPImagesDataPath();
50 }
51 
52 TEST_CASE("Benchmark affine warp on grayscale image", "[benchmark]")
53 {
54  std::string imgPath = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
55  REQUIRE(vpIoTools::checkFilename(imgPath));
56 
58  vpImageIo::read(I, imgPath);
59  REQUIRE(I.getSize() > 0);
60  vpImage<unsigned char> I_affine(I.getHeight(), I.getWidth());
61 
62  vpMatrix M(2, 3);
63  M.eye();
64 
65  const double theta = vpMath::rad(45);
66  M[0][0] = cos(theta);
67  M[0][1] = -sin(theta);
68  M[0][2] = I.getWidth() / 2;
69  M[1][0] = sin(theta);
70  M[1][1] = cos(theta);
71  M[1][2] = I.getHeight() / 2;
72 
73  BENCHMARK("Benchmark affine warp (ref code) (NN)")
74  {
76  return I_affine;
77  };
78 
79  BENCHMARK("Benchmark affine warp (fixed-point) (NN)")
80  {
82  return I_affine;
83  };
84 
85  BENCHMARK("Benchmark affine warp (ref code) (bilinear)")
86  {
88  return I_affine;
89  };
90 
91  BENCHMARK("Benchmark affine warp (fixed-point) (bilinear)")
92  {
94  return I_affine;
95  };
96 
97 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000) && defined(HAVE_OPENCV_IMGPROC)
98  cv::Mat img, img_affine;
100  vpImageConvert::convert(I, img_affine);
101 
102  cv::Mat M_cv(2, 3, CV_64FC1);
103  for (unsigned int i = 0; i < M.getRows(); i++) {
104  for (unsigned int j = 0; j < M.getCols(); j++) {
105  M_cv.at<double>(i, j) = M[i][j];
106  }
107  }
108 
109  BENCHMARK("Benchmark affine warp (OpenCV) (NN)")
110  {
111  cv::warpAffine(img, img_affine, M_cv, img.size(), cv::INTER_NEAREST);
112  return img_affine;
113  };
114 
115  BENCHMARK("Benchmark affine warp (OpenCV) (bilinear)")
116  {
117  cv::warpAffine(img, img_affine, M_cv, img.size(), cv::INTER_LINEAR);
118  return img_affine;
119  };
120 #endif
121 }
122 
123 TEST_CASE("Benchmark affine warp on color image", "[benchmark]")
124 {
125  std::string imgPath = vpIoTools::createFilePath(ipath, "Klimt/Klimt.ppm");
126  REQUIRE(vpIoTools::checkFilename(imgPath));
127 
128  vpImage<vpRGBa> I;
129  vpImageIo::read(I, imgPath);
130  REQUIRE(I.getSize() > 0);
131  vpImage<vpRGBa> I_affine(I.getHeight(), I.getWidth());
132 
133  vpMatrix M(2, 3);
134  M.eye();
135 
136  const double theta = vpMath::rad(45);
137  M[0][0] = cos(theta);
138  M[0][1] = -sin(theta);
139  M[0][2] = I.getWidth() / 2;
140  M[1][0] = sin(theta);
141  M[1][1] = cos(theta);
142  M[1][2] = I.getHeight() / 2;
143 
144  BENCHMARK("Benchmark affine warp (ref code) (NN)")
145  {
147  return I_affine;
148  };
149 
150  BENCHMARK("Benchmark affine warp (fixed-point) (NN)")
151  {
153  return I_affine;
154  };
155 
156  BENCHMARK("Benchmark affine warp (ref code) (bilinear)")
157  {
159  return I_affine;
160  };
161 
162  BENCHMARK("Benchmark affine warp (fixed-point) (bilinear)")
163  {
165  return I_affine;
166  };
167 
168 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000) && defined(HAVE_OPENCV_IMGPROC)
169  cv::Mat img, img_affine;
170  vpImageConvert::convert(I, img);
171  vpImageConvert::convert(I, img_affine);
172 
173  cv::Mat M_cv(2, 3, CV_64FC1);
174  for (unsigned int i = 0; i < M.getRows(); i++) {
175  for (unsigned int j = 0; j < M.getCols(); j++) {
176  M_cv.at<double>(i, j) = M[i][j];
177  }
178  }
179 
180  BENCHMARK("Benchmark affine warp (OpenCV) (NN)")
181  {
182  cv::warpAffine(img, img_affine, M_cv, img.size(), cv::INTER_NEAREST);
183  return img_affine;
184  };
185 
186  BENCHMARK("Benchmark affine warp (OpenCV) (bilinear)")
187  {
188  cv::warpAffine(img, img_affine, M_cv, img.size(), cv::INTER_LINEAR);
189  return img_affine;
190  };
191 #endif
192 }
193 
194 TEST_CASE("Benchmark perspective warp on grayscale image", "[benchmark]")
195 {
196  std::string imgPath = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
197  REQUIRE(vpIoTools::checkFilename(imgPath));
198 
200  vpImageIo::read(I, imgPath);
201  REQUIRE(I.getSize() > 0);
202  vpImage<unsigned char> I_perspective(I.getHeight(), I.getWidth());
203 
204  vpMatrix M(3, 3);
205  M.eye();
206 
207  const double theta = vpMath::rad(45);
208  M[0][0] = cos(theta);
209  M[0][1] = -sin(theta);
210  M[0][2] = I.getWidth() / 2;
211  M[1][0] = sin(theta);
212  M[1][1] = cos(theta);
213  M[1][2] = I.getHeight() / 2;
214 
215  BENCHMARK("Benchmark perspective warp (ref code) (NN)")
216  {
218  return I_perspective;
219  };
220 
221  BENCHMARK("Benchmark perspective warp (fixed-point) (NN)")
222  {
224  return I_perspective;
225  };
226 
227  BENCHMARK("Benchmark perspective warp (ref code) (bilinear)")
228  {
229  vpImageTools::warpImage(I, M, I_perspective, vpImageTools::INTERPOLATION_LINEAR, false);
230  return I_perspective;
231  };
232 
233  BENCHMARK("Benchmark perspective warp (fixed-point) (bilinear)")
234  {
236  return I_perspective;
237  };
238 
239 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000) && defined(HAVE_OPENCV_IMGPROC)
240  cv::Mat img, img_perspective;
241  vpImageConvert::convert(I, img);
242  vpImageConvert::convert(I, img_perspective);
243 
244  cv::Mat M_cv(3, 3, CV_64FC1);
245  for (unsigned int i = 0; i < M.getRows(); i++) {
246  for (unsigned int j = 0; j < M.getCols(); j++) {
247  M_cv.at<double>(i, j) = M[i][j];
248  }
249  }
250 
251  BENCHMARK("Benchmark perspective warp (OpenCV) (NN)")
252  {
253  cv::warpPerspective(img, img_perspective, M_cv, img.size(), cv::INTER_NEAREST);
254  return img_perspective;
255  };
256 
257  BENCHMARK("Benchmark perspective warp (OpenCV) (bilinear)")
258  {
259  cv::warpPerspective(img, img_perspective, M_cv, img.size(), cv::INTER_LINEAR);
260  return img_perspective;
261  };
262 #endif
263 }
264 
265 TEST_CASE("Benchmark perspective warp on color image", "[benchmark]")
266 {
267  std::string imgPath = vpIoTools::createFilePath(ipath, "Klimt/Klimt.ppm");
268  REQUIRE(vpIoTools::checkFilename(imgPath));
269 
270  vpImage<vpRGBa> I;
271  vpImageIo::read(I, imgPath);
272  REQUIRE(I.getSize() > 0);
273  vpImage<vpRGBa> I_perspective(I.getHeight(), I.getWidth());
274 
275  vpMatrix M(3, 3);
276  M.eye();
277 
278  const double theta = vpMath::rad(45);
279  M[0][0] = cos(theta);
280  M[0][1] = -sin(theta);
281  M[0][2] = I.getWidth() / 2;
282  M[1][0] = sin(theta);
283  M[1][1] = cos(theta);
284  M[1][2] = I.getHeight() / 2;
285 
286  BENCHMARK("Benchmark perspective warp (ref code) (NN)")
287  {
289  return I_perspective;
290  };
291 
292  BENCHMARK("Benchmark perspective warp (fixed-point) (NN)")
293  {
295  return I_perspective;
296  };
297 
298  BENCHMARK("Benchmark perspective warp (ref code) (bilinear)")
299  {
300  vpImageTools::warpImage(I, M, I_perspective, vpImageTools::INTERPOLATION_LINEAR, false);
301  return I_perspective;
302  };
303 
304  BENCHMARK("Benchmark perspective warp (fixed-point) (bilinear)")
305  {
307  return I_perspective;
308  };
309 
310 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000) && defined(HAVE_OPENCV_IMGPROC)
311  cv::Mat img, img_perspective;
312  vpImageConvert::convert(I, img);
313  vpImageConvert::convert(I, img_perspective);
314 
315  cv::Mat M_cv(3, 3, CV_64FC1);
316  for (unsigned int i = 0; i < M.getRows(); i++) {
317  for (unsigned int j = 0; j < M.getCols(); j++) {
318  M_cv.at<double>(i, j) = M[i][j];
319  }
320  }
321 
322  BENCHMARK("Benchmark perspective warp (OpenCV) (NN)")
323  {
324  cv::warpPerspective(img, img_perspective, M_cv, img.size(), cv::INTER_NEAREST);
325  return img_perspective;
326  };
327 
328  BENCHMARK("Benchmark perspective warp (OpenCV) (bilinear)")
329  {
330  cv::warpPerspective(img, img_perspective, M_cv, img.size(), cv::INTER_LINEAR);
331  return img_perspective;
332  };
333 #endif
334 }
335 
336 int main(int argc, char *argv[])
337 {
338  Catch::Session session; // There must be exactly one instance
339 
340  bool runBenchmark = false;
341  // Build a new parser on top of Catch's
342  using namespace Catch::clara;
343  auto cli = session.cli() // Get Catch's composite command line parser
344  | Opt(runBenchmark) // bind variable to a new option, with a hint string
345  ["--benchmark"] // the option names it will respond to
346  ("run benchmark?"); // description string for the help output
347 
348  // Now pass the new composite back to Catch so it uses that
349  session.cli(cli);
350 
351  // Let Catch (using Clara) parse the command line
352  session.applyCommandLine(argc, argv);
353 
354  if (runBenchmark) {
355  int numFailed = session.run();
356 
357  // numFailed is clamped to 255 as some unices only use the lower 8 bits.
358  // This clamping has already been applied, so just return it here
359  // You can also do any post run clean-up here
360  return numFailed;
361  }
362 
363  return EXIT_SUCCESS;
364 }
365 #else
366 #include <iostream>
367 
368 int main() { return EXIT_SUCCESS; }
369 #endif
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
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:1781
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:1199
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:2142
static double rad(double deg)
Definition: vpMath.h:127
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:146