Visual Servoing Platform  version 3.3.0 under development (2020-02-17)
testImageResize.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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 resize.
33  *
34  *****************************************************************************/
35 
36 #include <visp3/core/vpDisplay.h>
37 #include <visp3/core/vpImage.h>
38 #include <visp3/core/vpImageTools.h>
39 #include <visp3/core/vpIoTools.h>
40 #include <visp3/io/vpImageIo.h>
41 #include <visp3/io/vpParseArgv.h>
42 
43 #include <visp3/gui/vpDisplayD3D.h>
44 #include <visp3/gui/vpDisplayGDI.h>
45 #include <visp3/gui/vpDisplayGTK.h>
46 #include <visp3/gui/vpDisplayOpenCV.h>
47 #include <visp3/gui/vpDisplayX.h>
48 
54 // List of allowed command line options
55 #define GETOPTARGS "cdi:W:H:m:bh"
56 
57 namespace
58 {
59 /*
60  Print the program options.
61 
62  \param name : Program name.
63  \param badparam : Bad parameter name.
64  \param ipath: Input image path.
65  \param w : Resize width.
66  \param h : Resize height.
67  \param m : Resize interpolation method.
68  */
69 void usage(const char *name, const char *badparam, std::string ipath, unsigned int &w, unsigned int &h, int &m)
70 {
71  fprintf(stdout, "\n\
72  Test image resize.\n\
73  \n\
74  SYNOPSIS\n\
75  %s [-i <input image path>] [-W <width>] [-H <height>] [-m <method>] [-b] [-c] [-d]\n\
76  [-h]\n \
77  ", name);
78 
79  fprintf(stdout, "\n\
80  OPTIONS: Default\n\
81  -i <input image path> %s\n\
82  Set image input path.\n\
83  From this path read \"Klimt/Klimt.pgm\"\n\
84  image.\n\
85  Setting the VISP_INPUT_IMAGE_PATH environment\n\
86  variable produces the same behaviour than using\n\
87  this option.\n\
88  \n\
89  -W <width> %u\n\
90  Set the new image width.\n\
91  \n\
92  -H <height> %u\n\
93  Set the new image height.\n\
94  \n\
95  -m <method> %d\n\
96  Set resize interpolation method.\n\
97  \n\
98  -b \n\
99  Run image resize benchmark.\n\
100  \n\
101  -c \n\
102  Disable mouse click.\n\
103  \n\
104  -d \n\
105  Disable image display.\n\
106  \n\
107  -h\n\
108  Print the help.\n\n", ipath.c_str(), w, h, m);
109 
110  if (badparam)
111  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
112 }
113 
128 bool getOptions(int argc, const char **argv, std::string &ipath, unsigned int &w, unsigned int &h, int &method,
129  bool &benchmark, bool &opt_display, bool &opt_click)
130 {
131  const char *optarg_;
132  int c;
133  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
134 
135  switch (c) {
136  case 'i':
137  ipath = optarg_;
138  break;
139  case 'W':
140  w = (unsigned int)atoi(optarg_);
141  break;
142  case 'H':
143  h = (unsigned int)atoi(optarg_);
144  break;
145  case 'm':
146  method = atoi(optarg_);
147  break;
148  case 'b':
149  benchmark = true;
150  break;
151  case 'h':
152  usage(argv[0], NULL, ipath, w, h, method);
153  return false;
154  break;
155 
156  case 'c':
157  opt_click = false;
158  break;
159  case 'd':
160  opt_display = false;
161  break;
162 
163  default:
164  usage(argv[0], optarg_, ipath, w, h, method);
165  return false;
166  break;
167  }
168  }
169 
170  if ((c == 1) || (c == -1)) {
171  // standalone param or error
172  usage(argv[0], NULL, ipath, w, h, method);
173  std::cerr << "ERROR: " << std::endl;
174  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
175  return false;
176  }
177 
178  return true;
179 }
180 }
181 
182 int main(int argc, const char **argv)
183 {
184  try {
185  std::string env_ipath;
186  std::string opt_ipath;
187  std::string ipath;
188  std::string filename;
189  unsigned int width = 101;
190  unsigned int height = 207;
191  int method = 0;
192  bool benchmark = false;
193  bool opt_display = true;
194  bool opt_click = true;
195 
196  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
197  // environment variable value
198  env_ipath = vpIoTools::getViSPImagesDataPath();
199 
200  // Set the default input path
201  if (!env_ipath.empty())
202  ipath = env_ipath;
203 
204  // Read the command line options
205  if (getOptions(argc, argv, opt_ipath, width, height, method, benchmark, opt_display, opt_click) == false) {
206  exit(EXIT_FAILURE);
207  }
208 
209  // Get the option values
210  if (!opt_ipath.empty())
211  ipath = opt_ipath;
212 
213  // Compare ipath and env_ipath. If they differ, we take into account
214  // the input path comming from the command line option
215  if (opt_ipath.empty()) {
216  if (ipath != env_ipath) {
217  std::cout << std::endl << "WARNING: " << std::endl;
218  std::cout << " Since -i <visp image path=" << ipath << "> "
219  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
220  << " we skip the environment variable." << std::endl;
221  }
222  }
223 
224  // Test if an input path is set
225  if (opt_ipath.empty() && env_ipath.empty()) {
226  usage(argv[0], NULL, ipath, width, height, method);
227  std::cerr << std::endl << "ERROR:" << std::endl;
228  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
229  << " environment variable to specify the location of the " << std::endl
230  << " image path where test images are located." << std::endl
231  << std::endl;
232  exit(EXIT_FAILURE);
233  }
234 
235  //
236  // Here starts really the test
237  //
238  for (int m = 0; m < 3; m++) {
239  std::cout << "Interpolation method: " << m << std::endl;
240 
241  vpImage<unsigned char> Itest(3, 4);
242  for (unsigned int cpt = 0; cpt < Itest.getSize(); cpt++) {
243  Itest.bitmap[cpt] = cpt;
244  }
245  vpImage<unsigned char> Itest_resize(Itest.getHeight() * 2, Itest.getWidth() * 2),
246  Itest_resize2(Itest.getHeight(), Itest.getWidth());
248  vpImageTools::resize(Itest_resize, Itest_resize2, (vpImageTools::vpImageInterpolationType)m);
249  std::cout << "Itest:\n" << Itest << std::endl;
250  std::cout << "Itest_resize:\n" << Itest_resize << std::endl;
251  std::cout << "Itest_resize2:\n" << Itest_resize2 << std::endl;
252  std::cout << "(Itest ==Itest_resize2)? " << (Itest == Itest_resize2) << std::endl;
253 
254  Itest.resize(4, 4);
255  for (unsigned int cpt = 0; cpt < Itest.getSize(); cpt++) {
256  Itest.bitmap[cpt] = cpt;
257  }
258  vpImageTools::resize(Itest, Itest_resize, Itest.getWidth() / 2, Itest.getHeight() / 2,
260  vpImageTools::resize(Itest_resize, Itest_resize2, Itest.getWidth(), Itest.getHeight(),
262  std::cout << "\nItest:\n" << Itest << std::endl;
263  std::cout << "Itest_resize:\n" << Itest_resize << std::endl;
264  std::cout << "Itest_resize2:\n" << Itest_resize2 << std::endl;
265  std::cout << "(Itest ==Itest_resize2)? " << (Itest == Itest_resize2) << std::endl << std::endl;
266  }
267 
268  // Grayscale image
269  vpImage<unsigned char> I; // Input image
270 
271  // Read the input grey image from the disk
272  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
273  std::cout << "Read image: " << filename << std::endl;
274  vpImageIo::read(I, filename);
275 
276  vpImage<unsigned char> I_resize;
277  double t = vpTime::measureTimeMs();
278  vpImageTools::resize(I, I_resize, width, height, (vpImageTools::vpImageInterpolationType)method);
279  t = vpTime::measureTimeMs() - t;
280  std::cout << "Time to resize from " << I.getWidth() << "x" << I.getHeight() << " to " << width << "x" << height
281  << ": " << t << " ms" << std::endl;
282 
283 #if defined(VISP_HAVE_X11)
284  vpDisplayX *d1 = new vpDisplayX, *d2 = new vpDisplayX;
285 #elif defined(VISP_HAVE_OPENCV)
286  vpDisplayOpenCV *d1 = new vpDisplayOpenCV, *d2 = new vpDisplayOpenCV;
287 #elif defined(VISP_HAVE_GTK)
288  vpDisplayGTK *d1 = new vpDisplayGTK, *d2 = new vpDisplayGTK;
289 #elif defined(VISP_HAVE_GDI)
290  vpDisplayGDI *d1 = new vpDisplayGDI, *d2 = new vpDisplayGDI;
291 #elif defined(VISP_HAVE_D3D9)
292  vpDisplayD3D *d1 = new vpDisplayD3D, *d2 = new vpDisplayD3D;
293 #else
294  std::cerr << "No display available!" << std::endl;
295  opt_display = false;
296 #endif
297 
298  if (opt_display) {
299 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || \
300  defined(VISP_HAVE_D3D9)
301  d1->init(I, 0, 0, "Grayscale image");
302  d2->init(I_resize, (int)I.getWidth() + 80, 0, "Grayscale image resized");
303 #endif
304 
306  vpDisplay::display(I_resize);
307  vpDisplay::displayText(I_resize, 20, 20, "Click to continue.", vpColor::red);
308  vpDisplay::flush(I);
309  vpDisplay::flush(I_resize);
310 
311  if (opt_click) {
312  vpDisplay::getClick(I_resize);
313  }
314  }
315 
316  // Color image
317  vpImage<vpRGBa> I_color; // Input image
318 
319  // Read the input grey image from the disk
320  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.ppm");
321  std::cout << "\nRead image: " << filename << std::endl;
322  vpImageIo::read(I_color, filename);
323 
324  vpImage<vpRGBa> I_color_resize;
325  t = vpTime::measureTimeMs();
326  vpImageTools::resize(I_color, I_color_resize, width, height, (vpImageTools::vpImageInterpolationType)method);
327  t = vpTime::measureTimeMs() - t;
328  std::cout << "Time to resize from " << I_color.getWidth() << "x" << I_color.getHeight() << " to " << width << "x"
329  << height << ": " << t << " ms" << std::endl;
330 
331 #if defined(VISP_HAVE_X11)
332  vpDisplayX *d3 = new vpDisplayX, *d4 = new vpDisplayX;
333 #elif defined(VISP_HAVE_OPENCV)
334  vpDisplayOpenCV *d3 = new vpDisplayOpenCV, *d4 = new vpDisplayOpenCV;
335 #elif defined(VISP_HAVE_GTK)
336  vpDisplayGTK *d3 = new vpDisplayGTK, *d4 = new vpDisplayGTK;
337 #elif defined(VISP_HAVE_GDI)
338  vpDisplayGDI *d3 = new vpDisplayGDI, *d4 = new vpDisplayGDI;
339 #elif defined(VISP_HAVE_D3D9)
340  vpDisplayD3D *d3 = new vpDisplayD3D, *d4 = new vpDisplayD3D;
341 #else
342  std::cerr << "No display available!" << std::endl;
343  opt_display = false;
344 #endif
345 
346  if (opt_display) {
347 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || \
348  defined(VISP_HAVE_D3D9)
349  d3->init(I_color, 0, 0, "Color image");
350  d4->init(I_color_resize, (int)I_color.getWidth() + 80, 0, "Color image resized");
351 #endif
352 
353  vpDisplay::display(I_color);
354  vpDisplay::display(I_color_resize);
355  vpDisplay::displayText(I_color_resize, 20, 20, "Click to quit.", vpColor::red);
356  vpDisplay::flush(I_color);
357  vpDisplay::flush(I_color_resize);
358  if (opt_click) {
359  vpDisplay::getClick(I_color_resize);
360  }
361  }
362 
363 #if defined(VISP_HAVE_X11) || defined(VISP_HAVE_OPENCV) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI) || \
364  defined(VISP_HAVE_D3D9)
365  delete d1;
366  delete d2;
367  delete d3;
368  delete d4;
369 #endif
370 
371  vpImage<vpRGBa> I_color_double, I_color_double_half;
372  vpImageTools::resize(I_color, I_color_double, I_color.getWidth() * 2, I_color.getHeight() * 2,
374  vpImageTools::resize(I_color_double, I_color_double_half, I_color.getWidth(), I_color.getHeight(),
376  std::cout << "\n(I_color == I_color_double_half)? " << (I_color == I_color_double_half) << std::endl;
377 
378  double root_mean_square_error = 0.0;
379  for (unsigned int i = 0; i < I_color.getHeight(); i++) {
380  for (unsigned int j = 0; j < I_color.getWidth(); j++) {
381  vpColVector c_error = I_color[i][j] - I_color_double_half[i][j];
382  root_mean_square_error += c_error.sumSquare();
383  }
384  }
385  std::cout << "Root Mean Square Error: " << sqrt(root_mean_square_error / (I_color.getSize() * 3)) << std::endl;
386 
387  vpImage<vpRGBa> I_color_half, I_color_half_double;
388  vpImageTools::resize(I_color, I_color_half, I_color.getWidth() / 2, I_color.getHeight() / 2,
390  vpImageTools::resize(I_color_half, I_color_half_double, I_color.getWidth(), I_color.getHeight(),
392  std::cout << "\n(I_color == I_color_half_double)? " << (I_color == I_color_half_double) << std::endl;
393 
394  root_mean_square_error = 0.0;
395  for (unsigned int i = 0; i < I_color.getHeight(); i++) {
396  for (unsigned int j = 0; j < I_color.getWidth(); j++) {
397  vpColVector c_error = I_color[i][j] - I_color_half_double[i][j];
398  root_mean_square_error += c_error.sumSquare();
399  }
400  }
401  std::cout << "Root Mean Square Error: " << sqrt(root_mean_square_error / (I_color.getSize() * 3)) << std::endl;
402 
403  if (benchmark) {
404 #if defined(VISP_HAVE_OPENCV) && !defined(__mips__) && !defined(__mips) && !defined(mips) && !defined(__MIPS__)
405  std::vector<double> scales;
406  scales.push_back(2.0);
407  scales.push_back(3.0);
408  scales.push_back(4.0);
409  scales.push_back(5.0);
410  scales.push_back(1 / 2.0);
411  scales.push_back(1 / 3.0);
412  scales.push_back(1 / 4.0);
413  scales.push_back(1 / 5.0);
414 
415  std::vector<vpImageTools::vpImageInterpolationType> interpolations;
416  interpolations.push_back(vpImageTools::INTERPOLATION_NEAREST);
417  interpolations.push_back(vpImageTools::INTERPOLATION_LINEAR);
418  interpolations.push_back(vpImageTools::INTERPOLATION_CUBIC);
419 
420  std::vector<int> interpolationsCV;
421  interpolationsCV.push_back(cv::INTER_NEAREST);
422  interpolationsCV.push_back(cv::INTER_LINEAR);
423  interpolationsCV.push_back(cv::INTER_CUBIC);
424 
425  std::vector<std::string> interpolationNames;
426  interpolationNames.push_back("INTERPOLATION_NEAREST");
427  interpolationNames.push_back("INTERPOLATION_LINEAR");
428  interpolationNames.push_back("INTERPOLATION_CUBIC");
429  {
430  vpImage<unsigned char> I_resize_perf;
431  cv::Mat img, img_resize_perf;
432  vpImageConvert::convert(I, img);
433 
434  for (size_t iter = 0; iter < interpolations.size(); iter ++) {
435  std::cout << "\nInterpolation (gray): " << interpolationNames[iter] << std::endl;
436 
437  for (size_t s = 0; s < scales.size(); s++) {
438  unsigned int width_resize = static_cast<unsigned int>(I.getWidth() * scales[s]);
439  unsigned int height_resize = static_cast<unsigned int>(I.getHeight() * scales[s]);
440  cv::Size new_size(static_cast<int>(width_resize), static_cast<int>(height_resize));
441  std::cout << "Resize from " << I.getWidth() << "x" << I.getHeight() << " to "
442  << width_resize << "x" << height_resize << std::endl;
443 
444  t = vpTime::measureTimeMs();
445  for (int nbIter = 0; nbIter < 10; nbIter++) {
446  vpImageTools::resize(I, I_resize_perf, width_resize, height_resize, interpolations[iter]);
447  }
448  t = vpTime::measureTimeMs() - t;
449 
450  double t_cv = vpTime::measureTimeMs();
451  for (int nbIter = 0; nbIter < 10; nbIter++) {
452  cv::resize(img, img_resize_perf, new_size, 0.0, 0.0, interpolationsCV[iter]);
453  }
454  t_cv = vpTime::measureTimeMs() - t_cv;
455 
456  std::cout << "ViSP (10 iterations): " << t << " ms ; Mean: " << t / 10 << " ms" << std::endl;
457  std::cout << "OpenCV (10 iterations): " << t_cv << " ms ; Mean: " << t_cv / 10 << " ms" << std::endl;
458 
459  double diff = 0.0, diff_abs = 0.0;
460  for (int i = 0; i < img_resize_perf.rows; i++) {
461  for (int j = 0; j < img_resize_perf.cols; j++) {
462  int d = img_resize_perf.at<uchar>(i, j) - I_resize_perf[i][j];
463  diff += d;
464  diff_abs += vpMath::abs(d);
465  }
466  }
467 
468  std::cout << "Mean diff: " << (diff / I_resize_perf.getSize()) << std::endl;
469  std::cout << "Mean abs diff: " << (diff_abs / I_resize_perf.getSize()) << std::endl;
470  }
471  }
472  }
473 
474  {
475  vpImage<vpRGBa> I_resize_perf;
476  cv::Mat img, img_resize_perf;
477  vpImageConvert::convert(I_color, img);
478 
479  for (size_t iter = 0; iter < interpolations.size(); iter++) {
480  std::cout << "\nInterpolation (color): " << interpolationNames[iter] << std::endl;
481 
482  for (size_t s = 0; s < scales.size(); s++) {
483  unsigned int width_resize = static_cast<unsigned int>(I.getWidth() * scales[s]);
484  unsigned int height_resize = static_cast<unsigned int>(I.getHeight() * scales[s]);
485  cv::Size new_size(static_cast<int>(width_resize), static_cast<int>(height_resize));
486  std::cout << "Resize from " << I_color.getWidth() << "x" << I_color.getHeight() << " to "
487  << width_resize << "x" << height_resize << std::endl;
488 
489  t = vpTime::measureTimeMs();
490  for (int nbIter = 0; nbIter < 10; nbIter++) {
491  vpImageTools::resize(I_color, I_resize_perf, width_resize, height_resize, interpolations[iter]);
492  }
493  t = vpTime::measureTimeMs() - t;
494 
495  double t_cv = vpTime::measureTimeMs();
496  for (int nbIter = 0; nbIter < 10; nbIter++) {
497  cv::resize(img, img_resize_perf, new_size, 0.0, 0.0, interpolationsCV[iter]);
498  }
499  t_cv = vpTime::measureTimeMs() - t_cv;
500 
501  std::cout << "ViSP (10 iterations): " << t << " ms ; Mean: " << t / 10 << " ms" << std::endl;
502  std::cout << "OpenCV (10 iterations): " << t_cv << " ms ; Mean: " << t_cv / 10 << " ms" << std::endl;
503 
504  double diff = 0.0, diff_abs = 0.0;
505  for (int i = 0; i < img_resize_perf.rows; i++) {
506  for (int j = 0; j < img_resize_perf.cols; j++) {
507  int d = (img_resize_perf.at<cv::Vec3b>(i, j)[0] - I_resize_perf[i][j].B) +
508  (img_resize_perf.at<cv::Vec3b>(i, j)[1] - I_resize_perf[i][j].G) +
509  (img_resize_perf.at<cv::Vec3b>(i, j)[2] - I_resize_perf[i][j].R);
510  diff += d;
511  diff_abs += vpMath::abs(d);
512  }
513  }
514 
515  std::cout << "Mean diff: " << (diff / I_resize_perf.getSize()) << std::endl;
516  std::cout << "Mean abs diff: " << (diff_abs / I_resize_perf.getSize()) << std::endl;
517  }
518  }
519  }
520 #endif
521  }
522 
523  return EXIT_SUCCESS;
524  } catch (const vpException &e) {
525  std::cerr << "Catch an exception: " << e << std::endl;
526  return EXIT_FAILURE;
527  }
528 }
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1292
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:150
error that can be emited by ViSP classes.
Definition: vpException.h:71
static void flush(const vpImage< unsigned char > &I)
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:126
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
static const vpColor red
Definition: vpColor.h:179
static Type abs(const Type &x)
Definition: vpMath.h:158
Display for windows using Direct3D 3rd party. Thus to enable this class Direct3D should be installed...
Definition: vpDisplayD3D.h:106
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1537
static void display(const vpImage< unsigned char > &I)
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:137
unsigned int getHeight() const
Definition: vpImage.h:186
static void read(vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:243
Implementation of column vector and the associated operations.
Definition: vpColVector.h:130
unsigned int getSize() const
Definition: vpImage.h:225
double sumSquare() const
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="")
unsigned int getWidth() const
Definition: vpImage.h:244
static void resize(const vpImage< Type > &I, vpImage< Type > &Ires, unsigned int width, unsigned int height, const vpImageInterpolationType &method=INTERPOLATION_NEAREST, unsigned int nThreads=0)