Visual Servoing Platform  version 3.2.0 under development (2019-01-22)
testContours.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Test contours extraction.
33  *
34  * Authors:
35  * Souriya Trinh
36  *
37  *****************************************************************************/
38 
39 #include <iomanip>
40 
41 #include <visp3/core/vpImageTools.h>
42 #include <visp3/core/vpIoTools.h>
43 #include <visp3/imgproc/vpImgproc.h>
44 #include <visp3/io/vpImageIo.h>
45 #include <visp3/io/vpParseArgv.h>
46 
53 // List of allowed command line options
54 #define GETOPTARGS "cdi:o:h"
55 
56 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user);
57 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user);
58 
59 /*
60  Print the program options.
61 
62  \param name : Program name.
63  \param badparam : Bad parameter name.
64  \param ipath: Input image path.
65  \param opath : Output image path.
66  \param user : Username.
67  */
68 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
69 {
70  fprintf(stdout, "\n\
71 Test contours extraction.\n\
72 \n\
73 SYNOPSIS\n\
74  %s [-i <input image path>] [-o <output image path>]\n\
75  [-h]\n \
76 ", name);
77 
78  fprintf(stdout, "\n\
79 OPTIONS: Default\n\
80  -i <input image path> %s\n\
81  Set image input path.\n\
82  From this path read \"Klimt/Klimt.pgm\"\n\
83  image.\n\
84  Setting the VISP_INPUT_IMAGE_PATH environment\n\
85  variable produces the same behaviour than using\n\
86  this option.\n\
87 \n\
88  -o <output image path> %s\n\
89  Set image output path.\n\
90  From this directory, creates the \"%s\"\n\
91  subdirectory depending on the username, where \n\
92  output result images are written.\n\
93 \n\
94  -h\n\
95  Print the help.\n\n", ipath.c_str(), opath.c_str(), user.c_str());
96 
97  if (badparam)
98  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
99 }
100 
112 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, std::string user)
113 {
114  const char *optarg_;
115  int c;
116  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
117 
118  switch (c) {
119  case 'i':
120  ipath = optarg_;
121  break;
122  case 'o':
123  opath = optarg_;
124  break;
125  case 'h':
126  usage(argv[0], NULL, ipath, opath, user);
127  return false;
128  break;
129 
130  case 'c':
131  case 'd':
132  break;
133 
134  default:
135  usage(argv[0], optarg_, ipath, opath, user);
136  return false;
137  break;
138  }
139  }
140 
141  if ((c == 1) || (c == -1)) {
142  // standalone param or error
143  usage(argv[0], NULL, ipath, opath, user);
144  std::cerr << "ERROR: " << std::endl;
145  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
146  return false;
147  }
148 
149  return true;
150 }
151 
152 void printImage(const vpImage<unsigned char> &I, const std::string &name)
153 {
154  std::cout << "\n" << name << ":" << std::endl;
155 
156  std::cout << " ";
157  for (unsigned int j = 0; j < I.getWidth(); j++) {
158  std::cout << std::setfill(' ') << std::setw(2) << j << " ";
159  }
160  std::cout << std::endl;
161 
162  for (unsigned int i = 0; i < I.getHeight(); i++) {
163  std::cout << std::setfill(' ') << std::setw(2) << i << " ";
164 
165  for (unsigned int j = 0; j < I.getWidth(); j++) {
166  std::cout << std::setfill(' ') << std::setw(2) << static_cast<unsigned int>(I[i][j]) << " ";
167  }
168 
169  std::cout << std::endl;
170  }
171 }
172 
173 void displayContourInfo(const vp::vpContour &contour, const int level)
174 {
175  std::cout << "\nContour:" << std::endl;
176  std::cout << "\tlevel: " << level << std::endl;
177  std::cout << "\tcontour type: " << (contour.m_contourType == vp::CONTOUR_OUTER ? "outer contour" : "hole contour")
178  << std::endl;
179  std::cout << "\tnb children: " << contour.m_children.size() << std::endl;
180 
181  for (std::vector<vp::vpContour *>::const_iterator it = contour.m_children.begin(); it != contour.m_children.end();
182  ++it) {
183  displayContourInfo(**it, level + 1);
184  }
185 }
186 
187 int main(int argc, const char **argv)
188 {
189  try {
190  std::string env_ipath;
191  std::string opt_ipath;
192  std::string opt_opath;
193  std::string ipath;
194  std::string opath;
195  std::string filename;
196  std::string username;
197 
198  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
199  // environment variable value
200  env_ipath = vpIoTools::getViSPImagesDataPath();
201 
202  // Set the default input path
203  if (!env_ipath.empty())
204  ipath = env_ipath;
205 
206 // Set the default output path
207 #if defined(_WIN32)
208  opt_opath = "C:/temp";
209 #else
210  opt_opath = "/tmp";
211 #endif
212 
213  // Get the user login name
214  vpIoTools::getUserName(username);
215 
216  // Read the command line options
217  if (getOptions(argc, argv, opt_ipath, opt_opath, username) == false) {
218  exit(EXIT_FAILURE);
219  }
220 
221  // Get the option values
222  if (!opt_ipath.empty())
223  ipath = opt_ipath;
224  if (!opt_opath.empty())
225  opath = opt_opath;
226 
227  // Append to the output path string, the login name of the user
228  opath = vpIoTools::createFilePath(opath, username);
229 
230  // Test if the output path exist. If no try to create it
231  if (vpIoTools::checkDirectory(opath) == false) {
232  try {
233  // Create the dirname
235  } catch (...) {
236  usage(argv[0], NULL, ipath, opt_opath, username);
237  std::cerr << std::endl << "ERROR:" << std::endl;
238  std::cerr << " Cannot create " << opath << std::endl;
239  std::cerr << " Check your -o " << opt_opath << " option " << std::endl;
240  exit(EXIT_FAILURE);
241  }
242  }
243 
244  // Compare ipath and env_ipath. If they differ, we take into account
245  // the input path comming from the command line option
246  if (!opt_ipath.empty() && !env_ipath.empty()) {
247  if (ipath != env_ipath) {
248  std::cout << std::endl << "WARNING: " << std::endl;
249  std::cout << " Since -i <visp image path=" << ipath << "> "
250  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
251  << " we skip the environment variable." << std::endl;
252  }
253  }
254 
255  // Test if an input path is set
256  if (opt_ipath.empty() && env_ipath.empty()) {
257  usage(argv[0], NULL, ipath, opt_opath, username);
258  std::cerr << std::endl << "ERROR:" << std::endl;
259  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
260  << " environment variable to specify the location of the " << std::endl
261  << " image path where test images are located." << std::endl
262  << std::endl;
263  exit(EXIT_FAILURE);
264  }
265 
266  //
267  // Here starts really the test
268  //
269 
270  unsigned char image_data[14 * 10] = {
271  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,
272  1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
273  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
274  0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
275 
276  vpImage<unsigned char> I_test_data(image_data, 14, 10, true);
277  std::cout << "Test with image data:" << std::endl;
278  printImage(I_test_data, "I_test_data");
279 
280  vp::vpContour vp_contours;
281  std::vector<std::vector<vpImagePoint> > contours;
282  double t = vpTime::measureTimeMs();
283  vp::findContours(I_test_data, vp_contours, contours);
284  t = vpTime::measureTimeMs() - t;
285 
286  displayContourInfo(vp_contours, 0);
287  std::cout << "ViSP: nb contours=" << contours.size() << " ; t=" << t << " ms" << std::endl;
288 
289  // Read Klimt.ppm
290  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
292  std::cout << "Read image: " << filename << std::endl;
293  vpImageIo::read(I, filename);
294  vpImageTools::binarise(I, (unsigned char)127, (unsigned char)255, (unsigned char)0, (unsigned char)1,
295  (unsigned char)1);
296 
298  for (unsigned int cpt = 0; cpt < I2.getSize(); cpt++) {
299  I2.bitmap[cpt] = 255 * I.bitmap[cpt];
300  }
301  filename = vpIoTools::createFilePath(opath, "Klimt_contours_binarise.pgm");
302  vpImageIo::write(I2, filename);
303 
304  t = vpTime::measureTimeMs();
305  vp::findContours(I, vp_contours, contours);
306  t = vpTime::measureTimeMs() - t;
307 
308  displayContourInfo(vp_contours, 0);
309  std::cout << "\nTest with Klimt image:" << std::endl;
310  std::cout << "ViSP: nb contours=" << contours.size() << " ; t=" << t << " ms" << std::endl;
311 
312  // Draw and save
313  vpImage<unsigned char> I_draw_contours(I2.getHeight(), I2.getWidth(), 0);
314  vp::drawContours(I_draw_contours, contours);
315 
316  filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted.pgm");
317  vpImageIo::write(I_draw_contours, filename);
318 
319  vpImage<vpRGBa> I_draw_contours_color(I2.getHeight(), I2.getWidth(), vpRGBa(0, 0, 0));
320  vp::drawContours(I_draw_contours_color, contours, vpColor::red);
321 
322  filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_color.ppm");
323  vpImageIo::write(I_draw_contours_color, filename);
324 
325  // Test retrieve list
326  vp::findContours(I, vp_contours, contours, vp::CONTOUR_RETR_LIST);
327  vpImage<unsigned char> I_draw_contours_list(I2.getHeight(), I2.getWidth(), 0);
328 
329  vpImage<unsigned char> I_tmp_list(I.getHeight(), I.getWidth(), 0);
330  vp::drawContours(I_tmp_list, contours);
331 
332  contours.clear();
333  for (std::vector<vp::vpContour *>::const_iterator it = vp_contours.m_children.begin();
334  it != vp_contours.m_children.end(); ++it) {
335  contours.push_back((*it)->m_points);
336  }
337 
338  vp::drawContours(I_draw_contours_list, contours);
339  std::cout << "(I_tmp_list == I_draw_contours_list)? " << (I_tmp_list == I_draw_contours_list) << std::endl;
340 
341  filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_list.pgm");
342  vpImageIo::write(I_draw_contours_list, filename);
343 
344  // Test retrieve external
345  vp::findContours(I, vp_contours, contours, vp::CONTOUR_RETR_EXTERNAL);
346  vpImage<unsigned char> I_draw_contours_external(I2.getHeight(), I2.getWidth(), 0);
347 
348  vpImage<unsigned char> I_tmp_external(I.getHeight(), I.getWidth(), 0);
349  vp::drawContours(I_tmp_external, contours);
350 
351  contours.clear();
352  for (std::vector<vp::vpContour *>::const_iterator it = vp_contours.m_children.begin();
353  it != vp_contours.m_children.end(); ++it) {
354  contours.push_back((*it)->m_points);
355  }
356 
357  vp::drawContours(I_draw_contours_external, contours);
358  std::cout << "(I_tmp_external == I_draw_contours_external)? " << (I_tmp_external == I_draw_contours_external)
359  << std::endl;
360 
361  filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_external.pgm");
362  vpImageIo::write(I_draw_contours_external, filename);
363 
364  // Test fillHoles
365  vpImage<unsigned char> I_holes = I_draw_contours_external;
366  vpImageTools::binarise(I_holes, (unsigned char)127, (unsigned char)255, (unsigned char)0, (unsigned char)255,
367  (unsigned char)255);
368 
369  t = vpTime::measureTimeMs();
370  vp::fillHoles(I_holes);
371  t = vpTime::measureTimeMs() - t;
372  std::cout << "\nFill Holes: " << t << " ms" << std::endl;
373 
374  filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_external_fill_holes.pgm");
375  vpImageIo::write(I_holes, filename);
376 
377 #if VISP_HAVE_OPENCV_VERSION >= 0x030000
378  cv::Mat matImg;
379  vpImageConvert::convert(I, matImg);
380 
381  std::vector<std::vector<cv::Point> > contours_opencv;
382  double t_opencv = vpTime::measureTimeMs();
383  cv::findContours(matImg, contours_opencv, cv::RETR_TREE, cv::CHAIN_APPROX_NONE);
384  t_opencv = vpTime::measureTimeMs() - t_opencv;
385  std::cout << "\nOpenCV: nb contours=" << contours_opencv.size() << " ; t_opencv=" << t_opencv << " ms" << std::endl;
386 
387  vpImage<unsigned char> I_draw_contours_opencv(I.getHeight(), I.getWidth(), 0);
388  for (std::vector<std::vector<cv::Point> >::const_iterator it1 = contours_opencv.begin();
389  it1 != contours_opencv.end(); ++it1) {
390  for (std::vector<cv::Point>::const_iterator it2 = it1->begin(); it2 != it1->end(); ++it2) {
391  I_draw_contours_opencv[it2->y][it2->x] = 255;
392  }
393  }
394 
395  std::cout << "(I_draw_contours_opencv == I_drawContours)? " << (I_draw_contours_opencv == I_draw_contours)
396  << std::endl;
397 
398  filename = vpIoTools::createFilePath(opath, "Klimt_contours_extracted_opencv.pgm");
399  vpImageIo::write(I_draw_contours_opencv, filename);
400 
401  // Test retrieve list
402  vpImageConvert::convert(I, matImg);
403  contours_opencv.clear();
404  cv::findContours(matImg, contours_opencv, cv::RETR_LIST, cv::CHAIN_APPROX_NONE);
405 
406  I_draw_contours_opencv = 0;
407  for (std::vector<std::vector<cv::Point> >::const_iterator it1 = contours_opencv.begin();
408  it1 != contours_opencv.end(); ++it1) {
409  for (std::vector<cv::Point>::const_iterator it2 = it1->begin(); it2 != it1->end(); ++it2) {
410  I_draw_contours_opencv[it2->y][it2->x] = 255;
411  }
412  }
413 
414  std::cout << "(I_draw_contours_opencv == I_draw_contours_list)? "
415  << (I_draw_contours_opencv == I_draw_contours_list) << std::endl;
416 
417  // Test retrieve external
418  vpImageConvert::convert(I, matImg);
419  contours_opencv.clear();
420  cv::findContours(matImg, contours_opencv, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
421 
422  I_draw_contours_opencv = 0;
423  for (std::vector<std::vector<cv::Point> >::const_iterator it1 = contours_opencv.begin();
424  it1 != contours_opencv.end(); ++it1) {
425  for (std::vector<cv::Point>::const_iterator it2 = it1->begin(); it2 != it1->end(); ++it2) {
426  I_draw_contours_opencv[it2->y][it2->x] = 255;
427  }
428  }
429 
430  std::cout << "(I_draw_contours_opencv == I_draw_contours_external)? "
431  << (I_draw_contours_opencv == I_draw_contours_external) << std::endl;
432 #endif
433 
434  return EXIT_SUCCESS;
435  } catch (const vpException &e) {
436  std::cerr << "Catch an exception: " << e.what() << std::endl;
437  return EXIT_FAILURE;
438  }
439 }
static void binarise(vpImage< Type > &I, Type threshold1, Type threshold2, Type value1, Type value2, Type value3, const bool useLUT=true)
Definition: vpImageTools.h:430
static bool checkDirectory(const char *dirname)
Definition: vpIoTools.cpp:467
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1316
unsigned int getWidth() const
Definition: vpImage.h:239
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Type * bitmap
points toward the bitmap
Definition: vpImage.h:133
error that can be emited by ViSP classes.
Definition: vpException.h:71
std::vector< vpContour * > m_children
Definition: vpContours.h:172
VISP_EXPORT void findContours(const vpImage< unsigned char > &I_original, vpContour &contours, std::vector< std::vector< vpImagePoint > > &contourPts, const vpContourRetrievalType &retrievalMode=vp::CONTOUR_RETR_TREE)
Definition: vpContours.cpp:300
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:88
VISP_EXPORT void fillHoles(vpImage< unsigned char > &I)
Definition: vpMorph.cpp:54
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
Definition: vpRGBa.h:66
static const vpColor red
Definition: vpColor.h:180
static void write(const vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:375
static void makeDirectory(const char *dirname)
Definition: vpIoTools.cpp:597
const char * what() const
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1541
vpContourType m_contourType
Definition: vpContours.h:173
VISP_EXPORT void drawContours(vpImage< unsigned char > &I, const std::vector< std::vector< vpImagePoint > > &contours, unsigned char grayValue=255)
Definition: vpContours.cpp:250
static std::string getUserName()
Definition: vpIoTools.cpp:298
static void read(vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:207
unsigned int getHeight() const
Definition: vpImage.h:178