ViSP  2.9.0
fernClassifier.cpp
1 /****************************************************************************
2  *
3  * $Id: fernClassifier.cpp 4658 2014-02-09 09:50:14Z fspindle $
4  *
5  * This file is part of the ViSP software.
6  * Copyright (C) 2005 - 2014 by INRIA. All rights reserved.
7  *
8  * This software is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * ("GPL") version 2 as published by the Free Software Foundation.
11  * See the file LICENSE.GPL at the root directory of this source
12  * distribution for additional information about the GNU GPL.
13  *
14  * For using ViSP with software that can not be combined with the GNU
15  * GPL, please contact INRIA about acquiring a ViSP Professional
16  * Edition License.
17  *
18  * See http://www.irisa.fr/lagadic/visp/visp.html for more information.
19  *
20  * This software was developed at:
21  * INRIA Rennes - Bretagne Atlantique
22  * Campus Universitaire de Beaulieu
23  * 35042 Rennes Cedex
24  * France
25  * http://www.irisa.fr/lagadic
26  *
27  * If you have questions regarding the use of this file, please contact
28  * INRIA at visp@inria.fr
29  *
30  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
31  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  *
33  *
34  * Description:
35  * Detection of points of interests and matching using the Ferns classifier.
36  *
37  * Authors:
38  * Romain Tallonneau
39  *
40  *****************************************************************************/
53 #include <visp/vpConfig.h>
54 #include <visp/vpDebug.h>
55 
56 #if ((defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)) && (VISP_HAVE_OPENCV_VERSION >= 0x020000))
57 
58 #include <iostream>
59 #include <stdlib.h>
60 #include <visp/vpFernClassifier.h>
61 #include <visp/vpParseArgv.h>
62 #include <visp/vpConfig.h>
63 #include <visp/vpOpenCVGrabber.h>
64 #include <visp/vpImage.h>
65 #include <visp/vpDisplayX.h>
66 #include <visp/vpDisplayGTK.h>
67 #include <visp/vpDisplayGDI.h>
68 #include <visp/vpHomography.h>
69 #include <visp/vpImageIo.h>
70 #include <visp/vpIoTools.h>
71 #include <visp/vpTime.h>
72 #include <iomanip>
73 
74 #define GETOPTARGS "hlcdb:i:sp"
75 
76 void usage(const char *name, const char *badparam);
77 bool getOptions(int argc, const char **argv, bool &isLearning, std::string& dataFile, bool& click_allowed,
78  bool& display, bool& displayPoints, bool& useSequence, std::string& ipath);
79 
88 void usage(const char *name, const char *badparam)
89 {
90  fprintf(stdout, "\n\
91 Detection of points of interests and matching using the Ferns classifier. The \
92 object needs first to be learned (-l option). This learning process will create\
93 a file used to detect the object.\n\
94 \n\
95 SYNOPSIS\n\
96  %s [-l] [-h] [-b] [-c] [-d] [-p] [-i] [-s]\n", name);
97 
98  fprintf(stdout, "\n\
99 OPTIONS: \n\
100  -l\n\
101  learn an object.\n\
102 \n\
103  -i <input image path> \n\
104  Set image input path.\n\
105  From this path read \"ViSP-images/line/image.%%04d.pgm\"\n\
106  images. \n\
107  Setting the VISP_INPUT_IMAGE_PATH environment\n\
108  variable produces the same behaviour than using\n\
109  this option.\n\
110 \n\
111  -b\n\
112  database filename to use (default is ./dataFern).\n\
113 \n\
114  -c\n\
115  Disable the mouse click. Useful to automaze the \n\
116  execution of this program without humain intervention.\n\
117 \n\
118  -d \n\
119  Turn off the display.\n\
120 \n\
121  -s \n\
122  Turn off the use of the sequence and use a webcam.\n\
123 \n\
124  -p \n\
125  display points of interest.\n\
126 \n\
127  -h\n\
128  Print this help.\n");
129 
130  if (badparam)
131  fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
132 
133 }
134 
152 bool getOptions(int argc, const char **argv, bool &isLearning, std::string& dataFile, bool& click_allowed,
153  bool& display, bool& displayPoints, bool& useSequence, std::string& ipath)
154 {
155  const char *optarg_;
156  int c;
157  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
158 
159  switch (c) {
160  case 'c': click_allowed = false; break;
161  case 'd': display = false; break;
162  case 'l': isLearning = true; break;
163  case 'h': usage(argv[0], NULL); return false; break;
164  case 'b': dataFile = optarg_; break;
165  case 'p': displayPoints = true; break;
166  case 's': useSequence = false; break;
167  case 'i': ipath = optarg_; break;
168  default:
169  usage(argv[0], optarg_);
170  return false; break;
171  }
172  }
173 
174  if ((c == 1) || (c == -1)) {
175  // standalone param or error
176  usage(argv[0], NULL);
177  std::cerr << "ERROR: " << std::endl;
178  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
179  return false;
180  }
181 
182  return true;
183 }
184 
185 
186 
187 int
188 main(int argc, const char** argv)
189 {
190  try {
191  bool isLearning = false;
192  std::string dataFile("./dataFern");
193  bool opt_click_allowed = true;
194  bool opt_display = true;
195  std::string objectName("object");
196  bool displayPoints = false;
197  bool useSequence = true;
198  std::string opt_ipath;
199  std::string ipath;
200  std::string env_ipath;
201  std::string dirname;
202  std::string filename;
203 
204  // Get the VISP_IMAGE_PATH environment variable value
205  char *ptenv = getenv("VISP_INPUT_IMAGE_PATH");
206  if (ptenv != NULL){
207  env_ipath = ptenv;
208  }
209 
210  // Set the default input path
211  if (! env_ipath.empty()){
212  ipath = env_ipath;
213  }
214 
215  // Read the command line options
216  if (getOptions(argc, argv,
217  isLearning, dataFile, opt_click_allowed, opt_display, displayPoints, useSequence, opt_ipath) == false) {
218  exit (-1);
219  }
220 
221  // Get the option values
222  if (useSequence && !opt_ipath.empty()){
223  ipath = opt_ipath;
224  }
225 
226  // Compare ipath and env_ipath. If they differ, we take into account
227  // the input path comming from the command line option
228  if (useSequence && !opt_ipath.empty() && !env_ipath.empty()) {
229  if (ipath != env_ipath) {
230  std::cout << std::endl
231  << "WARNING: " << std::endl;
232  std::cout << " Since -i <visp image path=" << ipath << "> "
233  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
234  << " we skip the environment variable." << std::endl;
235  }
236  }
237 
238  // Test if an input path is set
239  if (useSequence && opt_ipath.empty() && env_ipath.empty()){
240  usage(argv[0], NULL);
241  std::cerr << std::endl
242  << "ERROR:" << std::endl;
243  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH "
244  << std::endl
245  << " environment variable to specify the location of the " << std::endl
246  << " image path where test images are located." << std::endl << std::endl;
247  exit(-1);
248  }
249 
250 
251  // Declare two images, these are gray level images (unsigned char)
254 
255 
256  // Set the path location of the image sequence
257  dirname = ipath + vpIoTools::path("/ViSP-images/cube/");
258 
259  // Build the name of the image file
260  unsigned iter = 0; // Image number
261  std::ostringstream s;
262  s.setf(std::ios::right, std::ios::adjustfield);
263  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
264  filename = dirname + s.str();
265 
266  // Read the PGM image named "filename" on the disk, and put the
267  // bitmap into the image structure I. I is initialized to the
268  // correct size
269  //
270  // exception readPGM may throw various exception if, for example,
271  // the file does not exist, or if the memory cannot be allocated
272  try{
273  if(useSequence){
274  vpCTRACE << "Load: " << filename << std::endl;
275  vpImageIo::read(Iref, filename) ;
276  I = Iref;
277  }
278  }
279  catch(...)
280  {
281  // an exception is throwned if an exception from readPGM has been catched
282  // here this will result in the end of the program
283  // Note that another error message has been printed from readPGM
284  // to give more information about the error
285  std::cerr << std::endl
286  << "ERROR:" << std::endl;
287  std::cerr << " Cannot read " << filename << std::endl;
288  std::cerr << " Check your -i " << ipath << " option " << std::endl
289  << " or VISP_INPUT_IMAGE_PATH environment variable."
290  << std::endl;
291  exit(-1);
292  }
293 
294 
295  // Declare a framegrabber
296  vpOpenCVGrabber g;
297  if(!useSequence){
298  try{
299  g.open(I);
300  }
301  catch(...){
302  std::cout << "problem to initialise the framegrabber" << std::endl;
303  exit(-1);
304  }
305  g.acquire(I);
306  // initialise the reference image
307  g.acquire(Iref);
308  }
309 
310 #if defined VISP_HAVE_X11
311  vpDisplayX display;
312 #elif defined VISP_HAVE_GTK
313  vpDisplayGTK display;
314 #elif defined VISP_HAVE_GDI
315  vpDisplayGDI display;
316 #endif
317 
318 #if defined VISP_HAVE_X11
319  vpDisplayX displayRef;
320 #elif defined VISP_HAVE_GTK
321  vpDisplayGTK displayRef;
322 #elif defined VISP_HAVE_GDI
323  vpDisplayGDI displayRef;
324 #endif
325 
326  // declare a planar object detector
327  vpFernClassifier fern;
328 
329  if(isLearning){
330  if(opt_display){
331  displayRef.init(Iref, 100, 100, "Reference image") ;
332  vpDisplay::display(Iref);
333  vpDisplay::flush(Iref);
334  }
335  vpImagePoint corners[2];
336  if (opt_display && opt_click_allowed){
337  std::cout << "Click on the top left and the bottom right corners to define the reference plane" << std::endl;
338  for (int i=0 ; i < 2 ; i++){
339  vpDisplay::getClick(Iref, corners[i]);
340  std::cout << corners[i] << std::endl;
341  }
342  }
343  else{
344  corners[0].set_ij(1,1);
345  corners[1].set_ij(I.getHeight()-2,I.getWidth()-2);
346  }
347 
348  if (opt_display) {
349  //Display the rectangle which defines the part of the image where the reference points are computed.
350  vpDisplay::displayRectangle(Iref, corners[0], corners[1], vpColor::green);
351  vpDisplay::flush(Iref);
352  }
353 
354  if (opt_click_allowed){
355  std::cout << "Click on the image to continue" << std::endl;
356  vpDisplay::getClick(Iref);
357  }
358 
359  vpRect roi(corners[0], corners[1]);
360 
361  std::cout << "> train the classifier on the selected plane. (may take up to several minutes)." << std::endl;
362  if(opt_display) {
363  vpDisplay::display(Iref);
364  vpDisplay::flush(Iref);
365  }
366 
367  try{
368  fern.buildReference(Iref, roi);
369  }
370  catch(vpException e){
371  std::cout << e.getMessage() << std::endl;
372  }
373  catch(...){
374  std::cout << "unknown error, line " << __LINE__ << std::endl;
375  }
376  try{
377  fern.record(objectName, dataFile);
378  }
379  catch(vpException e){
380  std::cout << e.getMessage() << std::endl;
381  }
382  catch(...){
383  std::cout << "unknown error, line " << __LINE__ << std::endl;
384  }
385  std::cout << __LINE__ << std::endl;
386  }
387  else{
388  if(!vpIoTools::checkFilename(dataFile)){
389  vpERROR_TRACE("cannot load the database with the specified name. Has the object been learned with the -l option? ");
390  exit(-1);
391  }
392  try{
393  // load a previously recorded file
394  fern.load(dataFile, objectName);
395  }
396  catch(...){
397  vpERROR_TRACE("cannot load the database with the specified name. Has the object been learned with the -l option? ");
398  exit(-1);
399  }
400  }
401 
402 
403  if(opt_display){
404  display.init(I, 110 + (int)Iref.getWidth(), 100, "Current image") ;
406  vpDisplay::flush(I);
407  }
408 
409  if (opt_display && opt_click_allowed){
410  std::cout << "Click on the current image to continue" << std::endl;
412  (char*)"Click on the current image to continue", vpColor::red);
413  vpDisplay::flush(I);
415  }
416 
417  for ( ; ; ) {
418  // acquire a new image
419  if(useSequence){
420  iter++;
421  if(iter >= 80){
422  break;
423  }
424  s.str("");
425  s << "image." << std::setw(4) << std::setfill('0') << iter << ".pgm";
426  filename = dirname + s.str();
427  // read the image
428  vpImageIo::read(I, filename);
429  }
430  else{
431  g.acquire(I);
432  }
433 
434  if(opt_display){
436  if(isLearning)
437  vpDisplay::display(Iref);
438  }
439 
440  double t0 = vpTime::measureTimeMs ();
441  // detection of the reference image
442  unsigned int nbpts;
443  try{
444  nbpts = fern.matchPoint(I);
445  }
446  catch(vpException e){
447  std::cout << e.getMessage() << std::endl;
448  return -1;
449  }
450  catch(...){
451  std::cout << "unknown error line " << __LINE__ << std::endl;
452  return -1;
453  }
454  std::cout << "matching " << nbpts << " points : " << vpTime::measureTimeMs () - t0 << " ms" << std::endl;
455 
456  if(opt_display){
457  fern.display(Iref, I, 7);
458  vpDisplay::flush(I);
459  if(isLearning)
460  vpDisplay::flush(Iref);
461  if(vpDisplay::getClick(I, false)){
462  break;
463  }
464  }
465  }
466 
467  return 0;
468  }
469  catch(vpException e) {
470  std::cout << "Catch an exception: " << e << std::endl;
471  return 1;
472  }
473 }
474 
475 #else
476 int
477 main()
478 {
479 #if ( ! (defined (VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)) )
480  vpERROR_TRACE("You do not have X11, GTK or GDI display functionalities...");
481 #else
482  vpERROR_TRACE("You do not have OpenCV-2.0.0 or a more recent release...");
483 #endif
484 }
485 
486 #endif
const char * getMessage(void)
unsigned int getWidth() const
Definition: vpImage.h:159
#define vpERROR_TRACE
Definition: vpDebug.h:395
virtual unsigned int matchPoint(const vpImage< unsigned char > &I)
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:132
Define the X11 console to display images.
Definition: vpDisplayX.h:152
error that can be emited by ViSP classes.
Definition: vpException.h:76
static std::string path(const char *pathname)
Definition: vpIoTools.cpp:715
static double measureTimeMs()
Definition: vpTime.cpp:86
static const vpColor green
Definition: vpColor.h:170
static void flush(const vpImage< unsigned char > &I)
Definition: vpDisplay.cpp:1994
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:79
static const vpColor red
Definition: vpColor.h:167
#define vpCTRACE
Definition: vpDebug.h:341
virtual unsigned int buildReference(const vpImage< unsigned char > &I)
static bool checkFilename(const char *filename)
Definition: vpIoTools.cpp:485
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:145
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)
virtual void displayCharString(const vpImagePoint &ip, const char *text, const vpColor &color=vpColor::green)=0
void acquire(vpImage< unsigned char > &I)
unsigned int getHeight() const
Definition: vpImage.h:150
Defines a rectangle in the plane.
Definition: vpRect.h:85
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:92
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:278
Class for cameras video capture using OpenCV library.
void set_ij(const double ii, const double jj)
Definition: vpImagePoint.h:180
Class that implements the Fern classifier and the YAPE detector thanks to the OpenCV library...