ViSP  3.0.0
fernClassifier.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ViSP software.
4  * Copyright (C) 2005 - 2015 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  * Detection of points of interests and matching using the Ferns classifier.
32  *
33  * Authors:
34  * Romain Tallonneau
35  *
36  *****************************************************************************/
49 #include <visp3/core/vpConfig.h>
50 #include <visp3/core/vpDebug.h>
51 
52 #if ((defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)) && (VISP_HAVE_OPENCV_VERSION >= 0x020000) && (VISP_HAVE_OPENCV_VERSION < 0x030000))
53 
54 #include <iostream>
55 #include <stdlib.h>
56 #include <visp3/vision/vpFernClassifier.h>
57 #include <visp3/io/vpParseArgv.h>
58 #include <visp3/core/vpConfig.h>
59 #include <visp3/core/vpImage.h>
60 #include <visp3/gui/vpDisplayX.h>
61 #include <visp3/gui/vpDisplayGTK.h>
62 #include <visp3/gui/vpDisplayGDI.h>
63 #include <visp3/vision/vpHomography.h>
64 #include <visp3/io/vpImageIo.h>
65 #include <visp3/core/vpIoTools.h>
66 #include <visp3/core/vpTime.h>
67 #include <iomanip>
68 
69 #define GETOPTARGS "hlcdb:i:p"
70 
71 void usage(const char *name, const char *badparam);
72 bool getOptions(int argc, const char **argv, bool &isLearning, std::string& dataFile, bool& click_allowed,
73  bool& display, bool& displayPoints, std::string& ipath);
74 
83 void usage(const char *name, const char *badparam)
84 {
85  fprintf(stdout, "\n\
86 Detection of points of interests and matching using the Ferns classifier. The \
87 object needs first to be learned (-l option). This learning process will create\
88 a file used to detect the object.\n\
89 \n\
90 SYNOPSIS\n\
91  %s [-l] [-h] [-b] [-c] [-d] [-p] [-i]\n", name);
92 
93  fprintf(stdout, "\n\
94 OPTIONS: \n\
95  -l\n\
96  learn an object.\n\
97 \n\
98  -i <input image path> \n\
99  Set image input path.\n\
100  From this path read \"ViSP-images/line/image.%%04d.pgm\"\n\
101  images. \n\
102  Setting the VISP_INPUT_IMAGE_PATH environment\n\
103  variable produces the same behaviour than using\n\
104  this option.\n\
105 \n\
106  -b\n\
107  database filename to use (default is ./dataFern).\n\
108 \n\
109  -c\n\
110  Disable the mouse click. Useful to automaze the \n\
111  execution of this program without humain intervention.\n\
112 \n\
113  -d \n\
114  Turn off the display.\n\
115 \n\
116  -p \n\
117  display points of interest.\n\
118 \n\
119  -h\n\
120  Print this help.\n");
121 
122  if (badparam)
123  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
124 
125 }
126 
143 bool getOptions(int argc, const char **argv, bool &isLearning, std::string& dataFile, bool& click_allowed,
144  bool& display, bool& displayPoints, std::string& ipath)
145 {
146  const char *optarg_;
147  int c;
148  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
149 
150  switch (c) {
151  case 'c': click_allowed = false; break;
152  case 'd': display = false; break;
153  case 'l': isLearning = true; break;
154  case 'h': usage(argv[0], NULL); return false; break;
155  case 'b': dataFile = optarg_; break;
156  case 'p': displayPoints = true; break;
157  case 'i': ipath = optarg_; break;
158  default:
159  usage(argv[0], optarg_);
160  return false; break;
161  }
162  }
163 
164  if ((c == 1) || (c == -1)) {
165  // standalone param or error
166  usage(argv[0], NULL);
167  std::cerr << "ERROR: " << std::endl;
168  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
169  return false;
170  }
171 
172  return true;
173 }
174 
175 
176 
177 int
178 main(int argc, const char** argv)
179 {
180  try {
181  bool isLearning = false;
182  std::string dataFile("./dataFern");
183  bool opt_click_allowed = true;
184  bool opt_display = true;
185  std::string objectName("object");
186  bool displayPoints = false;
187  std::string opt_ipath;
188  std::string ipath;
189  std::string env_ipath;
190  std::string dirname;
191  std::string filename;
192 
193  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH environment variable value
194  env_ipath = vpIoTools::getViSPImagesDataPath();
195 
196  // Set the default input path
197  if (! env_ipath.empty()){
198  ipath = env_ipath;
199  }
200 
201  // Read the command line options
202  if (getOptions(argc, argv,
203  isLearning, dataFile, opt_click_allowed, opt_display, displayPoints, opt_ipath) == false) {
204  exit (-1);
205  }
206 
207  // Get the option values
208  if (!opt_ipath.empty()){
209  ipath = opt_ipath;
210  }
211 
212  // Compare ipath and env_ipath. If they differ, we take into account
213  // the input path comming from the command line option
214  if (!opt_ipath.empty() && !env_ipath.empty()) {
215  if (ipath != env_ipath) {
216  std::cout << std::endl
217  << "WARNING: " << std::endl;
218  std::cout << " Since -i <visp image path=" << ipath << "> "
219  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
220  << " we skip the environment variable." << std::endl;
221  }
222  }
223 
224  // Test if an input path is set
225  if (opt_ipath.empty() && env_ipath.empty()){
226  usage(argv[0], NULL);
227  std::cerr << std::endl
228  << "ERROR:" << std::endl;
229  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
230  << std::endl
231  << " environment variable to specify the location of the " << std::endl
232  << " image path where test images are located." << std::endl << std::endl;
233  exit(-1);
234  }
235 
236 
237  // Declare two images, these are gray level images (unsigned char)
240 
241 
242  // Set the path location of the image sequence
243  dirname = vpIoTools::createFilePath(ipath, "ViSP-images/cube");
244 
245  // Build the name of the image file
246  unsigned iter = 0; // Image number
247  std::ostringstream s;
248  s.setf(std::ios::right, std::ios::adjustfield);
249  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
250  filename = vpIoTools::createFilePath(dirname, s.str());
251 
252  // Read the PGM image named "filename" on the disk, and put the
253  // bitmap into the image structure I. I is initialized to the
254  // correct size
255  //
256  // exception readPGM may throw various exception if, for example,
257  // the file does not exist, or if the memory cannot be allocated
258  try{
259  std::cout << "Load: " << filename << std::endl;
260  vpImageIo::read(Iref, filename) ;
261  I = Iref;
262  }
263  catch(...)
264  {
265  // an exception is throwned if an exception from readPGM has been catched
266  // here this will result in the end of the program
267  // Note that another error message has been printed from readPGM
268  // to give more information about the error
269  std::cerr << std::endl
270  << "ERROR:" << std::endl;
271  std::cerr << " Cannot read " << filename << std::endl;
272  std::cerr << " Check your -i " << ipath << " option " << std::endl
273  << " or VISP_INPUT_IMAGE_PATH environment variable."
274  << std::endl;
275  exit(-1);
276  }
277 
278 #if defined VISP_HAVE_X11
279  vpDisplayX display;
280 #elif defined VISP_HAVE_GTK
281  vpDisplayGTK display;
282 #elif defined VISP_HAVE_GDI
283  vpDisplayGDI display;
284 #endif
285 
286 #if defined VISP_HAVE_X11
287  vpDisplayX displayRef;
288 #elif defined VISP_HAVE_GTK
289  vpDisplayGTK displayRef;
290 #elif defined VISP_HAVE_GDI
291  vpDisplayGDI displayRef;
292 #endif
293 
294  // declare a planar object detector
295  vpFernClassifier fern;
296 
297  if(isLearning){
298  if(opt_display){
299  displayRef.init(Iref, 100, 100, "Reference image") ;
300  vpDisplay::display(Iref);
301  vpDisplay::flush(Iref);
302  }
303  vpImagePoint corners[2];
304  if (opt_display && opt_click_allowed){
305  std::cout << "Click on the top left and the bottom right corners to define the reference plane" << std::endl;
306  for (int i=0 ; i < 2 ; i++){
307  vpDisplay::getClick(Iref, corners[i]);
308  std::cout << corners[i] << std::endl;
309  }
310  }
311  else{
312  corners[0].set_ij(1,1);
313  corners[1].set_ij(I.getHeight()-2,I.getWidth()-2);
314  }
315 
316  if (opt_display) {
317  //Display the rectangle which defines the part of the image where the reference points are computed.
318  vpDisplay::displayRectangle(Iref, corners[0], corners[1], vpColor::green);
319  vpDisplay::flush(Iref);
320  }
321 
322  if (opt_click_allowed){
323  std::cout << "Click on the image to continue" << std::endl;
324  vpDisplay::getClick(Iref);
325  }
326 
327  vpRect roi(corners[0], corners[1]);
328 
329  std::cout << "> train the classifier on the selected plane. (may take up to several minutes)." << std::endl;
330  if(opt_display) {
331  vpDisplay::display(Iref);
332  vpDisplay::flush(Iref);
333  }
334 
335  try{
336  fern.buildReference(Iref, roi);
337  }
338  catch(vpException e){
339  std::cout << e.getMessage() << std::endl;
340  }
341  catch(...){
342  std::cout << "unknown error, line " << __LINE__ << std::endl;
343  }
344  try{
345  fern.record(objectName, dataFile);
346  }
347  catch(vpException e){
348  std::cout << e.getMessage() << std::endl;
349  }
350  catch(...){
351  std::cout << "unknown error, line " << __LINE__ << std::endl;
352  }
353  std::cout << __LINE__ << std::endl;
354  }
355  else{
356  if(!vpIoTools::checkFilename(dataFile)){
357  vpERROR_TRACE("cannot load the database with the specified name. Has the object been learned with the -l option? ");
358  exit(-1);
359  }
360  try{
361  // load a previously recorded file
362  fern.load(dataFile, objectName);
363  }
364  catch(...){
365  vpERROR_TRACE("cannot load the database with the specified name. Has the object been learned with the -l option? ");
366  exit(-1);
367  }
368  }
369 
370 
371  if(opt_display){
372  display.init(I, 110 + (int)Iref.getWidth(), 100, "Current image") ;
374  vpDisplay::flush(I);
375  }
376 
377  if (opt_display && opt_click_allowed){
378  std::cout << "Click on the current image to continue" << std::endl;
380  "Click on the current image to continue", vpColor::red);
381  vpDisplay::flush(I);
383  }
384 
385  for ( ; ; ) {
386  // acquire a new image
387  iter++;
388  if(iter >= 80){
389  break;
390  }
391  s.str("");
392  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
393  filename = vpIoTools::createFilePath(dirname, s.str());
394  // read the image
395  vpImageIo::read(I, filename);
396 
397  if(opt_display){
399  if(isLearning)
400  vpDisplay::display(Iref);
401  }
402 
403  double t0 = vpTime::measureTimeMs ();
404  // detection of the reference image
405  unsigned int nbpts;
406  try{
407  nbpts = fern.matchPoint(I);
408  }
409  catch(vpException e){
410  std::cout << e.getMessage() << std::endl;
411  return -1;
412  }
413  catch(...){
414  std::cout << "unknown error line " << __LINE__ << std::endl;
415  return -1;
416  }
417  std::cout << "matching " << nbpts << " points : " << vpTime::measureTimeMs () - t0 << " ms" << std::endl;
418 
419  if(opt_display){
420  fern.display(Iref, I, 7);
421  vpDisplay::flush(I);
422  if(isLearning)
423  vpDisplay::flush(Iref);
424  if(vpDisplay::getClick(I, false)){
425  break;
426  }
427  }
428  }
429 
430  return 0;
431  }
432  catch(vpException e) {
433  std::cout << "Catch an exception: " << e << std::endl;
434  return 1;
435  }
436 }
437 
438 #else
439 int
440 main()
441 {
442 #if ( ! (defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)) )
443  vpERROR_TRACE("You do not have X11, GTK or GDI display functionalities...");
444 #else
445  vpERROR_TRACE("You do not have OpenCV-2.0.0 or a more recent release...");
446 #endif
447 }
448 
449 #endif
const char * getMessage(void)
Definition: vpException.cpp:97
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1091
unsigned int getWidth() const
Definition: vpImage.h:161
virtual unsigned int matchPoint(const vpImage< unsigned char > &I)
#define vpERROR_TRACE
Definition: vpDebug.h:391
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:128
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
Definition: vpDisplay.cpp:888
Define the X11 console to display images.
Definition: vpDisplayX.h:148
error that can be emited by ViSP classes.
Definition: vpException.h:73
static const vpColor green
Definition: vpColor.h:166
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:2233
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:76
static const vpColor red
Definition: vpColor.h:163
virtual unsigned int buildReference(const vpImage< unsigned char > &I)
static bool checkFilename(const char *filename)
Definition: vpIoTools.cpp:485
static std::string createFilePath(const std::string &parent, const std::string child)
Definition: vpIoTools.cpp:1265
static void display(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:206
The vpDisplayGTK allows to display image using the GTK+ library version 1.2.
Definition: vpDisplayGTK.h:141
virtual void displayRectangle(const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)=0
void record(const std::string &_objectName, const std::string &_dataFile)
record the Ferns classifier in the text file
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const char *title=NULL)
VISP_EXPORT double measureTimeMs()
Definition: vpTime.cpp:93
unsigned int getHeight() const
Definition: vpImage.h:152
Defines a rectangle in the plane.
Definition: vpRect.h:81
virtual bool getClick(bool blocking=true)=0
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
void load(const std::string &_dataFile, const std::string &)
load the Fern classifier
virtual void display(const vpImage< unsigned char > &Iref, const vpImage< unsigned char > &Icurrent, unsigned int size=3)
static void read(vpImage< unsigned char > &I, const char *filename)
Definition: vpImageIo.cpp:274
void set_ij(const double ii, const double jj)
Definition: vpImagePoint.h:176
Class that implements the Fern classifier and the YAPE detector thanks to the OpenCV library...