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