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