Visual Servoing Platform  version 3.6.1 under development (2024-03-28)
testImageFilter.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 some functions from vpImageFilter class.
33  *
34 *****************************************************************************/
41 #include <iostream>
42 #include <visp3/core/vpImageConvert.h>
43 #include <visp3/core/vpImageFilter.h>
44 #include <visp3/core/vpIoTools.h>
45 #include <visp3/core/vpRGBa.h>
46 #include <visp3/io/vpImageIo.h>
47 #include <visp3/io/vpParseArgv.h>
48 
49 // List of allowed command line options
50 #define GETOPTARGS "cdi:p:h"
51 
52 namespace
53 {
54 /*
55  Print the program options.
56 
57  \param name : Program name.
58  \param badparam : Bad parameter name.
59  \param ipath: Input image path.
60  */
61 void usage(const char *name, const char *badparam, std::string ipath)
62 {
63  fprintf(stdout, "\n\
64  Test vpImageFilter class.\n\
65  \n\
66  SYNOPSIS\n\
67  %s [-i <input image path>] [-p <personal image path>]\n\
68  [-h]\n \
69  ",
70  name);
71 
72  fprintf(stdout, "\n\
73  OPTIONS: Default\n\
74  -i <input image path> %s\n\
75  Set image input path.\n\
76  From this path read \"Klimt/Klimt.pgm,\n\
77  .ppm, .jpeg and .png images.\n\
78  Setting the VISP_INPUT_IMAGE_PATH environment\n\
79  variable produces the same behaviour than using\n\
80  this option.\n\
81  \n\
82  -p <personal image path> \n\
83  Path to an image used to test image reading function.\n\
84  Example: -p /my_path_to/image.png\n\
85  \n\
86  -h\n\
87  Print the help.\n\n",
88  ipath.c_str());
89 
90  if (badparam)
91  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
92 }
93 
103 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &ppath)
104 {
105  const char *optarg_;
106  int c;
107  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
108 
109  switch (c) {
110  case 'i':
111  ipath = optarg_;
112  break;
113  case 'p':
114  ppath = optarg_;
115  break;
116  case 'h':
117  usage(argv[0], nullptr, ipath);
118  return false;
119  break;
120 
121  case 'c':
122  case 'd':
123  break;
124 
125  default:
126  usage(argv[0], optarg_, ipath);
127  return false;
128  break;
129  }
130  }
131 
132  if ((c == 1) || (c == -1)) {
133  // standalone param or error
134  usage(argv[0], nullptr, ipath);
135  std::cerr << "ERROR: " << std::endl;
136  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
137  return false;
138  }
139 
140  return true;
141 }
142 
143 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
144 bool check_results(const cv::Mat &mat, const vpImage<double> &I, unsigned int half_size_y, unsigned int half_size_x)
145 {
146  for (unsigned int i = half_size_y; i < I.getHeight() - half_size_y; i++) {
147  for (unsigned int j = half_size_x; j < I.getWidth() - half_size_x; j++) {
148  if (!vpMath::equal(mat.at<double>(static_cast<int>(i), static_cast<int>(j)), I[i][j],
149  std::numeric_limits<double>::epsilon())) {
150  return false;
151  }
152  }
153  }
154 
155  return true;
156 }
157 
158 bool check_results(const cv::Mat &mat, const vpImage<double> &I, unsigned int margin, double threshold)
159 {
160  for (unsigned int i = margin; i < I.getHeight() - margin; i++) {
161  for (unsigned int j = margin; j < I.getWidth() - margin; j++) {
162  if (!vpMath::equal(mat.at<unsigned char>(static_cast<int>(i), static_cast<int>(j)), I[i][j], threshold)) {
163  return false;
164  }
165  }
166  }
167 
168  return true;
169 }
170 
171 bool check_results(const cv::Mat &mat, const vpImage<vpRGBa> &I, unsigned int margin, double threshold)
172 {
173  for (unsigned int i = margin; i < I.getHeight() - margin; i++) {
174  for (unsigned int j = margin; j < I.getWidth() - margin; j++) {
175  if (!vpMath::equal(static_cast<double>(mat.at<cv::Vec3b>(static_cast<int>(i), static_cast<int>(j))[2]), I[i][j].R,
176  threshold)) {
177  return false;
178  }
179  if (!vpMath::equal(static_cast<double>(mat.at<cv::Vec3b>(static_cast<int>(i), static_cast<int>(j))[1]), I[i][j].G,
180  threshold)) {
181  return false;
182  }
183  if (!vpMath::equal(static_cast<double>(mat.at<cv::Vec3b>(static_cast<int>(i), static_cast<int>(j))[0]), I[i][j].B,
184  threshold)) {
185  return false;
186  }
187  }
188  }
189 
190  return true;
191 }
192 #endif
193 } // namespace
194 
195 int main(int argc, const char *argv[])
196 {
197  try {
198  std::string env_ipath;
199  std::string opt_ipath;
200  std::string opt_ppath;
201  std::string ipath;
202  std::string filename;
203 
204  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
205  // environment variable value
206  env_ipath = vpIoTools::getViSPImagesDataPath();
207 
208  // Set the default input path
209  if (!env_ipath.empty())
210  ipath = env_ipath;
211 
212  // Read the command line options
213  if (getOptions(argc, argv, opt_ipath, opt_ppath) == false) {
214  exit(EXIT_FAILURE);
215  }
216 
217  // Get the option values
218  if (!opt_ipath.empty())
219  ipath = opt_ipath;
220 
221  // Compare ipath and env_ipath. If they differ, we take into account
222  // the input path coming from the command line option
223  if (!opt_ipath.empty() && !env_ipath.empty()) {
224  if (ipath != env_ipath) {
225  std::cout << std::endl << "WARNING: " << std::endl;
226  std::cout << " Since -i <visp image path=" << ipath << "> "
227  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
228  << " we skip the environment variable." << std::endl;
229  }
230  }
231 
232  //
233  // Here starts really the test
234  //
235  vpMatrix kernel_1(2, 2);
236  for (unsigned int i = 0, cpt = 1; i < kernel_1.getRows(); i++) {
237  for (unsigned int j = 0; j < kernel_1.getCols(); j++, cpt++) {
238  kernel_1[i][j] = cpt;
239  }
240  }
241  std::cout << "kernel_1:\n" << kernel_1 << std::endl;
242 
243  vpMatrix kernel_2(3, 3);
244  for (unsigned int i = 0, cpt = 1; i < kernel_2.getRows(); i++) {
245  for (unsigned int j = 0; j < kernel_2.getCols(); j++, cpt++) {
246  kernel_2[i][j] = cpt;
247  }
248  }
249  std::cout << "kernel_2:\n" << kernel_2 << std::endl;
250 
251  vpMatrix kernel_3(2, 3);
252  for (unsigned int i = 0, cpt = 1; i < kernel_3.getRows(); i++) {
253  for (unsigned int j = 0; j < kernel_3.getCols(); j++, cpt++) {
254  kernel_3[i][j] = cpt;
255  }
256  }
257  std::cout << "kernel_3:\n" << kernel_3 << std::endl;
258 
259  {
260  // Test on small images first
261  vpImage<unsigned char> I(6, 6);
262  for (unsigned int i = 0; i < I.getSize(); i++) {
263  I.bitmap[i] = (unsigned char)i;
264  }
265  std::cout << "I:\n" << I << std::endl;
266 
267  // Test correlation
268  vpImage<double> I_correlation_1, I_correlation_2, I_correlation_3;
269  vpImageFilter::filter(I, I_correlation_1, kernel_1);
270  vpImageFilter::filter(I, I_correlation_2, kernel_2);
271  vpImageFilter::filter(I, I_correlation_3, kernel_3);
272 
273  std::cout << "\nI_correlation_1:\n" << I_correlation_1 << std::endl;
274  std::cout << "I_correlation_2:\n" << I_correlation_2 << std::endl;
275  std::cout << "I_correlation_3:\n" << I_correlation_3 << std::endl;
276 
277 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
278  cv::Mat matImg;
279  vpImageConvert::convert(I, matImg);
280 
281  cv::Mat mat_kernel_1(2, 2, CV_64F);
282  for (int i = 0, cpt = 1; i < mat_kernel_1.rows; i++) {
283  for (int j = 0; j < mat_kernel_1.cols; j++, cpt++) {
284  mat_kernel_1.at<double>(i, j) = cpt;
285  }
286  }
287 
288  cv::Mat mat_kernel_2(3, 3, CV_64F);
289  for (int i = 0, cpt = 1; i < mat_kernel_2.rows; i++) {
290  for (int j = 0; j < mat_kernel_2.cols; j++, cpt++) {
291  mat_kernel_2.at<double>(i, j) = cpt;
292  }
293  }
294 
295  cv::Mat mat_kernel_3(2, 3, CV_64F);
296  for (int i = 0, cpt = 1; i < mat_kernel_3.rows; i++) {
297  for (int j = 0; j < mat_kernel_3.cols; j++, cpt++) {
298  mat_kernel_3.at<double>(i, j) = cpt;
299  }
300  }
301 
302  cv::Mat matImg_correlation_1, matImg_correlation_2, matImg_correlation_3;
303  cv::filter2D(matImg, matImg_correlation_1, CV_64F, mat_kernel_1);
304  cv::filter2D(matImg, matImg_correlation_2, CV_64F, mat_kernel_2);
305  cv::filter2D(matImg, matImg_correlation_3, CV_64F, mat_kernel_3);
306 
307  std::cout << "\nTest correlation on small image:" << std::endl;
308  std::cout << "(I_correlation_1 == matImg_correlation_1)? "
309  << check_results(matImg_correlation_1, I_correlation_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2)
310  << std::endl;
311  std::cout << "(I_correlation_2 == matImg_correlation_2)? "
312  << check_results(matImg_correlation_2, I_correlation_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2)
313  << std::endl;
314  std::cout << "(I_correlation_3 == matImg_correlation_3)? "
315  << check_results(matImg_correlation_3, I_correlation_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2)
316  << std::endl;
317 #endif
318 
319  // Test convolution
320  vpImage<double> I_convolution_1, I_convolution_2, I_convolution_3;
321  vpImageFilter::filter(I, I_convolution_1, kernel_1, true);
322  vpImageFilter::filter(I, I_convolution_2, kernel_2, true);
323  vpImageFilter::filter(I, I_convolution_3, kernel_3, true);
324 
325  std::cout << "\nI_convolution_1:\n" << I_convolution_1 << std::endl;
326  std::cout << "I_convolution_2:\n" << I_convolution_2 << std::endl;
327  std::cout << "I_convolution_3:\n" << I_convolution_3 << std::endl;
328 
329 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
330  cv::Mat mat_kernel_1_flip, mat_kernel_2_flip, mat_kernel_3_flip;
331  cv::flip(mat_kernel_1, mat_kernel_1_flip, -1);
332  cv::flip(mat_kernel_2, mat_kernel_2_flip, -1);
333  cv::flip(mat_kernel_3, mat_kernel_3_flip, -1);
334 
335  cv::Mat matImg_convolution_1, matImg_convolution_2, matImg_convolution_3;
336 
337  cv::Point anchor1(mat_kernel_1_flip.cols - mat_kernel_1_flip.cols / 2 - 1,
338  mat_kernel_1_flip.rows - mat_kernel_1_flip.rows / 2 - 1);
339  cv::filter2D(matImg, matImg_convolution_1, CV_64F, mat_kernel_1_flip, anchor1);
340 
341  cv::Point anchor2(mat_kernel_2_flip.cols - mat_kernel_2_flip.cols / 2 - 1,
342  mat_kernel_2_flip.rows - mat_kernel_2_flip.rows / 2 - 1);
343  cv::filter2D(matImg, matImg_convolution_2, CV_64F, mat_kernel_2_flip, anchor2);
344 
345  cv::Point anchor3(mat_kernel_3_flip.cols - mat_kernel_3_flip.cols / 2 - 1,
346  mat_kernel_3_flip.rows - mat_kernel_3_flip.rows / 2 - 1);
347  cv::filter2D(matImg, matImg_convolution_3, CV_64F, mat_kernel_3_flip, anchor3);
348 
349  std::cout << "\nTest convolution on small image:" << std::endl;
350  std::cout << "(I_convolution_1 == matImg_convolution_1)? "
351  << check_results(matImg_convolution_1, I_convolution_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2)
352  << std::endl;
353  std::cout << "(I_convolution_2 == matImg_convolution_2)? "
354  << check_results(matImg_convolution_2, I_convolution_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2)
355  << std::endl;
356  std::cout << "(I_convolution_3 == matImg_convolution_3)? "
357  << check_results(matImg_convolution_3, I_convolution_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2)
358  << std::endl;
359 #endif
360  if (opt_ppath.empty()) {
361  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
362  vpImageIo::read(I, filename);
363  }
364  else {
365  filename = opt_ppath;
366  vpImageIo::read(I, filename);
367  printf("Image \"%s\" read successfully\n", filename.c_str());
368  }
369 
370  // Test correlation
371  double t = vpTime::measureTimeMs();
372  vpImageFilter::filter(I, I_correlation_1, kernel_1);
373  vpImageFilter::filter(I, I_correlation_2, kernel_2);
374  vpImageFilter::filter(I, I_correlation_3, kernel_3);
375  t = vpTime::measureTimeMs() - t;
376  std::cout << "\nTime to do 3 correlation filtering: " << t << " ms ; Mean: " << t / 3.0 << " ms" << std::endl;
377 
378 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
379  vpImageConvert::convert(I, matImg);
380 
381  t = vpTime::measureTimeMs();
382  cv::filter2D(matImg, matImg_correlation_1, CV_64F, mat_kernel_1);
383  cv::filter2D(matImg, matImg_correlation_2, CV_64F, mat_kernel_2);
384  cv::filter2D(matImg, matImg_correlation_3, CV_64F, mat_kernel_3);
385  t = vpTime::measureTimeMs() - t;
386  std::cout << "Time to do 3 cv::filter2D: " << t << " ms ; Mean: " << t / 3.0 << " ms" << std::endl;
387 
388  std::cout << "\nTest correlation on Klimt image:" << std::endl;
389  bool test = check_results(matImg_correlation_1, I_correlation_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2);
390  std::cout << "(I_correlation_1 == matImg_correlation_1)? " << test << std::endl;
391  if (!test) {
392  std::cerr << "Failed test1 correlation with vpImageFilter::filter()!" << std::endl;
393  return EXIT_FAILURE;
394  }
395 
396  test = check_results(matImg_correlation_2, I_correlation_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2);
397  std::cout << "(I_correlation_2 == matImg_correlation_2)? " << test << std::endl;
398  if (!test) {
399  std::cerr << "Failed test2 correlation with vpImageFilter::filter()!" << std::endl;
400  return EXIT_FAILURE;
401  }
402 
403  test = check_results(matImg_correlation_3, I_correlation_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2);
404  std::cout << "(I_correlation_3 == matImg_correlation_3)? " << test << std::endl;
405  if (!test) {
406  std::cerr << "Failed test3 correlation with vpImageFilter::filter()!" << std::endl;
407  return EXIT_FAILURE;
408  }
409 #endif
410 
411  // Test convolution
412  t = vpTime::measureTimeMs();
413  vpImageFilter::filter(I, I_convolution_1, kernel_1, true);
414  vpImageFilter::filter(I, I_convolution_2, kernel_2, true);
415  vpImageFilter::filter(I, I_convolution_3, kernel_3, true);
416  t = vpTime::measureTimeMs() - t;
417  std::cout << "\nTime to do 3 convolution filtering: " << t << " ms ; Mean: " << t / 3.0 << " ms" << std::endl;
418 
419 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
420 
421  t = vpTime::measureTimeMs();
422  cv::filter2D(matImg, matImg_convolution_1, CV_64F, mat_kernel_1_flip, anchor1);
423  cv::filter2D(matImg, matImg_convolution_2, CV_64F, mat_kernel_2_flip, anchor2);
424  cv::filter2D(matImg, matImg_convolution_3, CV_64F, mat_kernel_3_flip, anchor3);
425  t = vpTime::measureTimeMs() - t;
426  std::cout << "Time to do 3 cv::filter2D: " << t << " ms ; Mean: " << t / 3.0 << " ms" << std::endl;
427 
428  std::cout << "\nTest convolution on Klimt image:" << std::endl;
429  test = check_results(matImg_convolution_1, I_convolution_1, kernel_1.getRows() / 2, kernel_1.getCols() / 2);
430  std::cout << "(I_convolution_1 == matImg_convolution_1)? " << test << std::endl;
431  if (!test) {
432  std::cerr << "Failed test1 convolution with vpImageFilter::filter()!" << std::endl;
433  return EXIT_FAILURE;
434  }
435 
436  test = check_results(matImg_convolution_2, I_convolution_2, kernel_2.getRows() / 2, kernel_2.getCols() / 2);
437  std::cout << "(I_convolution_2 == matImg_convolution_2)? " << test << std::endl;
438  if (!test) {
439  std::cerr << "Failed test2 convolution with vpImageFilter::filter()!" << std::endl;
440  return EXIT_FAILURE;
441  }
442 
443  test = check_results(matImg_convolution_3, I_convolution_3, kernel_3.getRows() / 2, kernel_3.getCols() / 2);
444  std::cout << "(I_convolution_3 == matImg_convolution_3)? " << test << std::endl;
445  if (!test) {
446  std::cerr << "Failed test3 convolution with vpImageFilter::filter()!" << std::endl;
447  return EXIT_FAILURE;
448  }
449 #endif
450 
451  // Test Sobel
452  vpMatrix kernel_sobel_x_flip(5, 5);
453  vpImageFilter::getSobelKernelX(kernel_sobel_x_flip.data, 2);
454  vpMatrix kernel_sobel_x(5, 5);
455  for (unsigned int i = 0; i < kernel_sobel_x.getRows(); i++) {
456  for (unsigned int j = 0; j < kernel_sobel_x.getCols(); j++) {
457  kernel_sobel_x[i][j] = kernel_sobel_x_flip[i][kernel_sobel_x.getCols() - 1 - j];
458  }
459  }
460 
461  vpImage<double> I_sobel_x;
462  t = vpTime::measureTimeMs();
463  vpImageFilter::filter(I, I_sobel_x, kernel_sobel_x, true);
464  t = vpTime::measureTimeMs() - t;
465  std::cout << "\nTime to do Sobel: " << t << " ms" << std::endl;
466 
467 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
468  cv::Mat matImg_sobel_x;
469  t = vpTime::measureTimeMs();
470  cv::Sobel(matImg, matImg_sobel_x, CV_64F, 1, 0, 5);
471  t = vpTime::measureTimeMs() - t;
472  std::cout << "Time to do cv::Sobel: " << t << " ms" << std::endl;
473 
474  std::cout << "\nTest Sobel on Klimt image:" << std::endl;
475  std::cout << "(I_sobel_x == matImg_sobel_x)? "
476  << check_results(matImg_sobel_x, I_sobel_x, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
477  << std::endl;
478 #endif
479 
480  vpImage<double> I_double, Iu, Iv;
481  vpImageConvert::convert(I, I_double);
482  t = vpTime::measureTimeMs();
483  vpImageFilter::filter(I_double, Iu, Iv, kernel_sobel_x, true);
484  t = vpTime::measureTimeMs() - t;
485  std::cout << "\nTime to do Sobel Iu and Iv: " << t << " ms" << std::endl;
486 
487 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
488  cv::Mat matImg_sobel_y;
489  cv::Sobel(matImg, matImg_sobel_y, CV_64F, 0, 1, 5);
490 
491  std::cout << "(Iu == matImg_sobel_x)? "
492  << check_results(matImg_sobel_x, Iu, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
493  << std::endl;
494  std::cout << "(Iv == matImg_sobel_y)? "
495  << check_results(matImg_sobel_y, Iv, kernel_sobel_x.getRows() / 2, kernel_sobel_x.getCols() / 2)
496  << std::endl;
497 #endif
498 
499  // Test Sobel separable filters
500  vpImage<double> I_sep_filtered;
501  vpColVector kernel_sep_x(5);
502  kernel_sep_x[0] = 1.0;
503  kernel_sep_x[1] = 2.0;
504  kernel_sep_x[2] = 0.0;
505  kernel_sep_x[3] = -2.0;
506  kernel_sep_x[4] = -1.0;
507  vpColVector kernel_sep_y(5);
508  kernel_sep_y[0] = 1.0;
509  kernel_sep_y[1] = 4.0;
510  kernel_sep_y[2] = 6.0;
511  kernel_sep_y[3] = 4.0;
512  kernel_sep_y[4] = 1.0;
513 
514  t = vpTime::measureTimeMs();
515  vpImageFilter::sepFilter(I, I_sep_filtered, kernel_sep_x, kernel_sep_y);
516  t = vpTime::measureTimeMs() - t;
517  std::cout << "\nTime to do sepFilter: " << t << " ms" << std::endl;
518 
519 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
520  test = check_results(matImg_sobel_x, Iu, I_sep_filtered.getRows() / 2, kernel_sobel_x.getCols() / 2);
521  std::cout << "(I_sep_filtered == matImg_sobel_x)? " << test << std::endl;
522 
523  if (!test) {
524  std::cerr << "Failed separable filter!" << std::endl;
525  return EXIT_FAILURE;
526  }
527 
528  // Test median filter on gray-scale image
529  std::cout << "\nTest median on grayscale image:" << std::endl;
530  vpImage<unsigned char> I_median(3, 3);
531  for (unsigned int r = 0; r < 3; r++) {
532  for (unsigned int c = 0; c < 3; c++) {
533  I_median[r][c] = r * 3 + c;
534  }
535  }
536  double median = vpImageFilter::median(I_median);
537  double expectedMedian = 4.;
538  test = (median == expectedMedian);
539  std::cout << "(median (=" << median << ") == expectedMedian(" << expectedMedian << "))? " << test << std::endl;
540 
541  if (!test) {
542  std::cerr << "Failed median filter on gray-scale image!" << std::endl;
543  return EXIT_FAILURE;
544  }
545 
546  std::cout << "\nTest median on vpRGBa image:" << std::endl;
547  vpImage<vpRGBa> I_median_rgba(3, 3);
548  for (unsigned int r = 0; r < 3; r++) {
549  for (unsigned int c = 0; c < 3; c++) {
550  I_median_rgba[r][c].R = r * 3 + c;
551  I_median_rgba[r][c].G = 2 * (r * 3 + c);
552  I_median_rgba[r][c].B = 3 * (r * 3 + c);
553  }
554  }
555  std::vector<float> median_rgba = vpImageFilter::median(I_median_rgba);
556  std::vector<float> expected_median_rgba = { 4.f, 8.f, 12.f };
557  for (unsigned int i = 0; i < 3; i++) {
558  bool test_local = (median_rgba[i] == expected_median_rgba[i]);
559  test &= test_local;
560  std::cout << "(median_rgba[" << i << "] (=" << median_rgba[i] << ") == expected_median_rgba[" << i << "] ( " << expected_median_rgba[i] << "))? " << test_local << std::endl;
561  }
562  if (!test) {
563  std::cerr << "Failed median filter on vpRGBa image!" << std::endl;
564  return EXIT_FAILURE;
565  }
566 #endif
567  }
568  {
569  // Test Gaussian blur on grayscale image
570 
571  std::cout << "\nTest Gaussian Blur on Klimt grayscale image:" << std::endl;
573  vpImage<double> I_blur;
574  // Test on real image
575 
576  if (opt_ppath.empty()) {
577  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
578  vpImageIo::read(I, filename);
579  }
580  else {
581  filename = opt_ppath;
582  vpImageIo::read(I, filename);
583  printf("Image \"%s\" read successfully\n", filename.c_str());
584  }
585 
586  unsigned int gaussian_filter_size = 7;
587  double sigma = 3;
588  double t = vpTime::measureTimeMs();
589  vpImageFilter::gaussianBlur(I, I_blur, gaussian_filter_size, sigma);
590  t = vpTime::measureTimeMs() - t;
591  std::cout << "Time to do ViSP Gaussian Blur on grayscale images: " << t << " ms" << std::endl;
592 
593 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
594  cv::Mat matImg, matImg_blur;
595  vpImageConvert::convert(I, matImg);
596  t = vpTime::measureTimeMs();
597  cv::GaussianBlur(matImg, matImg_blur, cv::Size(gaussian_filter_size, gaussian_filter_size), sigma, 0);
598  t = vpTime::measureTimeMs() - t;
599  std::cout << "Time to do OpenCV Gaussian Blur on grayscale images: " << t << " ms" << std::endl;
600 
601  double threshold = 3.;
602  unsigned int margin = 3;
603  bool test = check_results(matImg_blur, I_blur, margin, threshold);
604  std::cout << "(I_blur == matImg_blur)? " << test << std::endl;
605 
606  if (!test) {
607  std::cerr << "Failed Gaussian blur filter on grayscale image!" << std::endl;
608  return EXIT_FAILURE;
609  }
610 #endif
611  }
612 
613  {
614  // Test Gaussian blur on color image
615  std::cout << "\nTest Gaussian Blur on Klimt color image:" << std::endl;
616 
617  vpImage<vpRGBa> I_rgb, I_rgb_blur;
618  // Test on real image
619 
620  if (opt_ppath.empty()) {
621  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.ppm");
622  vpImageIo::read(I_rgb, filename);
623  }
624  else {
625  filename = opt_ppath;
626  vpImageIo::read(I_rgb, filename);
627  printf("Image \"%s\" read successfully\n", filename.c_str());
628  }
629 
630  unsigned int gaussian_filter_size = 7;
631  double sigma = 3;
632  double t = vpTime::measureTimeMs();
633  vpImageFilter::gaussianBlur(I_rgb, I_rgb_blur, gaussian_filter_size, sigma);
634  t = vpTime::measureTimeMs() - t;
635  std::cout << "Time to do ViSP Gaussian Blur on color images: " << t << " ms" << std::endl;
636 
637 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC)
638  cv::Mat matImg_rgb, matImg_rgb_blur;
639  vpImageConvert::convert(I_rgb, matImg_rgb);
640  t = vpTime::measureTimeMs();
641  cv::GaussianBlur(matImg_rgb, matImg_rgb_blur, cv::Size(gaussian_filter_size, gaussian_filter_size), sigma, 0);
642  t = vpTime::measureTimeMs() - t;
643  std::cout << "Time to do OpenCV Gaussian Blur on color images: " << t << " ms" << std::endl;
644 
645  double threshold = 3.;
646  unsigned int margin = 3;
647  bool test = check_results(matImg_rgb_blur, I_rgb_blur, margin, threshold);
648  std::cout << "(I_rgb_blur == matImg_rgb_blur)? " << test << std::endl;
649 
650  if (!test) {
651  std::cerr << "Failed Gaussian blur filter on color image!" << std::endl;
652  return EXIT_FAILURE;
653  }
654 #endif
655  }
656 
657  }
658  catch (const vpException &e) {
659  std::cerr << "Catch an exception: " << e.what() << std::endl;
660  return EXIT_FAILURE;
661  }
662 
663  std::cout << "\ntestImageFilter is ok." << std::endl;
664  return EXIT_SUCCESS;
665 }
Implementation of column vector and the associated operations.
Definition: vpColVector.h:163
error that can be emitted by ViSP classes.
Definition: vpException.h:59
const char * what() const
Definition: vpException.cpp:70
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static FilterType getSobelKernelX(FilterType *filter, unsigned int size)
static void sepFilter(const vpImage< unsigned char > &I, vpImage< double > &If, const vpColVector &kernelH, const vpColVector &kernelV)
static void gaussianBlur(const vpImage< ImageType > &I, vpImage< FilterType > &GI, unsigned int size=7, FilterType sigma=0., bool normalize=true, const vpImage< bool > *p_mask=nullptr)
static void filter(const vpImage< ImageType > &I, vpImage< FilterType > &If, const vpArray2D< FilterType > &M, bool convolve=false, const vpImage< bool > *p_mask=nullptr)
static float median(const cv::Mat &cv_I)
Calculates the median value of a single channel. The algorithm is based on based on https://github....
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:143
unsigned int getWidth() const
Definition: vpImage.h:245
unsigned int getSize() const
Definition: vpImage.h:224
Type * bitmap
points toward the bitmap
Definition: vpImage.h:139
unsigned int getHeight() const
Definition: vpImage.h:184
unsigned int getRows() const
Definition: vpImage.h:215
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1781
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:2142
static bool equal(double x, double y, double threshold=0.001)
Definition: vpMath.h:449
Implementation of a matrix and operations on matrices.
Definition: vpMatrix.h:146
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
VISP_EXPORT double measureTimeMs()