Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
testImageAddSub.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
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 http://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 images addition / substraction.
32  *
33  * Author:
34  * Souriya Trinh
35  *
36  *****************************************************************************/
37 
38 #include <visp3/core/vpImage.h>
39 #include <visp3/io/vpImageIo.h>
40 #include <visp3/core/vpImageTools.h>
41 #include <visp3/core/vpIoTools.h>
42 #include <visp3/io/vpParseArgv.h>
43 #include <visp3/core/vpDebug.h>
44 
51 // List of allowed command line options
52 #define GETOPTARGS "cdi:o:n:h"
53 
54 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user, int nbiter);
55 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user, int &nbiter);
56 
57 /*
58  Print the program options.
59 
60  \param name : Program name.
61  \param badparam : Bad parameter name.
62  \param ipath: Input image path.
63  \param opath : Output image path.
64  \param user : Username.
65  \param nbiter : Number of benchmark iterations.
66  */
67 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user, int nbiter)
68 {
69  fprintf(stdout, "\n\
70 Test images addition / substraction.\n\
71 \n\
72 SYNOPSIS\n\
73  %s [-i <input image path>] [-o <output image path>] [-n <nb iterations>]\n\
74  [-h]\n \
75 ", name);
76 
77  fprintf(stdout, "\n\
78 OPTIONS: Default\n\
79  -i <input image path> %s\n\
80  Set image input path.\n\
81  From this path read \"ViSP-images/Klimt/Klimt.pgm\"\n\
82  image.\n\
83  Setting the VISP_INPUT_IMAGE_PATH environment\n\
84  variable produces the same behaviour than using\n\
85  this option.\n\
86 \n\
87  -o <output image path> %s\n\
88  Set image output path.\n\
89  From this directory, creates the \"%s\"\n\
90  subdirectory depending on the username, where \n\
91  result output images are written.\n\
92 \n\
93  -n <nb iterations> %d\n\
94  Set the number of benchmark iterations.\n\
95 \n\
96  -h\n\
97  Print the help.\n\n",
98  ipath.c_str(), opath.c_str(), user.c_str(), nbiter);
99 
100  if (badparam)
101  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
102 }
103 
115 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user, int &nbiter)
116 {
117  const char *optarg_;
118  int c;
119  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
120 
121  switch (c) {
122  case 'i': ipath = optarg_; break;
123  case 'o': opath = optarg_; break;
124  case 'n': nbiter = atoi(optarg_); break;
125  case 'h': usage(argv[0], NULL, ipath, opath, user, nbiter); return false; break;
126 
127  case 'c':
128  case 'd':
129  break;
130 
131  default:
132  usage(argv[0], optarg_, ipath, opath, user, nbiter); return false; break;
133  }
134  }
135 
136  if ((c == 1) || (c == -1)) {
137  // standalone param or error
138  usage(argv[0], NULL, ipath, opath, user, nbiter);
139  std::cerr << "ERROR: " << std::endl;
140  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
141  return false;
142  }
143 
144  return true;
145 }
146 
147 void regularImageAdd(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
148  vpImage<unsigned char> &Ires, const bool saturate) {
149  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
150  throw (vpException(vpException::dimensionError, "The two images do not have the same size"));
151  }
152 
153  if ((I1.getHeight() != Ires.getHeight()) || (I1.getWidth() != Ires.getWidth())) {
154  Ires.resize(I1.getHeight(), I1.getWidth());
155  }
156 
157  unsigned char *ptr_I1 = I1.bitmap;
158  unsigned char *ptr_I2 = I2.bitmap;
159  unsigned char *ptr_Ires = Ires.bitmap;
160 
161  for (unsigned int cpt = 0; cpt < Ires.getSize(); cpt++, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
162  *ptr_Ires = saturate ? vpMath::saturate<unsigned char>( (short int) *ptr_I1 + (short int) *ptr_I2 ) : *ptr_I1 + *ptr_I2;
163  }
164 }
165 
166 void regularImageSubtract(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2,
167  vpImage<unsigned char> &Ires, const bool saturate) {
168  if ((I1.getHeight() != I2.getHeight()) || (I1.getWidth() != I2.getWidth())) {
169  throw (vpException(vpException::dimensionError, "The two images do not have the same size"));
170  }
171 
172  if ((I1.getHeight() != Ires.getHeight()) || (I1.getWidth() != Ires.getWidth())) {
173  Ires.resize(I1.getHeight(), I1.getWidth());
174  }
175 
176  unsigned char *ptr_I1 = I1.bitmap;
177  unsigned char *ptr_I2 = I2.bitmap;
178  unsigned char *ptr_Ires = Ires.bitmap;
179 
180  for (unsigned int cpt = 0; cpt < Ires.getSize(); cpt++, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
181  *ptr_Ires = saturate ? vpMath::saturate<unsigned char>( (short int) *ptr_I1 - (short int) *ptr_I2 ) : *ptr_I1 - *ptr_I2;
182  }
183 }
184 
185 int
186 main(int argc, const char ** argv)
187 {
188  try {
189  std::string env_ipath;
190  std::string opt_ipath;
191  std::string opt_opath;
192  std::string ipath;
193  std::string opath;
194  std::string filename;
195  std::string username;
196  int nbIterations = 100;
197 
198  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
199  env_ipath = vpIoTools::getViSPImagesDataPath();
200 
201  // Set the default input path
202  if (! env_ipath.empty())
203  ipath = env_ipath;
204 
205  // Set the default output path
206 #if defined(_WIN32)
207  opt_opath = "C:/temp";
208 #else
209  opt_opath = "/tmp";
210 #endif
211 
212  // Get the user login name
213  vpIoTools::getUserName(username);
214 
215  // Read the command line options
216  if (getOptions(argc, argv, opt_ipath, opt_opath, username, nbIterations) == false) {
217  exit (EXIT_FAILURE);
218  }
219 
220  // Get the option values
221  if (!opt_ipath.empty())
222  ipath = opt_ipath;
223  if (!opt_opath.empty())
224  opath = opt_opath;
225 
226  // Append to the output path string, the login name of the user
227  opath = vpIoTools::createFilePath(opath, username);
228 
229  // Test if the output path exist. If no try to create it
230  if (vpIoTools::checkDirectory(opath) == false) {
231  try {
232  // Create the dirname
234  }
235  catch (...) {
236  usage(argv[0], NULL, ipath, opt_opath, username, nbIterations);
237  std::cerr << std::endl
238  << "ERROR:" << std::endl;
239  std::cerr << " Cannot create " << opath << std::endl;
240  std::cerr << " Check your -o " << opt_opath << " option " << std::endl;
241  exit(EXIT_FAILURE);
242  }
243  }
244 
245  // Compare ipath and env_ipath. If they differ, we take into account
246  // the input path comming from the command line option
247  if (opt_ipath.empty()) {
248  if (ipath != env_ipath) {
249  std::cout << std::endl
250  << "WARNING: " << std::endl;
251  std::cout << " Since -i <visp image path=" << ipath << "> "
252  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
253  << " we skip the environment variable." << std::endl;
254  }
255  }
256 
257  // Test if an input path is set
258  if (opt_ipath.empty() && env_ipath.empty()){
259  usage(argv[0], NULL, ipath, opt_opath, username, nbIterations);
260  std::cerr << std::endl
261  << "ERROR:" << std::endl;
262  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
263  << std::endl
264  << " environment variable to specify the location of the " << std::endl
265  << " image path where test images are located." << std::endl << std::endl;
266  exit(EXIT_FAILURE);
267  }
268 
269  //
270  // Here starts really the test
271  //
272  vpImage<unsigned char> I; // Input image
273 
274  // Read the input grey image from the disk
275  filename = vpIoTools::createFilePath(ipath, "ViSP-images/Klimt/Klimt.pgm");
276  std::cout << "Read image: " << filename << std::endl << std::endl;
277  vpImageIo::read(I, filename);
278 
279 
280  // Test add image
281  vpImage<unsigned char> Inull(I.getHeight(), I.getWidth(), 0);
283  vpImageTools::imageAdd(I, Inull, Iadd);
284  if (Iadd != I) {
285  throw vpException(vpException::fatalError, "Problem with vpImageTools::imageAdd (Iadd != I)!");
286  } else {
287  std::cout << "(Iadd == I)? " << (Iadd == I) << std::endl;
288  }
289 
290  // Test in-place add
291  Iadd = 0;
292  vpImageTools::imageAdd(I, Iadd, Iadd);
293  if (Iadd != I) {
294  throw vpException(vpException::fatalError, "Problem with in-place vpImageTools::imageAdd (Iadd != I)!");
295  } else {
296  std::cout << "In-place (Iadd == I)? " << (Iadd == I) << std::endl;
297  }
298 
299 
300  // Test subtract image
301  Inull = 0;
303  vpImageTools::imageSubtract(I, Inull, Isub);
304  if (Isub != I) {
305  throw vpException(vpException::fatalError, "Problem with vpImageTools::imageSubtract (Iadd != I)!");
306  } else {
307  std::cout << "(Isub == I)? " << (Isub == I) << std::endl;
308  }
309 
310  // Test in-place subtract
311  Isub = 0;
312  vpImageTools::imageSubtract(I, Isub, Isub);
313  if (Isub != I) {
314  throw vpException(vpException::fatalError, "Problem with in-place vpImageTools::imageSubtract (Isub != I)!");
315  } else {
316  std::cout << "In-place (Isub == I)? " << (Isub == I) << std::endl;
317  }
318 
319 
320  // Test add image saturation
322  for (unsigned int cpt = 0; cpt < I2.getSize(); cpt++) {
323  I2.bitmap[cpt] = (unsigned char) cpt;
324  }
325 
326  // No saturation
327  vpImageTools::imageAdd(I, I2, Iadd, false);
328  vpImage<unsigned char> Iadd_regular;
329  regularImageAdd(I, I2, Iadd_regular, false);
330  if (Iadd != Iadd_regular) {
331  throw vpException(vpException::fatalError, "Problem with vpImageTools::imageAdd(I, I2, Iadd, false) (Iadd != Iadd_regular)!");
332  } else {
333  std::cout << "\nNo saturation (Iadd == Iadd_regular)? " << (Iadd == Iadd_regular) << std::endl;
334  }
335 
336  // Saturation
337  vpImageTools::imageAdd(I, I2, Iadd, true);
338  regularImageAdd(I, I2, Iadd_regular, true);
339  if (Iadd != Iadd_regular) {
340  throw vpException(vpException::fatalError, "Problem with vpImageTools::imageAdd(I, I2, Iadd, true) (Iadd != Iadd_regular)!");
341  } else {
342  std::cout << "Saturation (Iadd == Iadd_regular)? " << (Iadd == Iadd_regular) << std::endl;
343  }
344 
345 
346  // Test subtract image saturation
347  // No saturation
348  vpImageTools::imageSubtract(I, I2, Isub, false);
349  vpImage<unsigned char> Isub_regular;
350  regularImageSubtract(I, I2, Isub_regular, false);
351  if (Isub != Isub_regular) {
352  throw vpException(vpException::fatalError, "Problem with vpImageTools::imageSubtract(I, I2, Isub, false) (Isub != Isub_regular)!");
353  } else {
354  std::cout << "\nNo saturation (Isub == Isub_regular)? " << (Isub == Isub_regular) << std::endl;
355  }
356 
357  // Saturation
358  vpImageTools::imageSubtract(I, I2, Isub, true);
359  regularImageSubtract(I, I2, Isub_regular, true);
360  if (Isub != Isub_regular) {
361  throw vpException(vpException::fatalError, "Problem with vpImageTools::imageSubtract(I, I2, Isub, true) (Isub != Isub_regular)!");
362  } else {
363  std::cout << "Saturation (Isub == Isub_regular)? " << (Isub == Isub_regular) << std::endl;
364  }
365 
366 
367  // Benchmark
368  // Benchmark add no saturation
369  Iadd = 0;
370  double t_sse = vpTime::measureTimeMs();
371  for (int cpt = 0; cpt < nbIterations; cpt++) {
372  vpImageTools::imageAdd(I, Iadd, Iadd, false);
373  }
374  t_sse = vpTime::measureTimeMs() - t_sse;
375  std::cout << "\nAdd no saturation ; t_sse (" << nbIterations << " iterations)=" << t_sse << " ms" << std::endl;
376 
377  Iadd_regular = 0;
378  double t = vpTime::measureTimeMs();
379  for (int cpt = 0; cpt < nbIterations; cpt++) {
380  regularImageAdd(I, Iadd_regular, Iadd_regular, false);
381  }
382  t = vpTime::measureTimeMs() - t;
383  std::cout << "Add regular no saturation ; t (" << nbIterations << " iterations)=" << t << " ms"
384  << " ; Speed-up: " << (t / t_sse) << "X" << std::endl;
385  std::cout << "(Iadd == Iadd_regular)? " << (Iadd == Iadd_regular) << std::endl;
386 
387  // Write add no saturation
388  filename = vpIoTools::createFilePath(opath, "Klimt_add_no_sat_sse.pgm");
389  std::cout << "\nWrite: " << filename << std::endl;
390  vpImageIo::write(Iadd, filename);
391 
392  filename = vpIoTools::createFilePath(opath, "Klimt_add_no_sat.pgm");
393  std::cout << "Write: " << filename << std::endl;
394  vpImageIo::write(Iadd_regular, filename);
395 
396 
397  // Benchmark add saturation
398  Iadd = 0;
399  t_sse = vpTime::measureTimeMs();
400  for (int cpt = 0; cpt < nbIterations; cpt++) {
401  vpImageTools::imageAdd(I, Iadd, Iadd, true);
402  }
403  t_sse = vpTime::measureTimeMs() - t_sse;
404  std::cout << "\nAdd saturation ; t_sse (" << nbIterations << " iterations)=" << t_sse << " ms" << std::endl;
405 
406  Iadd_regular = 0;
407  t = vpTime::measureTimeMs();
408  for (int cpt = 0; cpt < nbIterations; cpt++) {
409  regularImageAdd(I, Iadd_regular, Iadd_regular, true);
410  }
411  t = vpTime::measureTimeMs() - t;
412  std::cout << "Add saturation ; t (" << nbIterations << " iterations)=" << t << " ms"
413  << " ; Speed-up: " << (t / t_sse) << "X" << std::endl;
414  std::cout << "(Iadd == Iadd_regular)? " << (Iadd == Iadd_regular) << std::endl;
415 
416  // Write add no saturation
417  filename = vpIoTools::createFilePath(opath, "Klimt_add_sat_sse.pgm");
418  std::cout << "\nWrite: " << filename << std::endl;
419  vpImageIo::write(Iadd, filename);
420 
421  filename = vpIoTools::createFilePath(opath, "Klimt_add_sat.pgm");
422  std::cout << "Write: " << filename << std::endl;
423  vpImageIo::write(Iadd_regular, filename);
424 
425 
426  // Benchmark subtract no saturation
427  Isub = I2;
428  t_sse = vpTime::measureTimeMs();
429  for (int cpt = 0; cpt < nbIterations; cpt++) {
430  vpImageTools::imageSubtract(I, Isub, Isub, false);
431  }
432  t_sse = vpTime::measureTimeMs() - t_sse;
433  std::cout << "\nSubtract no saturation ; t_sse (" << nbIterations << " iterations)=" << t_sse << " ms" << std::endl;
434 
435  Isub_regular = I2;
436  t = vpTime::measureTimeMs();
437  for (int cpt = 0; cpt < nbIterations; cpt++) {
438  regularImageSubtract(I, Isub_regular, Isub_regular, false);
439  }
440  t = vpTime::measureTimeMs() - t;
441  std::cout << "Subtract regular no saturation ; t (" << nbIterations << " iterations)=" << t << " ms"
442  << " ; Speed-up: " << (t / t_sse) << "X" << std::endl;
443  std::cout << "(Isub == Isub_regular)? " << (Isub == Isub_regular) << std::endl;
444 
445  // Write subtract no saturation
446  filename = vpIoTools::createFilePath(opath, "Klimt_subtract_no_sat_sse.pgm");
447  std::cout << "\nWrite: " << filename << std::endl;
448  vpImageIo::write(Isub, filename);
449 
450  filename = vpIoTools::createFilePath(opath, "Klimt_subtract_no_sat.pgm");
451  std::cout << "Write: " << filename << std::endl;
452  vpImageIo::write(Isub_regular, filename);
453 
454 
455  // Benchmark subtract saturation
456  Isub = I2;
457  t_sse = vpTime::measureTimeMs();
458  for (int cpt = 0; cpt < nbIterations; cpt++) {
459  vpImageTools::imageSubtract(I, Isub, Isub, true);
460  }
461  t_sse = vpTime::measureTimeMs() - t_sse;
462  std::cout << "\nSubtract saturation ; t_sse (" << nbIterations << " iterations)=" << t_sse << " ms" << std::endl;
463 
464  Isub_regular = I2;
465  t = vpTime::measureTimeMs();
466  for (int cpt = 0; cpt < nbIterations; cpt++) {
467  regularImageSubtract(I, Isub_regular, Isub_regular, true);
468  }
469  t = vpTime::measureTimeMs() - t;
470  std::cout << "Subtract saturation ; t (" << nbIterations << " iterations)=" << t << " ms"
471  << " ; Speed-up: " << (t / t_sse) << "X" << std::endl;
472  std::cout << "(Isub == Isub_regular)? " << (Isub == Isub_regular) << std::endl;
473 
474  // Write subtract no saturation
475  filename = vpIoTools::createFilePath(opath, "Klimt_subtract_sat_sse.pgm");
476  std::cout << "\nWrite: " << filename << std::endl;
477  vpImageIo::write(Isub, filename);
478 
479  filename = vpIoTools::createFilePath(opath, "Klimt_subtract_sat.pgm");
480  std::cout << "Write: " << filename << std::endl;
481  vpImageIo::write(Isub_regular, filename);
482 
483 
484  // Invert Klimt with image cropped
485  if (I.getWidth() >= 411 && I.getHeight() >= 507) {
486  vpRect r_crop(0, 0, 411, 507);
487  vpImage<unsigned char> I_crop;
488  vpImageTools::crop(I, r_crop, I_crop);
489  std::cout << "\nI_crop=" << I_crop.getWidth() << "x" << I_crop.getHeight() << std::endl;
490 
491  vpImage<unsigned char> I_invert(I_crop.getHeight(), I_crop.getWidth(), 255);
492  vpImageTools::imageSubtract(I_invert, I_crop, I_invert);
493 
494  vpImage<unsigned char> I_invert_regular(I_crop.getHeight(), I_crop.getWidth(), 255);
495  regularImageSubtract(I_invert_regular, I_crop, I_invert_regular, false);
496  std::cout << "(I_invert == I_invert_regular)? " << (I_invert == I_invert_regular) << std::endl;
497 
498  vpImage<unsigned char> I_white(I_crop.getHeight(), I_crop.getWidth(), 255);
499  vpImage<unsigned char> I_invert2 = I_invert;
500  vpImageTools::imageAdd(I_invert2, I_crop, I_invert2);
501  std::cout << "(I_invert2 == I_white)? " << (I_invert2 == I_white) << std::endl;
502 
503  filename = vpIoTools::createFilePath(opath, "Klimt_invert_crop.pgm");
504  std::cout << "Write: " << filename << std::endl;
505  vpImageIo::write(I_invert, filename);
506  }
507 
508  return EXIT_SUCCESS;
509  }
510  catch(const vpException &e) {
511  std::cerr << "Catch an exception: " << e << std::endl;
512  return EXIT_FAILURE;
513  }
514 }
static bool checkDirectory(const char *dirname)
Definition: vpIoTools.cpp:358
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1157
unsigned int getWidth() const
Definition: vpImage.h:226
Type * bitmap
points toward the bitmap
Definition: vpImage.h:134
error that can be emited by ViSP classes.
Definition: vpException.h:73
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:93
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:76
static void write(const vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:368
static void makeDirectory(const char *dirname)
Definition: vpIoTools.cpp:427
unsigned int getSize() const
Definition: vpImage.h:212
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1366
static std::string getUserName()
Definition: vpIoTools.cpp:177
void resize(const unsigned int h, const unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:903
static void read(vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:205
static void imageAdd(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Ires, const bool saturate=false)
static void crop(const vpImage< Type > &I, double roi_top, double roi_left, unsigned int roi_height, unsigned int roi_width, vpImage< Type > &crop, unsigned int v_scale=1, unsigned int h_scale=1)
Definition: vpImageTools.h:266
static void imageSubtract(const vpImage< unsigned char > &I1, const vpImage< unsigned char > &I2, vpImage< unsigned char > &Ires, const bool saturate=false)
unsigned int getHeight() const
Definition: vpImage.h:175
Defines a rectangle in the plane.
Definition: vpRect.h:82