Fawkes API  Fawkes Development Version
surf.cpp
1 
2 /***************************************************************************
3  * surf.cpp - SURF based classifier
4  *
5  * Created: Tue Apr 01 10:15:23 2008
6  * Copyright 2008 Stefan Schiffer [stefanschiffer.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <iostream>
25 #include <vector>
26 
27 #include <fvclassifiers/surf.h>
28 #include <math.h>
29 //#ifdef SURF_TIMETRACKER
30 #include <utils/time/clock.h>
31 #include <utils/time/tracker.h>
32 //#endif
33 #include <fstream>
34 
35 #include <string>
36 
37 #include <surf/surflib.h>
38 //#include <surf/ipoint.h>
39 //#include <surf/image.h>
40 //#include <surf/imload.h>
41 
42 #include <core/exception.h>
43 #include <core/exceptions/software.h>
44 #include <fvutils/color/colorspaces.h>
45 #include <fvutils/color/conversions.h>
46 #include <fvutils/readers/png.h>
47 #include <utils/system/console_colors.h>
48 #include <dirent.h>
49 #include <utils/logging/liblogger.h>
50 
51 #define BVERBOSE true
52 
53 //#include <fvutils/writers/pnm.h>
54 //#include <fvutils/writers/png.h>
55 
56 namespace firevision {
57 #if 0 /* just to make Emacs auto-indent happy */
58 }
59 #endif
60 
61 /** @class SurfClassifier <fvclassifiers/surf.h>
62  * SURF classifier.
63  *
64  * This class provides a classifier that uses SURF to detect objects in a given
65  * image by matching features. The objects are reported back as regions of interest.
66  * Each ROI contains an object. ROIs with 11x11 are matched features.
67  *
68  * This code uses libSurf from http://www.vision.ee.ethz.ch/~surf/
69  * and is partly based on code from their package.
70  *
71  * @author Stefan Schiffer
72  */
73 
74 
75 /** saveIpoints
76  * save Surf points
77  * @param sFileName surf file name
78  * @param ipts surf ipoints (surf::iPoint)
79  * @param bVerbose verbose mode
80  * @param bLaplacian laplacian mode
81  */
82 
83 void saveIpoints(std::string sFileName, const std::vector< surf::Ipoint >& ipts, bool bVerbose, bool bLaplacian, int VLength)
84 {
85  std::cout<<"Attempting to save interest points" << std::endl;
86 
87  std::ofstream ipfile(sFileName.c_str());
88  if( !ipfile ) {
89  std::cerr << "ERROR in loadIpoints(): "
90  << "Couldn't open file '" << sFileName.c_str() << "'!" << std::endl; //STS
91  return;
92  }
93 
94  double sc;
95  unsigned count = ipts.size();
96 
97  // Write the file header
98  if (bLaplacian)
99  ipfile << VLength + 1 << std::endl << count << std::endl;
100  else
101  ipfile << VLength << std::endl << count << std::endl;
102  // In order to just save the interest points without descriptor, comment
103  // the above and uncomment the following command.
104  // ipfile << 1.0 << std::endl << count << std::endl;
105  // Save interest point with descriptor in the format of Krystian Mikolajczyk
106  // for reasons of comparison with other descriptors. As our interest points
107  // are circular in any case, we use the second component of the ellipse to
108  // provide some information about the strength of the interest point. This is
109  // important for 3D reconstruction as only the strongest interest points are
110  // considered. Replace the strength with 0.0 in order to perform Krystian's
111  // comparisons.
112  for (unsigned n=0; n<ipts.size(); n++){
113  // circular regions with diameter 5 x scale
114  sc = 2.5 * ipts[n].scale; sc*=sc;
115  ipfile << ipts[n].x /* x-location of the interest point */
116  << " " << ipts[n].y /* y-location of the interest point */
117  << " " << 1.0/sc /* 1/r^2 */
118  << " " << 0.0 //(*ipts)[n]->strength /* 0.0 */
119  << " " << 1.0/sc; /* 1/r^2 */
120 
121  if (bLaplacian)
122  ipfile << " " << ipts[n].laplace;
123 
124  // Here comes the descriptor
125  for (int i = 0; i < VLength; i++) {
126  ipfile << " " << ipts[n].ivec[i];
127  }
128  ipfile << std::endl;
129  }
130 
131  // Write message to terminal.
132  if( bVerbose )
133  std::cout << count << " interest points found" << std::endl;
134 }
135 
136 /** loadIpoints
137  * load interest points
138  * @param sFileName location of the interest points
139  * @param ipts vector to store interest points
140  * @param bVerbose if the saveIpoints was carried out with verbose mode
141  */
142 void loadIpoints( std::string sFileName, std::vector< surf::Ipoint >& ipts, bool bVerbose, int& __vlen )
143 {
144  std::ifstream ipfile(sFileName.c_str());
145 
146  if( !ipfile ) {
147  std::cerr << "ERROR in loadIpoints(): "
148  << "Couldn't open file '" << sFileName.c_str() << "'!" << std::endl; //STS
149  return;
150  }
151 
152  // Load the file header
153 
154  unsigned count;
155  ipfile >> __vlen >> count;
156 
157  __vlen--;
158 
159  // create a new interest point vector
160  ipts.clear();
161  ipts.resize(count);
162 
163  // Load the interest points in Mikolajczyk's format
164  for (unsigned n=0; n<count; n++){
165  // circular regions with diameter 5 x scale
166  float x, y, a, b, c;
167  ipfile >> x >> y >> a >> b >> c;
168 
169  float det = sqrt((a-c)*(a-c) + 4.0*b*b);
170  float e1 = 0.5*(a+c + det);
171  float e2 = 0.5*(a+c - det);
172  float l1 = (1.0/sqrt(e1));
173  float l2 = (1.0/sqrt(e2));
174  float sc = sqrt( l1*l2 );
175 
176  ipts[n].x = x;
177  ipts[n].y = y;
178  ipts[n].scale = sc/2.5;
179  ipfile >> ipts[n].laplace;
180 
181  //ipts[n].allocIvec( VLength );
182  ipts[n].ivec = new double[ __vlen];
183 
184  for( int j = 0 ; j < __vlen; j++ )
185  {
186 
187  ipfile >> ipts[n].ivec[j];
188 
189  // std::cout << ipts[n].ivec[j] << " ";
190  }
191 
192  }
193 
194  // close the interest point file again
195  ipfile.close();
196 
197  // Write message to terminal.
198  if( bVerbose )
199  std::cout << "read in " << count << " interest points." << std::endl;
200 }
201 
202 /** Constructor.
203  * @param keypoints_dir location of the keypoints (descriptor file as a txt file) for the reference objects
204  * @param samplingStep Initial sampling step
205  * @param min_match minimum number of features that have to be matched per ROI
206  * @param min_match_ratio minimum ratio of features matched per object to be matched per ROI
207  * @param octaves Number of analysed octaves
208  * @param thres Blob response treshold
209  * @param doubleImageSize true to double the image size, false to keep original
210  * @param initLobe Initial lobe size, default 3 and 5 (with double image size)
211  * @param upright rotation invariance (fasle) or upright (true)
212  * @param extended true to use the extended descriptor (SURF 128)
213  * @param indexSize Spatial size of the descriptor window (default 4)
214 
215  */
216 SurfClassifier::SurfClassifier( std::string keypoints_dir, unsigned int min_match, float min_match_ratio,
217  int samplingStep, int octaves, double thres,
218  bool doubleImageSize, int initLobe,
219  bool upright, bool extended, int indexSize ): Classifier("SurfClassifier")
220 {
221  __obj_features.clear();
222  __obj_features.reserve(1000);
223  // matching constraints
224  __min_match = min_match;
225  __min_match_ratio = min_match_ratio;
226  // params for FastHessian
227  __samplingStep = samplingStep;
228  __octaves = octaves;
229  __thres = thres;
230  __doubleImageSize = doubleImageSize;
231  __initLobe = initLobe;
232  // params for Descriptors
233  __upright = upright;
234  __extended = extended;
235  __indexSize = indexSize;
236 
237  // descriptor vector length
238  __vlen = 0;
239 
240  //#ifdef SURF_TIMETRACKER
241  __tt = new fawkes::TimeTracker();
242  __loop_count = 0;
243  __ttc_objconv = __tt->add_class("ObjectConvert");
244  __ttc_objfeat = __tt->add_class("ObjectFeatures");
245  __ttc_imgconv = __tt->add_class("ImageConvert");
246  __ttc_imgfeat = __tt->add_class("ImageFeatures");
247  __ttc_matchin = __tt->add_class("Matching");
248  __ttc_roimerg = __tt->add_class("MergeROIs");
249  //#endif
250 
251  //#ifdef SURF_TIMETRACKER
252  __tt->ping_start(__ttc_objconv);
253  //#endif
254 
255  DIR *dir = 0;
256 
257  if( (dir = opendir( keypoints_dir.c_str() ) ) == NULL ) {
258  char* buffer = new char[256];
259  sprintf(buffer, "The directory %s does not exist!", keypoints_dir.c_str() );
260  fawkes::LibLogger::log_error("SurfClassifier",buffer);
261  }
262 
263  struct dirent* ent;
264  std::string object_file;
265  int num_obj_index = 0;
266 
267 
268  while( (ent = readdir(dir)) != NULL ) {
269 
270  if ( strcmp( ent->d_name, ".") == 0 || strcmp( ent->d_name,"..") == 0 || strcmp( ent->d_name,".svn") == 0 )
271  continue;
272 
273  object_file = keypoints_dir + ent->d_name;
274  std:: cout<<"SurfClassifier: reading the following descriptor file" << object_file << std::endl;
275 
276  __obj_names.push_back(object_file);
277 
278 
279  bool b_verbose = BVERBOSE;
280  loadIpoints( object_file, __obj_features[num_obj_index], b_verbose, __vlen);
281  num_obj_index++;
282 
283  }
284 
285  closedir(dir);
286  delete ent;
287 
288  __num_obj = num_obj_index;
289 
290  if( num_obj_index != 0 ) {
291  std::cout<< "SurfClassifier: Reading successful"<< std::endl;
292  //#ifdef SURF_TIMETRACKER
293  __tt->ping_end(__ttc_objconv);
294  //#endif
295  }
296  else {
297 // if no objects were read, then the descriptor files were probably not created still. We can create them now!
298  std::cout <<"SurfClassifier: The descriptor directory is probably empty since no objects were read off. Will instantiate a Surfclassifier with the png images directory") << std::endl;
299  return new SurfClassifier( "../res/opx/objects/", 5 );
300  }
301 
302 
303  // save object image for debugging
304  ///surf::ImLoad::saveImage( "obj.pgm", __obj_img);
305 
306  //#ifdef SURF_TIMETRACKER
307  __tt->ping_start(__ttc_objfeat);
308  //#endif
309  //#ifdef SURF_TIMETRACKER
310  __tt->ping_end(__ttc_objfeat);
311  //#endif
312 
313 
314 }
315 
316 
317 
318 
319 
320 /** Constructor.
321  * @param object_dir file that contains an image of the object to detect
322  * @param samplingStep Initial sampling step
323  * @param min_match minimum number of features that have to be matched per ROI
324  * @param min_match_ratio minimum ratio of features matched per object to be matched per ROI
325  * @param octaves Number of analysed octaves
326  * @param thres Blob response treshold
327  * @param doubleImageSize true to double the image size, false to keep original
328  * @param initLobe Initial lobe size, default 3 and 5 (with double image size)
329  * @param upright rotation invariance (fasle) or upright (true)
330  * @param extended true to use the extended descriptor (SURF 128)
331  * @param indexSize Spatial size of the descriptor window (default 4)
332  */
333 
334 
335 SurfClassifier::SurfClassifier( const char * object_dir,
336  unsigned int min_match, float min_match_ratio,
337  int samplingStep, int octaves, double thres,
338  bool doubleImageSize, int initLobe,
339  bool upright, bool extended, int indexSize)
340  : Classifier("SurfClassifier")
341 {
342 
343  __obj_features.clear();
344  __obj_features.reserve(1000);
345  // matching constraints
346  __min_match = min_match;
347  __min_match_ratio = min_match_ratio;
348  // params for FastHessian
349  __samplingStep = samplingStep;
350  __octaves = octaves;
351  __thres = thres;
352  __doubleImageSize = doubleImageSize;
353  __initLobe = initLobe;
354  // params for Descriptors
355  __upright = upright;
356  __extended = extended;
357  __indexSize = indexSize;
358 
359  // descriptor vector length
360  __vlen = 0;
361 
362 
363  //#ifdef SURF_TIMETRACKER
364  __tt = new fawkes::TimeTracker();
365  __loop_count = 0;
366  __ttc_objconv = __tt->add_class("ObjectConvert");
367  __ttc_objfeat = __tt->add_class("ObjectFeatures");
368  __ttc_imgconv = __tt->add_class("ImageConvert");
369  __ttc_imgfeat = __tt->add_class("ImageFeatures");
370  __ttc_matchin = __tt->add_class("Matching");
371  __ttc_roimerg = __tt->add_class("MergeROIs");
372  //#endif
373 
374  //#ifdef SURF_TIMETRACKER
375  __tt->ping_start(__ttc_objconv);
376  //#endif
377 
378 
379  DIR *dir = 0;
380 
381  std::string dir_path = object_dir;
382 
383  if( (dir = opendir( dir_path.c_str() ) ) == NULL )
384  {
385  char* buffer = new char[256];
386  sprintf(buffer, "The directory %s does not exist!", dir_path.c_str() );
387 
388  fawkes::LibLogger::log_error("SurfClassifier",buffer);
389  }
390 
391  struct dirent* ent;
392  std::string object_file;
393  int num_obj_index = 0;
394 
395  while( (ent = readdir(dir)) != NULL ) {
396 
397  if ( strcmp( ent->d_name, ".") == 0 || strcmp( ent->d_name,"..") == 0 || strcmp( ent->d_name,".svn") == 0)
398  continue;
399 
400  object_file = dir_path + ent->d_name;
401 
402 // if( !object_file && strcmp( object_file, "" ) == 0 ) {
403 // throw fawkes::Exception("empty object file");
404 // }
405 
406  std::cout << "SurfClassifier(classify): opening object image file '" << object_file << "'" << std::endl;
407 
408  PNGReader pngr( object_file.c_str() );
409  unsigned char* buf = malloc_buffer( pngr.colorspace(), pngr.pixel_width(), pngr.pixel_height() );
410  pngr.set_buffer( buf );
411  pngr.read();
412 
413  unsigned int lwidth = pngr.pixel_width();
414  unsigned int lheight = pngr.pixel_height();
415  surf::Image * __simage = new surf::Image( lwidth, lheight );
416  for (unsigned int h = 0; h < lheight; ++h) {
417  for (unsigned int w = 0; w < lwidth ; ++w) {
418  __simage->setPix(w, h, (double)buf[h * lwidth + w] / 255.f);
419  }
420  }
421  // make integral image
422  __obj_img = new surf::Image(__simage, __doubleImageSize);
423 
424  // NOT WORKING
425  //__obj_img = new surf::Image( pngr.pixel_width(), pngr.pixel_height());
426  //__obj_img->setFrame( buf );
427 
428  if ( ! __obj_img ) {
429  throw fawkes::Exception("Could not load object file '%s'", object_file.c_str());
430  }
431 
432  //#ifdef SURF_TIMETRACKER
433  __tt->ping_end(__ttc_objconv);
434  //#endif
435 
436  // save object image for debugging
437  ///surf::ImLoad::saveImage( "obj.pgm", __obj_img);
438 
439  //#ifdef SURF_TIMETRACKER
440  __tt->ping_start(__ttc_objfeat);
441  //#endif
442 
443  // COMPUTE OBJECT FEATURES
444 
445  std::vector<surf::Ipoint> obj_feature;
446  __obj_features.push_back( obj_feature );
447  __obj_features[num_obj_index].clear();
448  __obj_features[num_obj_index].reserve(1000);
449  __obj_num_features = 0;
450  // Extract interest points with Fast-Hessian
451  surf::FastHessian fh(__obj_img, /* pointer to integral image */
452  __obj_features[num_obj_index],
453  __thres, /* blob response threshold */
454  __doubleImageSize, /* double image size flag */
455  __initLobe * 3 /* 3 times lobe size equals the mask size */,
456  __samplingStep, /* subsample the blob response map */
457  __octaves /* number of octaves to be analysed */);
458  // Extract them and get their pointer
459  fh.getInterestPoints();
460  // Initialise the SURF descriptor
461  surf::Surf des(__obj_img, /* pointer to integral image */
462  __doubleImageSize, /* double image size flag */
463  __upright, /* rotation invariance or upright */
464  __extended, /* use the extended descriptor */
465  __indexSize /* square size of the descriptor window (default 4x4)*/);
466  // Get the length of the descriptor vector
467  // resulting from the parameters
468  __vlen = des.getVectLength();
469 
470  //printf("vlen=%i\n", __vlen);
471 
472  // Compute the orientation and the descriptor for every interest point
473  for (unsigned n=0; n < __obj_features[num_obj_index].size(); n++){
474  // set the current interest point
475  des.setIpoint(&(__obj_features.at(num_obj_index).at(n)));
476  // assign reproducible orientation
477  des.assignOrientation();
478  // make the SURF descriptor
479  des.makeDescriptor();
480 
481  }
482 
483 
484  __obj_num_features = __obj_features[num_obj_index].size();
485  if ( ! __obj_num_features > 0 ) {
486  throw fawkes::Exception("Could not compute object features");
487  }
488  std::cout << "SurfClassifier(classify): computed '" << __obj_num_features << "' features from object" << std::endl;
489 
490  char buffer[256];
491  sprintf( buffer, "descriptors/%s-%d.surf", ent->d_name, num_obj_index );
492  std::string des_file_name = buffer;
493 
494  bool b_verbose = BVERBOSE;
495  bool b_laplacian = true;
496 
497  __obj_names.push_back( des_file_name );
498 
499 
500  // save descriptor
501  saveIpoints( des_file_name, __obj_features[num_obj_index], b_verbose, b_laplacian, __vlen );
502 
503 
504  // CleanUp
505  delete __simage;
506 
507  //#ifdef SURF_TIMETRACKER
508  __tt->ping_end(__ttc_objfeat);
509  //#endif
510 
511  num_obj_index++;
512  }
513 
514  __num_obj = num_obj_index;
515 
516 }
517 
518 
519 /** Destructor. */
521 {
522  //
523 }
524 
525 
526 std::list< ROI > *
528 {
529 
530  // std::cout<<"SurfClassifier: Entering classification:-"<< std::endl;
531  //#ifdef SURF_TIMETRACKER
532  __tt->ping_start(0);
533  //#endif
534 
535  // list of ROIs to return
536 
537  std::list<ROI> rv[__num_obj];
538  float match_ratios[__num_obj];
539 
540 
541  // std::list< ROI > *rv = new std::list< ROI >();
542 
543  // for ROI calculation
544  int x_min = _width;
545  int y_min = _height;
546  int x_max = 0;
547  int y_max = 0;
548 
549  //#ifdef SURF_TIMETRACKER
550  __tt->ping_start(__ttc_imgconv);
551  //#endif
552  std::cout << "SurfClassifier(classify): copy imgdat to SURF Image" << std::endl;
553 
554  /*
555  // NOT WOKRING ALTERNATIVE
556  double *tmpb = (double *)malloc(_width * _height * sizeof(double));
557  for (unsigned int h = 0; h < _height; ++h) {
558  for (unsigned int w = 0; w < _width; ++w) {
559  tmpb[h * _width + w] = (double)_src[h * _width + w] / 255;
560  }
561  }
562  __simage->setFrame( (unsigned char*)tmpb );
563  //surf::ImLoad::saveImage( "stst.pgm", __simage);
564  __image = new surf::Image(__simage, __doubleImageSize);
565  //__image = new surf::Image( _width, _height);
566  //__image->setFrame( (unsigned char *)tmpb );
567  */
568 
569  surf::Image * __simage = new surf::Image( _width, _height);
570  for (unsigned int h = 0; h < _height; ++h) {
571  for (unsigned int w = 0; w < _width; ++w) {
572  __simage->setPix(w, h, (double)_src[h * _width + w] / 255.f);
573  }
574  }
575  // create integral image
576  __image = new surf::Image(__simage, __doubleImageSize);
577 
578  //#ifdef SURF_TIMETRACKER
579  __tt->ping_end(__ttc_imgconv);
580  //#endif
581 
582 
583  /*
584  /// write pnm (with surf-routine) for debugging
585  //surf::ImLoad::saveImage( "tst.pgm", __simage);
586  /// write integral pnm (with surf-routine) for debugging
587  //surf::ImLoad::saveImage( "tst.pgm", __image);
588  /// write pgm (with fv-routine) for debugging
589  PNMWriter pnm(PNM_PGM, "fvimg.pgm", _width, _height);
590  pnm.set_buffer(YUV422_PLANAR, _src );
591  pnm.write();
592  /// write png (with fv-routine) for debugging
593  PNGWriter pngw("fvimg.png", _width, _height);
594  pngw.set_buffer(YUV422_PLANAR, _src );
595  pngw.write();
596  */
597 
598  //#ifdef SURF_TIMETRACKER
599  __tt->ping_start(__ttc_imgfeat);
600  //#endif
601 
602  // COMPUTE OBJECT FEATURES
603  __img_features.clear();
604  __img_features.reserve(1000);
605  __img_num_features = 0;
606  // Extract interest points with Fast-Hessian
607  surf::FastHessian fh(__image, /* pointer to integral image */
608  __img_features,
609  __thres, /* blob response threshold */
610  __doubleImageSize, /* double image size flag */
611  __initLobe * 3 /* 3 times lobe size equals the mask size */,
612  __samplingStep, /* subsample the blob response map */
613  __octaves /* number of octaves to be analysed */);
614  // Extract them and get their pointer
615  std::cout<<"surfclassifer/classify : getting interest points"<<std::endl;
616  fh.getInterestPoints();
617  // Initialise the SURF descriptor
618  surf::Surf des(__image, /* pointer to integral image */
619  __doubleImageSize, /* double image size flag */
620  __upright, /* rotation invariance or upright */
621  __extended, /* use the extended descriptor */
622  __indexSize /* square size of the descriptor window (default 4x4)*/);
623  // Get the length of the descriptor vector
624  // resulting from the parameters
625  // NOT NEEDED HERE!
626  //__vlen = des.getVectLength();
627  //printf("img vlen=%i\n", __vlen);
628 
629  // Compute the orientation and the descriptor for every interest point
630  for (unsigned n=0; n < __img_features.size(); n++){
631  //for (Ipoint *k = ipts; k != NULL; k = k->next){
632  // set the current interest point
633  des.setIpoint(&__img_features[n]);
634  // assign reproducible orientation
635  des.assignOrientation();
636  // make the SURF descriptor
637  des.makeDescriptor();
638  }
639  __img_num_features = __img_features.size();
640  //#ifdef SURF_TIMETRACKER
641  __tt->ping_end(__ttc_imgfeat);
642  //#endif
643 
644  std::cout << "Extracted '" << __img_num_features << "' image features" << std::endl;
645 
646 
647  //#ifdef SURF_TIMETRACKER
648  __tt->ping_start(__ttc_matchin);
649  //#endif
650  std::cout << "SurfClassifier(classify): matching ..." << std::endl;
651 
652  for( unsigned j = 0; j < __num_obj; j++ )
653  {
654  std::vector< int > matches(__obj_features[j].size());
655  // std::cout<< "SurfClassifier; _debug_ : " << __obj_features[j].size() << "and" << __img_features.size() << std::endl;
656  int c = 0;
657  for (unsigned i = 0; i < __obj_features[j].size(); i++) {
658  int match = findMatch((__obj_features[j])[i], __img_features);
659  matches[i] = match;
660  if (match != -1) {
661  // std::cout << " Matched feature " << i << " in object image with feature " << match << " in image." << std::endl;
662  /// adding feature-ROI
663  ROI r( (int)(__img_features[matches[i]].x)-5, (int)(__img_features[matches[i]].y )-5, 11, 11, _width, _height);
664  r.num_hint_points = 0;
665  rv[j].push_back(r);
666  /// increment feature-match-count
667  ++c;
668  }
669  }
670  //#ifdef SURF_TIMETRACKER
671  __tt->ping_end(__ttc_matchin);
672  //#endif
673  if( c == 0 )
674  std::cout << "SurfClassifier(classify) matched '" << c << fawkes::cnormal <<"' of '" << __obj_features[j].size() << "' features in scene. (for supplied object = " << j << std::endl ;
675  else
676  std::cout << "SurfClassifier(classify) matched '" << fawkes::cblue << c << fawkes::cnormal <<"' of '" << __obj_features[j].size() << "' features in scene. (for supplied object = " << j << std::endl ;
677 
678 
679  float match_ratio = ((float)c / (float)__obj_features[j].size());
680  match_ratios[j] = match_ratio;
681 
682  std::cout << "SurfClassifier(classify): match_ratio is '" << match_ratio << "' and min_match_ratio is" << __min_match_ratio << std::endl;
683 
684  std::cout << "SurfClassifier(classify): computing ROI" << std::endl;
685  //#ifdef SURF_TIMETRACKER
686  __tt->ping_start(__ttc_roimerg);
687  //#endif
688  for (unsigned i = 0; i < matches.size(); i++) {
689  if (matches[i] != -1) {
690  // //(int)__obj_features[i].x, (int)__obj_features[i].y
691  //(int)__img_features[matches[i]].x, (int)(__img_features[matches[i]].y );
692  if( (int)__img_features[matches[i]].x < x_min )
693  x_min = (int)__img_features[matches[i]].x;
694  if( (int)__img_features[matches[i]].y < y_min )
695  y_min = (int)__img_features[matches[i]].y;
696  if( (int)__img_features[matches[i]].x > x_max )
697  x_max = (int)__img_features[matches[i]].x;
698  if( (int)__img_features[matches[i]].y > y_max )
699  y_max = (int)__img_features[matches[i]].y;
700  }
701  }
702  if( (c != 0) && ((unsigned)c > __min_match) &&
703  (match_ratio > __min_match_ratio) &&
704  (x_max - x_min != 0 ) && (y_max - y_min != 0) ) {
705 
706  std::cout << "SurfClassifier(classify): c='" << c << "' __min_match='" << __min_match << "'." << std::endl;
707 
708  ROI r(x_min, y_min, x_max-x_min, y_max-y_min, _width, _height);
709  r.num_hint_points = c;
710  rv[j].push_back(r);
711  } else {
712  std::cout << " clearing ROI-list (no or too few matches or [0,0]-roi!)" << std::endl;
713  rv[j].clear();
714  }
715  }
716  //#ifdef SURF_TIMETRACKER
717  __tt->ping_end(__ttc_roimerg);
718  //#endif
719 
720  // CleanUp
721  delete __image;
722  delete __simage;
723 
724  //#ifdef SURF_TIMETRACKER
725  __tt->ping_end(0);
726  //#endif
727 
728  //#ifdef SURF_TIMETRACKER
729  // print timetracker statistics
730  //__tt->print_to_stdout();
731  //#endif
732 
733 
734  // histogram comparison of all rois and features detected
735  float min_ratio_tmp = -1.0;
736  int min_ratio_index = -1;
737  for( unsigned int i = 0; i < __num_obj; i++ )
738  {
739  if( match_ratios[i] > min_ratio_tmp )
740  {
741  min_ratio_tmp = match_ratios[i];
742  min_ratio_index = i;
743  }
744  }
745 
746  std::list<ROI> *final_rv = new std::list<ROI>;
747 
748  final_rv->assign( rv[min_ratio_index].begin(), rv[min_ratio_index].end() );
749 
750 
751  std::string first_not(".-");
752  int first_not_index = __obj_names[ min_ratio_index ].find_first_of( first_not );
753  std::string obj_name_tmp( __obj_names[ min_ratio_index ] );
754  obj_name_tmp.erase( first_not_index );
755 
756 
757  std::cout << "SurfClassifier(classify): done, ... returning '" << rv->size() << "' ROIs. The object class is " << min_ratio_index << "and object name is " << fawkes::cgreen << obj_name_tmp << fawkes::cnormal << std::endl;
758  return final_rv;
759 }
760 
761 int
762 SurfClassifier::findMatch(const surf::Ipoint& ip1, const std::vector< surf::Ipoint >& ipts) {
763  double mind = 1e100, second = 1e100;
764  int match = -1;
765 
766  // std::cout<< "SurfClassifier/findMatch: " << ipts.size() <<" " << __vlen << std::endl;
767 
768  for (unsigned i = 0; i < ipts.size(); i++) {
769  // Take advantage of Laplacian to speed up matching
770  if (ipts[i].laplace != ip1.laplace)
771  continue;
772 
773  double d = distSquare(ipts[i].ivec, ip1.ivec, __vlen);
774 
775  if (d < mind) {
776  second = mind;
777  mind = d;
778  match = i;
779  } else if (d < second) {
780  second = d;
781  }
782  }
783 
784  if (mind < 0.5 * second)
785  return match;
786 
787  return -1;
788 }
789 
790 
791 double
792 SurfClassifier::distSquare(double *v1, double *v2, int n) {
793  double dsq = 0.;
794  // std::cout<< fawkes::cblue << (*v1) << fawkes::cred << (*v2);
795 
796  while (n--) {
797 
798  dsq += (*v1 - *v2) * (*v1 - *v2);
799  v1++;
800  v2++;
801  }
802 
803  // std::cout << fawkes::cgreen << " "<<dsq << std::endl;
804 
805  return dsq;
806 }
807 
808 } // end namespace firevision
void ping_start(unsigned int cls)
Start of given class task.
Definition: tracker.cpp:228
virtual std::list< ROI > * classify()
Classify image.
Definition: surf.cpp:527
unsigned int _width
Width in pixels of _src buffer.
Definition: classifier.h:54
Region of interest.
Definition: roi.h:58
unsigned int _height
Height in pixels of _src buffer.
Definition: classifier.h:56
PNG file reader.
Definition: png.h:36
static std::string cgreen
Print green on console.
static void log_error(const char *component, const char *format,...)
Log error message.
Definition: liblogger.cpp:180
Base class for exceptions in Fawkes.
Definition: exception.h:36
unsigned int add_class(std::string name)
Add a new class.
Definition: tracker.cpp:156
Time tracking utility.
Definition: tracker.h:38
void ping_end(unsigned int cls)
End of given class task.
Definition: tracker.cpp:254
static std::string cnormal
Print normal on console, without colors, depends on console settings.
Classifier to extract regions of interest.
Definition: classifier.h:37
unsigned int num_hint_points
Minimum estimate of points in ROI that are attributed to the ROI hint.
Definition: roi.h:139
SurfClassifier(std::string keypoints_descriptor_txt_file, unsigned int min_match=5, float min_match_ratio=MIN_MATCH_RATIO, int samplingStep=2, int octaves=4, double thres=4.0, bool doubleImageSize=false, int initLobe=3, bool upright=false, bool extended=false, int indexSize=4)
Constructor.
Definition: surf.cpp:216
static std::string cblue
Print blue on console.
unsigned char * _src
Source buffer, encoded as YUV422_PLANAR.
Definition: classifier.h:52
virtual ~SurfClassifier()
Destructor.
Definition: surf.cpp:520