Visual Servoing Platform  version 3.0.1
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
testImageMorphology.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 for vpImageMorphology functions.
32  *
33  * Authors:
34  * Souriya Trinh
35  *
36  *****************************************************************************/
43 #include <visp3/core/vpImageMorphology.h>
44 #include <visp3/core/vpImageTools.h>
45 #include <visp3/io/vpImageIo.h>
46 #include <visp3/io/vpParseArgv.h>
47 #include <visp3/core/vpIoTools.h>
48 
49 // List of allowed command line options
50 #define GETOPTARGS "cdi:n:h"
51 
52 
53 /*
54  Print the program options.
55 
56  \param name : Program name.
57  \param badparam : Bad parameter name.
58  \param ipath: Input image path.
59  \param nbiter : Iteration number.
60  */
61 void usage(const char *name, const char *badparam, std::string ipath, int nbiter)
62 {
63  fprintf(stdout, "\n\
64 Test vpImageMorphology functions.\n\
65 \n\
66 SYNOPSIS\n\
67  %s [-i <input image path>] [-n <nb benchmark iterations>]\n\
68  [-h]\n \
69 ", name);
70 
71  fprintf(stdout, "\n\
72 OPTIONS: Default\n\
73  -i <input image path> %s\n\
74  Set image input path.\n\
75  From this path read \"ViSP-images/Klimt/Klimt.pgm\"\n\
76  and \"ViSP-images/Klimt/Klimt.ppm\" images.\n\
77  Setting the VISP_INPUT_IMAGE_PATH environment\n\
78  variable produces the same behaviour than using\n\
79  this option.\n\
80  -n <nb benchmark iterations> %d\n\
81  Set the number of benchmark iterations.\n\
82 \n\
83  -h\n\
84  Print the help.\n\n",
85  ipath.c_str(), nbiter);
86 
87  if (badparam)
88  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
89 }
90 
100 bool getOptions(int argc, const char **argv, std::string &ipath, int &nbIterations)
101 {
102  const char *optarg_;
103  int c;
104  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
105 
106  switch (c) {
107  case 'i': ipath = optarg_; break;
108  case 'n': nbIterations = atoi(optarg_); break;
109  case 'h': usage(argv[0], NULL, ipath, nbIterations); return false; break;
110 
111  case 'c':
112  case 'd':
113  break;
114 
115  default:
116  usage(argv[0], optarg_, ipath, nbIterations); return false; break;
117  }
118  }
119 
120  if ((c == 1) || (c == -1)) {
121  // standalone param or error
122  usage(argv[0], NULL, ipath, nbIterations);
123  std::cerr << "ERROR: " << std::endl;
124  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
125  return false;
126  }
127 
128  return true;
129 }
130 
131 void printMatrix(const vpImage<unsigned char> &I, const std::string &name) {
132  std::cout << "\n" << name << ":" << std::endl;
133  for(unsigned int i = 0; i < I.getHeight(); i++) {
134  for(unsigned int j = 0; j < I.getWidth(); j++) {
135  std::cout << static_cast<unsigned>(I[i][j]) << " ";
136  }
137  std::cout << std::endl;
138  }
139 }
140 
141 // Erosion in the general case on grayscale images
143  if(I.getSize() == 0) {
144  std::cerr << "Input image is empty!" << std::endl;
145  return;
146  }
147 
148  const unsigned char null_value = 255;
149 
150  vpImage<unsigned char> J(I.getHeight()+2, I.getWidth()+2);
151  // Copy I to J and add border
152  for (unsigned int i = 0; i < J.getHeight(); i++) {
153  if (i == 0 || i == J.getHeight() - 1) {
154  for (unsigned int j = 0; j < J.getWidth(); j++) {
155  J[i][j] = null_value;
156  }
157  } else {
158  J[i][0] = null_value;
159  memcpy(J[i]+1, I[i-1], sizeof(unsigned char)*I.getWidth());
160  J[i][J.getWidth() - 1] = null_value;
161  }
162  }
163 
164  if (connexity == vpImageMorphology::CONNEXITY_4) {
165  unsigned int offset[5] = {1, J.getWidth(), J.getWidth()+1, J.getWidth()+2, J.getWidth()*2 + 1};
166 
167  for (unsigned int i = 0; i < I.getHeight(); i++) {
168  unsigned char *ptr_curr_J = J.bitmap + i*J.getWidth();
169  unsigned char *ptr_curr_I = I.bitmap + i*I.getWidth();
170 
171  for (unsigned int j = 0; j < I.getWidth(); j++) {
172  unsigned char min_value = null_value;
173  for (int k = 0; k < 5; k++) {
174  min_value = std::min(min_value, *(ptr_curr_J + j + offset[k]));
175  }
176 
177  *(ptr_curr_I + j) = min_value;
178  }
179  }
180  } else {
181  //CONNEXITY_8
182  unsigned int offset[9] = {0, 1, 2, J.getWidth(), J.getWidth()+1, J.getWidth()+2,
183  J.getWidth()*2, J.getWidth()*2 + 1, J.getWidth()*2 + 2};
184 
185  for (unsigned int i = 0; i < I.getHeight(); i++) {
186  unsigned char *ptr_curr_J = J.bitmap + i*J.getWidth();
187  unsigned char *ptr_curr_I = I.bitmap + i*I.getWidth();
188 
189  for (unsigned int j = 0; j < I.getWidth(); j++) {
190  unsigned char min_value = null_value;
191  for (int k = 0; k < 9; k++) {
192  min_value = std::min(min_value, *(ptr_curr_J + j + offset[k]));
193  }
194 
195  *(ptr_curr_I + j) = min_value;
196  }
197  }
198  }
199 }
200 
201 //Dilatation in the general case on grayscale images
203  if(I.getSize() == 0) {
204  std::cerr << "Input image is empty!" << std::endl;
205  return;
206  }
207 
208  const unsigned char null_value = 0;
209 
210  vpImage<unsigned char> J(I.getHeight()+2, I.getWidth()+2);
211  // Copy I to J and add border
212  for (unsigned int i = 0; i < J.getHeight(); i++) {
213  if (i == 0 || i == J.getHeight() - 1) {
214  for (unsigned int j = 0; j < J.getWidth(); j++) {
215  J[i][j] = null_value;
216  }
217  } else {
218  J[i][0] = null_value;
219  memcpy(J[i]+1, I[i-1], sizeof(unsigned char)*I.getWidth());
220  J[i][J.getWidth() - 1] = null_value;
221  }
222  }
223 
224  if (connexity == vpImageMorphology::CONNEXITY_4) {
225  unsigned int offset[5] = {1, J.getWidth(), J.getWidth()+1, J.getWidth()+2, J.getWidth()*2 + 1};
226 
227  for (unsigned int i = 0; i < I.getHeight(); i++) {
228  unsigned char *ptr_curr_J = J.bitmap + i*J.getWidth();
229  unsigned char *ptr_curr_I = I.bitmap + i*I.getWidth();
230 
231  for (unsigned int j = 0; j < I.getWidth(); j++) {
232  unsigned char max_value = null_value;
233  for (int k = 0; k < 5; k++) {
234  max_value = std::max(max_value, *(ptr_curr_J + j + offset[k]));
235  }
236 
237  *(ptr_curr_I + j) = max_value;
238  }
239  }
240  } else {
241  //CONNEXITY_8
242  unsigned int offset[9] = {0, 1, 2, J.getWidth(), J.getWidth()+1, J.getWidth()+2,
243  J.getWidth()*2, J.getWidth()*2 + 1, J.getWidth()*2 + 2};
244 
245  for (unsigned int i = 0; i < I.getHeight(); i++) {
246  unsigned char *ptr_curr_J = J.bitmap + i*J.getWidth();
247  unsigned char *ptr_curr_I = I.bitmap + i*I.getWidth();
248 
249  for (unsigned int j = 0; j < I.getWidth(); j++) {
250  unsigned char max_value = null_value;
251  for (int k = 0; k < 9; k++) {
252  max_value = std::max(max_value, *(ptr_curr_J + j + offset[k]));
253  }
254 
255  *(ptr_curr_I + j) = max_value;
256  }
257  }
258  }
259 }
260 
261 //Generate a magic square matrix to get a consistent grayscale image
262 void magicSquare(vpImage<unsigned char> &magic_square, const int N) {
263  magic_square.resize((unsigned int) N, (unsigned int) N, 0);
264 
265  int n = 1;
266  int i = 0, j = N/2;
267 
268  while (n <= N*N) {
269  magic_square[i][j] = vpMath::saturate<unsigned char>(n);
270  n++;
271 
272  int newi = vpMath::modulo((i-1), N), newj = vpMath::modulo((j+1), N);
273 
274  if (magic_square[newi][newj]) {
275  i++;
276  } else {
277  i = newi;
278  j = newj;
279  }
280  }
281 }
282 
283 int main(int argc, const char ** argv) {
284  try {
285  std::string env_ipath;
286  std::string opt_ipath;
287  std::string ipath;
288  std::string filename;
289  int nbIterations = 100;
290 
291  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
292  env_ipath = vpIoTools::getViSPImagesDataPath();
293 
294  // Set the default input path
295  if (! env_ipath.empty())
296  ipath = env_ipath;
297 
298  // Read the command line options
299  if (getOptions(argc, argv, opt_ipath, nbIterations) == false) {
300  exit (EXIT_FAILURE);
301  }
302 
303  // Get the option values
304  if (!opt_ipath.empty())
305  ipath = opt_ipath;
306 
307  // Compare ipath and env_ipath. If they differ, we take into account
308  // the input path comming from the command line option
309  if (opt_ipath.empty()) {
310  if (ipath != env_ipath) {
311  std::cout << std::endl
312  << "WARNING: " << std::endl;
313  std::cout << " Since -i <visp image path=" << ipath << "> "
314  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
315  << " we skip the environment variable." << std::endl;
316  }
317  }
318 
319  // Test if an input path is set
320  if (opt_ipath.empty() && env_ipath.empty()){
321  usage(argv[0], NULL, ipath, nbIterations);
322  std::cerr << std::endl
323  << "ERROR:" << std::endl;
324  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
325  << std::endl
326  << " environment variable to specify the location of the " << std::endl
327  << " image path where test images are located." << std::endl << std::endl;
328  exit(EXIT_FAILURE);
329  }
330 
331 
332  // Create a binary image
333  unsigned char image_data[8*16] = {
334  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
335  0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0,
336  0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0,
337  0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1,
338  0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
339  1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
340  1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1,
341  1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0
342  };
343 
344  vpImage<unsigned char> I(image_data, 8, 16, true);
345  printMatrix(I, "I");
346 
347 
348  //Regular code
349  //Dilatation
350  vpImage<unsigned char> I_dilatation1 = I;
351  vpImage<unsigned char> I_dilatation2 = I;
352 
353  vpImageMorphology::dilatation(I_dilatation1, (unsigned char) 1, (unsigned char) 0, vpImageMorphology::CONNEXITY_4);
354  vpImageMorphology::dilatation(I_dilatation2, (unsigned char) 1, (unsigned char) 0, vpImageMorphology::CONNEXITY_8);
355 
356  printMatrix(I_dilatation1, "I_dilatation1");
357  printMatrix(I_dilatation2, "I_dilatation2");
358 
359 
360  //Erosion
361  vpImage<unsigned char> I_erosion1 = I_dilatation1;
362  vpImage<unsigned char> I_erosion2 = I_dilatation2;
363 
364  vpImageMorphology::erosion(I_erosion1, (unsigned char) 1, (unsigned char) 0, vpImageMorphology::CONNEXITY_4);
365  vpImageMorphology::erosion(I_erosion2, (unsigned char) 1, (unsigned char) 0, vpImageMorphology::CONNEXITY_8);
366 
367  printMatrix(I_erosion1, "I_erosion1");
368  printMatrix(I_erosion2, "I_erosion2");
369 
370 
371  //SSE code
372  //Dilatation
373  vpImage<unsigned char> I_dilatation1_sse = I;
374  vpImage<unsigned char> I_dilatation2_sse = I;
375 
378 
379  printMatrix(I_dilatation1_sse, "I_dilatation1_sse");
380  printMatrix(I_dilatation2_sse, "I_dilatation2_sse");
381 
382  std::cout << "\n(I_dilatation1 == I_dilatation1_sse)? " << (I_dilatation1 == I_dilatation1_sse) << std::endl;
383  std::cout << "(I_dilatation2 == I_dilatation2_sse)? " << (I_dilatation2 == I_dilatation2_sse) << std::endl;
384 
385  if ((I_dilatation1 != I_dilatation1_sse)) {
386  throw vpException(vpException::fatalError, "(I_dilatation1 != I_dilatation1_sse)");
387  }
388  if ((I_dilatation2 != I_dilatation2_sse)) {
389  throw vpException(vpException::fatalError, "(I_dilatation2 != I_dilatation2_sse)");
390  }
391 
392 
393  //Erosion
394  vpImage<unsigned char> I_erosion1_sse = I_dilatation1_sse;
395  vpImage<unsigned char> I_erosion2_sse = I_dilatation2_sse;
396 
399 
400  printMatrix(I_erosion1_sse, "I_erosion1_sse");
401  printMatrix(I_erosion2_sse, "I_erosion2_sse");
402 
403  std::cout << "\n(I_erosion1 == I_erosion1_sse)? " << (I_erosion1 == I_erosion1_sse) << std::endl;
404  std::cout << "(I_erosion2 == I_erosion2_sse)? " << (I_erosion2 == I_erosion2_sse) << std::endl;
405 
406  if ((I_erosion1 != I_erosion1_sse)) {
407  throw vpException(vpException::fatalError, "(I_erosion1 != I_erosion1_sse)");
408  }
409  if ((I_erosion2 != I_erosion2_sse)) {
410  throw vpException(vpException::fatalError, "(I_erosion2 != I_erosion2_sse)");
411  }
412 
413 
414  //Check results against Matlab
415  unsigned char image_data_dilated1[8*16] = {
416  0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,
417  0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,0,
418  0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,
419  0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,
420  1,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,
421  1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,1,
422  1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,
423  1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,1
424  };
425 
426  vpImage<unsigned char> I_check_dilated1(image_data_dilated1, 8, 16, true);
427 
428  if (I_check_dilated1 != I_dilatation1_sse) {
429  throw vpException(vpException::fatalError, "(I_check_dilated1 != I_dilatation1_sse)");
430  }
431 
432 
433  unsigned char image_data_dilated2[8*16] = {
434  0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,0,
435  0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,
436  0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
437  0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
438  1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,
439  1,1,0,0,1,1,1,1,1,0,0,0,0,0,1,1,
440  1,1,0,0,1,1,1,1,1,1,1,0,0,0,1,1,
441  1,1,0,0,1,1,1,1,1,1,1,0,0,0,1,1
442  };
443 
444  vpImage<unsigned char> I_check_dilated2(image_data_dilated2, 8, 16, true);
445 
446  if (I_check_dilated2 != I_dilatation2_sse) {
447  throw vpException(vpException::fatalError, "(I_check_dilated2 != I_dilatation2_sse)");
448  }
449 
450 
451  unsigned char image_data_eroded1[8*16] = {
452  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
453  0,0,0,0,0,1,1,0,1,0,0,0,0,1,0,0,
454  0,0,0,0,1,1,1,1,0,1,0,0,0,1,1,0,
455  0,0,1,1,1,1,1,0,0,0,1,0,0,0,1,1,
456  0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,1,
457  1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,
458  1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,
459  1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0
460  };
461 
462  vpImage<unsigned char> I_check_eroded1(image_data_eroded1, 8, 16, true);
463 
464  if (I_check_eroded1 != I_erosion1_sse) {
465  throw vpException(vpException::fatalError, "(I_check_eroded1 != I_erosion1_sse)");
466  }
467 
468 
469  unsigned char image_data_eroded2[8*16] = {
470  0,0,0,0,0,1,1,1,1,0,0,0,0,1,0,0,
471  0,0,0,0,0,1,1,1,1,0,0,0,0,1,0,0,
472  0,0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,
473  0,0,1,1,1,1,1,1,1,1,1,0,0,0,1,1,
474  0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,1,
475  1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,1,
476  1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,1,
477  1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1
478  };
479 
480  vpImage<unsigned char> I_check_eroded2(image_data_eroded2, 8, 16, true);
481 
482  if (I_check_eroded2 != I_erosion2_sse) {
483  throw vpException(vpException::fatalError, "(I_check_eroded2 != I_erosion2_sse)");
484  }
485 
486 
487 
488  //Morphology on grayscale images
489  vpImage<unsigned char> I_magic_square;
490  magicSquare(I_magic_square, 17);
491  printMatrix(I_magic_square, "I_magic_square");
492 
493  //Dilatation CONNEXITY_4 grayscale
494  vpImage<unsigned char> I_magic_square_dilatation1 = I_magic_square;
495  vpImage<unsigned char> I_magic_square_dilatation1_sse = I_magic_square;
496 
497  generalDilatation(I_magic_square_dilatation1, vpImageMorphology::CONNEXITY_4);
498  vpImageMorphology::dilatation(I_magic_square_dilatation1_sse, vpImageMorphology::CONNEXITY_4);
499 
500  if ((I_magic_square_dilatation1 != I_magic_square_dilatation1_sse)) {
501  throw vpException(vpException::fatalError, "(I_magic_square_dilatation1 != I_magic_square_dilatation1_sse)");
502  }
503 
504  //Dilatation CONNEXITY_8 grayscale
505  vpImage<unsigned char> I_magic_square_dilatation2 = I_magic_square;
506  vpImage<unsigned char> I_magic_square_dilatation2_sse = I_magic_square;
507 
508  generalDilatation(I_magic_square_dilatation2, vpImageMorphology::CONNEXITY_8);
509  vpImageMorphology::dilatation(I_magic_square_dilatation2_sse, vpImageMorphology::CONNEXITY_8);
510 
511  if ((I_magic_square_dilatation2 != I_magic_square_dilatation2_sse)) {
512  throw vpException(vpException::fatalError, "(I_magic_square_dilatation2 != I_magic_square_dilatation2_sse)");
513  }
514 
515  //Erosion CONNEXITY_4 grayscale
516  vpImage<unsigned char> I_magic_square_erosion1 = I_magic_square_dilatation1;
517  vpImage<unsigned char> I_magic_square_erosion1_sse = I_magic_square_dilatation1_sse;
518 
519  generalErosion(I_magic_square_erosion1, vpImageMorphology::CONNEXITY_4);
520  vpImageMorphology::erosion(I_magic_square_erosion1_sse, vpImageMorphology::CONNEXITY_4);
521 
522  if ((I_magic_square_erosion1 != I_magic_square_erosion1_sse)) {
523  throw vpException(vpException::fatalError, "(I_magic_square_erosion1 != I_magic_square_erosion1_sse)");
524  }
525 
526  //Dilatation CONNEXITY_8 grayscale
527  vpImage<unsigned char> I_magic_square_erosion2 = I_magic_square_dilatation2;
528  vpImage<unsigned char> I_magic_square_erosion2_sse = I_magic_square_dilatation2_sse;
529 
530  generalErosion(I_magic_square_erosion2, vpImageMorphology::CONNEXITY_8);
531  vpImageMorphology::erosion(I_magic_square_erosion2_sse, vpImageMorphology::CONNEXITY_8);
532 
533  if ((I_magic_square_erosion2 != I_magic_square_erosion2_sse)) {
534  throw vpException(vpException::fatalError, "(I_magic_square_erosion2 != I_magic_square_erosion2_sse)");
535  }
536 
537 
538  //Check results against Matlab (grayscale)
539  unsigned char image_data2_dilated1[17*17] = {
540  174,193,212,231,250,255,255,255,255,39,58,77,96,115,134,153,154,
541  192,211,230,249,255,255,255,255,38,57,76,95,114,133,152,170,172,
542  210,229,248,255,255,255,255,37,56,75,94,113,132,151,170,172,190,
543  228,247,255,255,255,255,36,55,74,93,112,131,150,169,187,190,208,
544  246,255,255,255,255,51,54,73,92,111,130,149,168,187,189,208,226,
545  255,255,255,255,51,53,72,91,110,129,148,167,186,204,207,226,244,
546  255,255,255,50,68,71,90,109,128,147,166,185,204,206,225,244,255,
547  255,255,49,68,70,89,108,127,146,165,184,203,221,224,243,255,255,
548  255,48,67,85,88,107,126,145,164,183,202,221,223,242,255,255,255,
549  47,66,85,87,106,125,144,163,182,201,220,238,241,255,255,255,255,
550  65,84,102,105,124,143,162,181,200,219,238,240,255,255,255,255,45,
551  83,102,104,123,142,161,180,199,218,237,255,255,255,255,255,45,63,
552  101,119,122,141,160,179,198,217,236,255,255,255,255,255,44,63,81,
553  119,121,140,159,178,197,216,235,254,255,255,255,255,43,62,81,99,
554  136,139,158,177,196,215,234,253,255,255,255,255,42,61,80,99,117,
555  138,157,176,195,214,233,252,255,255,255,255,41,60,79,98,117,135,
556  156,175,194,213,232,251,255,255,255,255,40,59,78,97,116,135,135
557  };
558 
559  vpImage<unsigned char> I2_check_dilated1(image_data2_dilated1, 17, 17, true);
560 
561  if (I2_check_dilated1 != I_magic_square_dilatation1_sse) {
562  throw vpException(vpException::fatalError, "(I2_check_dilated1 != I_magic_square_dilatation1_sse)");
563  }
564 
565 
566  unsigned char image_data2_dilated2[17*17] = {
567  192,211,230,249,255,255,255,255,255,57,76,95,114,133,152,154,154,
568  210,229,248,255,255,255,255,255,255,75,94,113,132,151,170,172,172,
569  228,247,255,255,255,255,255,255,74,93,112,131,150,169,171,190,190,
570  246,255,255,255,255,255,255,73,92,111,130,149,168,187,189,208,208,
571  255,255,255,255,255,255,72,91,110,129,148,167,186,188,207,226,226,
572  255,255,255,255,255,71,90,109,128,147,166,185,204,206,225,244,244,
573  255,255,255,255,70,89,108,127,146,165,184,203,205,224,243,255,255,
574  255,255,255,69,88,107,126,145,164,183,202,221,223,242,255,255,255,
575  255,255,85,87,106,125,144,163,182,201,220,222,241,255,255,255,255,
576  65,84,86,105,124,143,162,181,200,219,238,240,255,255,255,255,255,
577  83,102,104,123,142,161,180,199,218,237,239,255,255,255,255,255,255,
578  101,103,122,141,160,179,198,217,236,255,255,255,255,255,255,255,63,
579  119,121,140,159,178,197,216,235,254,255,255,255,255,255,255,81,81,
580  120,139,158,177,196,215,234,253,255,255,255,255,255,255,80,99,99,
581  138,157,176,195,214,233,252,255,255,255,255,255,255,79,98,117,117,
582  156,175,194,213,232,251,255,255,255,255,255,255,78,97,116,135,135,
583  156,175,194,213,232,251,255,255,255,255,255,59,78,97,116,135,135
584  };
585 
586  vpImage<unsigned char> I2_check_dilated2(image_data2_dilated2, 17, 17, true);
587 
588  if (I2_check_dilated2 != I_magic_square_dilatation2_sse) {
589  throw vpException(vpException::fatalError, "(I2_check_dilated2 != I_magic_square_dilatation2_sse)");
590  }
591 
592 
593  unsigned char image_data2_eroded1[17*17] = {
594  174,174,193,212,231,250,255,255,38,39,39,58,77,96,115,134,153,
595  174,192,211,230,249,255,255,37,38,38,57,76,95,114,133,152,154,
596  192,210,229,248,255,255,36,37,37,56,75,94,113,132,151,170,172,
597  210,228,247,255,255,36,36,36,55,74,93,112,131,150,169,172,190,
598  228,246,255,255,51,51,36,54,73,92,111,130,149,168,187,189,208,
599  246,255,255,50,51,51,53,72,91,110,129,148,167,186,189,207,226,
600  255,255,49,50,50,53,71,90,109,128,147,166,185,204,206,225,244,
601  255,48,49,49,68,70,89,108,127,146,165,184,203,206,224,243,255,
602  47,48,48,67,70,88,107,126,145,164,183,202,221,223,242,255,255,
603  47,47,66,85,87,106,125,144,163,182,201,220,223,241,255,255,45,
604  47,65,84,87,105,124,143,162,181,200,219,238,240,255,255,45,45,
605  65,83,102,104,123,142,161,180,199,218,237,240,255,255,44,45,45,
606  83,101,104,122,141,160,179,198,217,236,255,255,255,43,44,44,63,
607  101,119,121,140,159,178,197,216,235,254,255,255,42,43,43,62,81,
608  119,121,139,158,177,196,215,234,253,255,255,41,42,42,61,80,99,
609  136,138,157,176,195,214,233,252,255,255,40,41,41,60,79,98,117,
610  138,156,175,194,213,232,251,255,255,40,40,40,59,78,97,116,135
611  };
612 
613  vpImage<unsigned char> I2_check_eroded1(image_data2_eroded1, 17, 17, true);
614 
615  if (I2_check_eroded1 != I_magic_square_erosion1_sse) {
616  printMatrix(I_magic_square_erosion1_sse, "I_magic_square_erosion1_sse");
617 
618  throw vpException(vpException::fatalError, "(I2_check_eroded1 != I_magic_square_erosion1_sse)");
619  }
620 
621 
622  unsigned char image_data2_eroded2[17*17] = {
623  192,192,211,230,249,255,255,255,57,57,57,76,95,114,133,152,154,
624  192,192,211,230,249,255,255,74,57,57,57,76,95,114,133,152,154,
625  210,210,229,248,255,255,73,73,73,74,75,94,113,132,151,170,172,
626  228,228,247,255,255,72,72,72,73,74,93,112,131,150,169,171,190,
627  246,246,255,255,71,71,71,72,73,92,111,130,149,168,187,189,208,
628  255,255,255,70,70,70,71,72,91,110,129,148,167,186,188,207,226,
629  255,255,69,69,69,70,71,90,109,128,147,166,185,204,206,225,244,
630  255,85,69,69,69,70,89,108,127,146,165,184,203,205,224,243,255,
631  65,65,69,69,69,88,107,126,145,164,183,202,221,223,242,255,255,
632  65,65,84,85,87,106,125,144,163,182,201,220,222,241,255,255,255,
633  65,65,84,86,105,124,143,162,181,200,219,238,240,255,255,63,63,
634  83,83,102,104,123,142,161,180,199,218,237,239,255,255,81,63,63,
635  101,101,103,122,141,160,179,198,217,236,255,255,255,80,80,63,63,
636  119,119,121,140,159,178,197,216,235,254,255,255,79,79,79,80,81,
637  120,120,139,158,177,196,215,234,253,255,255,78,78,78,79,80,99,
638  138,138,157,176,195,214,233,252,255,255,59,59,59,78,79,98,117,
639  156,156,175,194,213,232,251,255,255,255,59,59,59,78,97,116,135
640  };
641 
642  vpImage<unsigned char> I2_check_eroded2(image_data2_eroded2, 17, 17, true);
643 
644  if (I2_check_eroded2 != I_magic_square_erosion2_sse) {
645  throw vpException(vpException::fatalError, "(I2_check_eroded2 != I_magic_square_erosion2_sse)");
646  }
647 
648 
649 
650 
651  std::cout << std::endl;
652  vpImage<unsigned char> I_Klimt;
653  filename = vpIoTools::createFilePath(ipath, "ViSP-images/Klimt/Klimt.pgm");
654  vpImageIo::read(I_Klimt, filename);
655 
656 
657  //Benchmark on binarized image (compare regular code with SSE implementation)
658 
659 
660  vpImage<unsigned char> I_Klimt_binarized = I_Klimt;
661  vpImageTools::binarise(I_Klimt_binarized, (unsigned char) 127, (unsigned char) 127, (unsigned char) 0, (unsigned char) 1, (unsigned char) 1, true);
662 
663 
664  //Dilatation CONNEXITY_4
665  vpImage<unsigned char> I_Klimt_binarized_dilatation1 = I_Klimt_binarized;
666  vpImage<unsigned char> I_Klimt_binarized_dilatation1_sse = I_Klimt_binarized;
667 
668  double t = vpTime::measureTimeMs();
669  for (int cpt = 0; cpt < nbIterations; cpt++) {
670  vpImageMorphology::dilatation(I_Klimt_binarized_dilatation1, (unsigned char) 1, (unsigned char) 0, vpImageMorphology::CONNEXITY_4);
671  }
672  t = vpTime::measureTimeMs() - t;
673 
674  double t_sse = vpTime::measureTimeMs();
675  for (int cpt = 0; cpt < nbIterations; cpt++) {
676  vpImageMorphology::dilatation(I_Klimt_binarized_dilatation1_sse, vpImageMorphology::CONNEXITY_4);
677  }
678  t_sse = vpTime::measureTimeMs() - t_sse;
679 
680  std::cout << "(I_Klimt_binarized_dilatation1 == I_Klimt_binarized_dilatation1_sse)? "
681  << (I_Klimt_binarized_dilatation1 == I_Klimt_binarized_dilatation1_sse)
682  << " ; t=" << t << " ms ; t_sse=" << t_sse << " ms"
683  << " ; speed-up=" << (t/t_sse) << "X" << std::endl;
684 
685 
686  //Dilatation CONNEXITY_8
687  vpImage<unsigned char> I_Klimt_binarized_dilatation2 = I_Klimt_binarized;
688  vpImage<unsigned char> I_Klimt_binarized_dilatation2_sse = I_Klimt_binarized;
689 
690  t = vpTime::measureTimeMs();
691  for (int cpt = 0; cpt < nbIterations; cpt++) {
692  vpImageMorphology::dilatation(I_Klimt_binarized_dilatation2, (unsigned char) 1, (unsigned char) 0, vpImageMorphology::CONNEXITY_8);
693  }
694  t = vpTime::measureTimeMs() - t;
695 
696  t_sse = vpTime::measureTimeMs();
697  for (int cpt = 0; cpt < nbIterations; cpt++) {
698  vpImageMorphology::dilatation(I_Klimt_binarized_dilatation2_sse, vpImageMorphology::CONNEXITY_8);
699  }
700  t_sse = vpTime::measureTimeMs() - t_sse;
701 
702  std::cout << "(I_Klimt_binarized_dilatation2 == I_Klimt_binarized_dilatation2_sse)? "
703  << (I_Klimt_binarized_dilatation2 == I_Klimt_binarized_dilatation2_sse)
704  << " ; t=" << t << " ms ; t_sse=" << t_sse << " ms"
705  << " ; speed-up=" << (t/t_sse) << "X" << std::endl;
706 
707 
708  //Erosion CONNEXITY_4
709  vpImage<unsigned char> I_Klimt_binarized_erosion1 = I_Klimt_binarized;
710  vpImage<unsigned char> I_Klimt_binarized_erosion1_sse = I_Klimt_binarized;
711 
712  t = vpTime::measureTimeMs();
713  for (int cpt = 0; cpt < nbIterations; cpt++) {
714  vpImageMorphology::erosion(I_Klimt_binarized_erosion1, (unsigned char) 1, (unsigned char) 0, vpImageMorphology::CONNEXITY_4);
715  }
716  t = vpTime::measureTimeMs() - t;
717 
718  t_sse = vpTime::measureTimeMs();
719  for (int cpt = 0; cpt < nbIterations; cpt++) {
720  vpImageMorphology::erosion(I_Klimt_binarized_erosion1_sse, vpImageMorphology::CONNEXITY_4);
721  }
722  t_sse = vpTime::measureTimeMs() - t_sse;
723 
724  std::cout << "(I_Klimt_binarized_erosion1 == I_Klimt_binarized_erosion1_sse)? "
725  << (I_Klimt_binarized_erosion1 == I_Klimt_binarized_erosion1_sse)
726  << " ; t=" << t << " ms ; t_sse=" << t_sse << " ms"
727  << " ; speed-up=" << (t/t_sse) << "X" << std::endl;
728 
729 
730  //Erosion CONNEXITY_8
731  vpImage<unsigned char> I_Klimt_binarized_erosion2 = I_Klimt_binarized;
732  vpImage<unsigned char> I_Klimt_binarized_erosion2_sse = I_Klimt_binarized;
733 
734  t = vpTime::measureTimeMs();
735  for (int cpt = 0; cpt < nbIterations; cpt++) {
736  vpImageMorphology::erosion(I_Klimt_binarized_erosion2, (unsigned char) 1, (unsigned char) 0, vpImageMorphology::CONNEXITY_8);
737  }
738  t = vpTime::measureTimeMs() - t;
739 
740  t_sse = vpTime::measureTimeMs();
741  for (int cpt = 0; cpt < nbIterations; cpt++) {
742  vpImageMorphology::erosion(I_Klimt_binarized_erosion2_sse, vpImageMorphology::CONNEXITY_8);
743  }
744  t_sse = vpTime::measureTimeMs() - t_sse;
745 
746  std::cout << "(I_Klimt_binarized_erosion2 == I_Klimt_binarized_erosion2_sse)? "
747  << (I_Klimt_binarized_erosion2 == I_Klimt_binarized_erosion2_sse)
748  << " ; t=" << t << " ms ; t_sse=" << t_sse << " ms"
749  << " ; speed-up=" << (t/t_sse) << "X" << std::endl;
750 
751 
752 
753  //Benchmark on grayscale images (compare regular code with SSE implementation)
754 
755 
756  //Dilatation CONNEXITY_4 grayscale
757  vpImage<unsigned char> I_Klimt_dilatation1 = I_Klimt;
758  vpImage<unsigned char> I_Klimt_dilatation1_sse = I_Klimt;
759 
760  t = vpTime::measureTimeMs();
761  for (int cpt = 0; cpt < nbIterations; cpt++) {
762  generalDilatation(I_Klimt_dilatation1, vpImageMorphology::CONNEXITY_4);
763  }
764  t = vpTime::measureTimeMs() - t;
765 
766  t_sse = vpTime::measureTimeMs();
767  for (int cpt = 0; cpt < nbIterations; cpt++) {
769  }
770  t_sse = vpTime::measureTimeMs() - t_sse;
771 
772  std::cout << "(I_Klimt_dilatation1 == I_Klimt_dilatation1_sse)? "
773  << (I_Klimt_dilatation1 == I_Klimt_dilatation1_sse)
774  << " ; t=" << t << " ms ; t_sse=" << t_sse << " ms"
775  << " ; speed-up=" << (t/t_sse) << "X" << std::endl;
776 
777 
778  //Dilatation CONNEXITY_8 grayscale
779  vpImage<unsigned char> I_Klimt_dilatation2 = I_Klimt;
780  vpImage<unsigned char> I_Klimt_dilatation2_sse = I_Klimt;
781 
782  t = vpTime::measureTimeMs();
783  for (int cpt = 0; cpt < nbIterations; cpt++) {
784  generalDilatation(I_Klimt_dilatation2, vpImageMorphology::CONNEXITY_8);
785  }
786  t = vpTime::measureTimeMs() - t;
787 
788  t_sse = vpTime::measureTimeMs();
789  for (int cpt = 0; cpt < nbIterations; cpt++) {
791  }
792  t_sse = vpTime::measureTimeMs() - t_sse;
793 
794  std::cout << "(I_Klimt_dilatation2 == I_Klimt_dilatation2_sse)? "
795  << (I_Klimt_dilatation2 == I_Klimt_dilatation2_sse)
796  << " ; t=" << t << " ms ; t_sse=" << t_sse << " ms"
797  << " ; speed-up=" << (t/t_sse) << "X" << std::endl;
798 
799 
800  //Erosion CONNEXITY_4 grayscale
801  vpImage<unsigned char> I_Klimt_erosion1 = I_Klimt;
802  vpImage<unsigned char> I_Klimt_erosion1_sse = I_Klimt;
803 
804  t = vpTime::measureTimeMs();
805  for (int cpt = 0; cpt < nbIterations; cpt++) {
806  generalErosion(I_Klimt_erosion1, vpImageMorphology::CONNEXITY_4);
807  }
808  t = vpTime::measureTimeMs() - t;
809 
810  t_sse = vpTime::measureTimeMs();
811  for (int cpt = 0; cpt < nbIterations; cpt++) {
813  }
814  t_sse = vpTime::measureTimeMs() - t_sse;
815 
816  std::cout << "(I_Klimt_erosion1 == I_Klimt_erosion1_sse)? "
817  << (I_Klimt_erosion1 == I_Klimt_erosion1_sse)
818  << " ; t=" << t << " ms ; t_sse=" << t_sse << " ms"
819  << " ; speed-up=" << (t/t_sse) << "X" << std::endl;
820 
821 
822  //Erosion CONNEXITY_8 grayscale
823  vpImage<unsigned char> I_Klimt_erosion2 = I_Klimt;
824  vpImage<unsigned char> I_Klimt_erosion2_sse = I_Klimt;
825 
826  t = vpTime::measureTimeMs();
827  for (int cpt = 0; cpt < nbIterations; cpt++) {
828  generalErosion(I_Klimt_erosion2, vpImageMorphology::CONNEXITY_8);
829  }
830  t = vpTime::measureTimeMs() - t;
831 
832  t_sse = vpTime::measureTimeMs();
833  for (int cpt = 0; cpt < nbIterations; cpt++) {
835  }
836  t_sse = vpTime::measureTimeMs() - t_sse;
837 
838  std::cout << "(I_Klimt_erosion2 == I_Klimt_erosion2_sse)? "
839  << (I_Klimt_erosion2 == I_Klimt_erosion2_sse)
840  << " ; t=" << t << " ms ; t_sse=" << t_sse << " ms"
841  << " ; speed-up=" << (t/t_sse) << "X" << std::endl;
842 
843 
844  //Compare with OpenCV
845 #if (VISP_HAVE_OPENCV_VERSION >= 0x030000)
846  std::cout << std::endl;
847 
848  cv::Mat cross_SE = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(3,3));
849  cv::Mat rect_SE = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3,3));
850 
851  //Dilatation CONNEXITY_4 grayscale
852  cv::Mat matImg_dilatation1;
853  vpImageConvert::convert(I_Klimt, matImg_dilatation1);
854 
855  double t_opencv = vpTime::measureTimeMs();
856  for (int cpt = 0; cpt < nbIterations; cpt++) {
857  cv::morphologyEx(matImg_dilatation1, matImg_dilatation1, cv::MORPH_DILATE, cross_SE);
858  }
859  t_opencv = vpTime::measureTimeMs() - t_opencv;
860 
861  vpImage<unsigned char> I_matImg_dilatation1;
862  vpImageConvert::convert(matImg_dilatation1, I_matImg_dilatation1);
863  std::cout << "(I_matImg_dilatation1 == I_Klimt_dilatation1_sse)? "
864  << (I_matImg_dilatation1 == I_Klimt_dilatation1_sse)
865  << " ; t_opencv=" << t_opencv << " ms"
866  << std::endl;
867 
868 
869  //Dilatation CONNEXITY_8 grayscale
870  cv::Mat matImg_dilatation2;
871  vpImageConvert::convert(I_Klimt, matImg_dilatation2);
872 
873  t_opencv = vpTime::measureTimeMs();
874  for (int cpt = 0; cpt < nbIterations; cpt++) {
875  cv::morphologyEx(matImg_dilatation2, matImg_dilatation2, cv::MORPH_DILATE, rect_SE);
876  }
877  t_opencv = vpTime::measureTimeMs() - t_opencv;
878 
879  vpImage<unsigned char> I_matImg_dilatation2;
880  vpImageConvert::convert(matImg_dilatation2, I_matImg_dilatation2);
881  std::cout << "(I_matImg_dilatation2 == I_Klimt_dilatation2_sse)? "
882  << (I_matImg_dilatation2 == I_Klimt_dilatation2_sse)
883  << " ; t_opencv=" << t_opencv << " ms"
884  << std::endl;
885 
886  //Erosion CONNEXITY_4 grayscale
887  cv::Mat matImg_erosion1;
888  vpImageConvert::convert(I_Klimt, matImg_erosion1);
889 
890  t_opencv = vpTime::measureTimeMs();
891  for (int cpt = 0; cpt < nbIterations; cpt++) {
892  cv::morphologyEx(matImg_erosion1, matImg_erosion1, cv::MORPH_ERODE, cross_SE);
893  }
894  t_opencv = vpTime::measureTimeMs() - t_opencv;
895 
896  vpImage<unsigned char> I_matImg_erosion1;
897  vpImageConvert::convert(matImg_erosion1, I_matImg_erosion1);
898  std::cout << "(I_matImg_erosion1 == I_Klimt_erosion1_sse)? "
899  << (I_matImg_erosion1 == I_Klimt_erosion1_sse)
900  << " ; t_opencv=" << t_opencv << " ms"
901  << std::endl;
902 
903 
904  //Erosion CONNEXITY_8 grayscale
905  cv::Mat matImg_erosion2;
906  vpImageConvert::convert(I_Klimt, matImg_erosion2);
907 
908  t_opencv = vpTime::measureTimeMs();
909  for (int cpt = 0; cpt < nbIterations; cpt++) {
910  cv::morphologyEx(matImg_erosion2, matImg_erosion2, cv::MORPH_ERODE, rect_SE);
911  }
912  t_opencv = vpTime::measureTimeMs() - t_opencv;
913 
914  vpImage<unsigned char> I_matImg_erosion2;
915  vpImageConvert::convert(matImg_erosion2, I_matImg_erosion2);
916  std::cout << "(I_matImg_erosion2 == I_Klimt_erosion2_sse)? "
917  << (I_matImg_erosion2 == I_Klimt_erosion2_sse)
918  << " ; t_opencv=" << t_opencv << " ms"
919  << std::endl;
920 
921 #endif
922 
923  } catch(vpException &e) {
924  std::cout << "\nCatch an exception: " << e << std::endl;
925  return EXIT_FAILURE;
926  }
927 
928  std::cout << "\nTest of morphology erosion / dilatation functions are OK!" << std::endl;
929  return EXIT_SUCCESS;
930 }
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, const bool useLUT=true)
Definition: vpImageTools.h:423
static int modulo(const int a, const int n)
Definition: vpMath.cpp:274
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1157
static void dilatation(vpImage< Type > &I, Type value, Type value_out, vpConnexityType connexity=CONNEXITY_4)
unsigned int getWidth() const
Definition: vpImage.h:226
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
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 erosion(vpImage< Type > &I, Type value, Type value_out, vpConnexityType connexity=CONNEXITY_4)
unsigned int getSize() const
Definition: vpImage.h:212
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1366
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
unsigned int getHeight() const
Definition: vpImage.h:175