surf.cpp

00001 
00002 /***************************************************************************
00003  *  surf.cpp - SURF based classifier
00004  *
00005  *  Created: Tue Apr 01 10:15:23 2008
00006  *  Copyright 2008 Stefan Schiffer [stefanschiffer.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version. A runtime exception applies to
00014  *  this software (see LICENSE.GPL_WRE file mentioned below for details).
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.
00022  */
00023 
00024 #include <iostream>
00025 #include <vector>
00026 
00027 #include <classifiers/surf.h>
00028 #include <math.h>
00029 //#ifdef SURF_TIMETRACKER
00030 #include <utils/time/clock.h>
00031 #include <utils/time/tracker.h>
00032 //#endif
00033 #include <fstream>
00034 
00035 #include <string>
00036 
00037 #include <surf/surflib.h>
00038 //#include <surf/ipoint.h>
00039 //#include <surf/image.h>
00040 //#include <surf/imload.h>
00041 
00042 #include <core/exception.h>
00043 #include <core/exceptions/software.h>
00044 #include <fvutils/color/colorspaces.h>
00045 #include <fvutils/color/conversions.h>
00046 #include <fvutils/readers/png.h>
00047 #include <utils/system/console_colors.h>
00048 #include <dirent.h>
00049 #include <utils/logging/liblogger.h>
00050 
00051 #define BVERBOSE true
00052 
00053 //#include <fvutils/writers/pnm.h>
00054 //#include <fvutils/writers/png.h>
00055 
00056 namespace firevision {
00057 #if 0 /* just to make Emacs auto-indent happy */
00058 }
00059 #endif
00060 
00061 /** @class SurfClassifier <classifiers/surf.h>
00062  * SURF classifier.
00063  *
00064  * This class provides a classifier that uses SURF to detect objects in a given
00065  * image by matching features. The objects are reported back as regions of interest.
00066  * Each ROI contains an object. ROIs with 11x11 are matched features.
00067  *
00068  * This code uses libSurf from http://www.vision.ee.ethz.ch/~surf/
00069  * and is partly based on code from their package.
00070  *
00071  * @author Stefan Schiffer
00072  */
00073 
00074 
00075 /** saveIpoints
00076  * save Surf points
00077  * @param sFileName surf file name
00078  * @param ipts surf ipoints (surf::iPoint)
00079  * @param bVerbose verbose mode
00080  * @param bLaplacian laplacian mode
00081  */
00082 
00083 void saveIpoints(std::string sFileName, const std::vector< surf::Ipoint >& ipts, bool bVerbose, bool bLaplacian, int VLength)
00084 {
00085   std::cout<<"Attempting to save interest points" << std::endl;
00086 
00087   std::ofstream ipfile(sFileName.c_str());
00088   if( !ipfile ) {
00089     std::cerr << "ERROR in loadIpoints(): "
00090               << "Couldn't open file '" << sFileName.c_str() << "'!" << std::endl; //STS
00091     return;
00092   }
00093 
00094   double sc;
00095   unsigned count = ipts.size();
00096 
00097   // Write the file header
00098   if (bLaplacian)
00099      ipfile << VLength + 1 << std::endl << count << std::endl;
00100    else
00101      ipfile << VLength << std::endl << count << std::endl;
00102   // In order to just save the interest points without descriptor, comment
00103   // the above and uncomment the following command.
00104   //  ipfile << 1.0 << std::endl << count << std::endl;
00105   // Save interest point with descriptor in the format of Krystian Mikolajczyk
00106   // for reasons of comparison with other descriptors. As our interest points
00107   // are circular in any case, we use the second component of the ellipse to
00108   // provide some information about the strength of the interest point. This is
00109   // important for 3D reconstruction as only the strongest interest points are
00110   // considered. Replace the strength with 0.0 in order to perform Krystian's
00111   // comparisons.
00112   for (unsigned n=0; n<ipts.size(); n++){
00113     // circular regions with diameter 5 x scale
00114     sc = 2.5 * ipts[n].scale; sc*=sc;
00115     ipfile  << ipts[n].x /* x-location of the interest point */
00116             << " " << ipts[n].y /* y-location of the interest point */
00117             << " " << 1.0/sc /* 1/r^2 */
00118             << " " << 0.0     //(*ipts)[n]->strength /* 0.0 */
00119             << " " << 1.0/sc; /* 1/r^2 */
00120 
00121     if (bLaplacian)
00122       ipfile << " " << ipts[n].laplace;
00123 
00124     // Here comes the descriptor
00125     for (int i = 0; i < VLength; i++) {
00126       ipfile << " " << ipts[n].ivec[i];
00127     }
00128     ipfile << std::endl;
00129   }
00130 
00131   // Write message to terminal.
00132   if( bVerbose )
00133     std::cout << count << " interest points found" << std::endl;
00134 }
00135 
00136 /** loadIpoints
00137  * load interest points
00138  * @param sFileName location of the interest points
00139  * @param ipts vector to store interest points
00140  * @param bVerbose if the saveIpoints was carried out with verbose mode
00141  */
00142 void loadIpoints( std::string sFileName, std::vector< surf::Ipoint >& ipts, bool bVerbose, int& __vlen )
00143 {
00144   std::ifstream ipfile(sFileName.c_str());
00145 
00146   if( !ipfile ) {
00147   std::cerr << "ERROR in loadIpoints(): "
00148             << "Couldn't open file '" << sFileName.c_str() << "'!" << std::endl; //STS
00149     return;
00150   }
00151 
00152   // Load the file header
00153 
00154   unsigned count;
00155   ipfile >> __vlen >> count;
00156 
00157   __vlen--;
00158 
00159   // create a new interest point vector
00160   ipts.clear();
00161   ipts.resize(count);
00162 
00163   // Load the interest points in Mikolajczyk's format
00164   for (unsigned n=0; n<count; n++){
00165     // circular regions with diameter 5 x scale
00166     float x, y, a, b, c;
00167     ipfile >> x >> y >> a >> b >> c;
00168 
00169     float det = sqrt((a-c)*(a-c) + 4.0*b*b);
00170     float e1 = 0.5*(a+c + det);
00171     float e2 = 0.5*(a+c - det);
00172     float l1 = (1.0/sqrt(e1));
00173     float l2 = (1.0/sqrt(e2));
00174     float sc = sqrt( l1*l2 );
00175 
00176     ipts[n].x     = x;
00177     ipts[n].y     = y;
00178     ipts[n].scale = sc/2.5;
00179     ipfile >> ipts[n].laplace;
00180 
00181     //ipts[n].allocIvec( VLength );
00182     ipts[n].ivec = new double[ __vlen];
00183 
00184     for( int j = 0 ; j < __vlen; j++ )
00185       {
00186 
00187         ipfile >> ipts[n].ivec[j];
00188 
00189         //      std::cout << ipts[n].ivec[j] << " ";
00190       }
00191 
00192   }
00193 
00194   // close the interest point file again
00195   ipfile.close();
00196 
00197   // Write message to terminal.
00198   if( bVerbose )
00199     std::cout << "read in " << count << " interest points." << std::endl;
00200 }
00201 
00202 /** Constructor.
00203  * @param keypoints_dir location of the keypoints (descriptor file as a txt file) for the reference objects
00204  * @param samplingStep Initial sampling step
00205  * @param min_match minimum number of features that have to be matched per ROI
00206  * @param min_match_ratio  minimum ratio of features matched per object to be matched per ROI
00207  * @param octaves Number of analysed octaves
00208  * @param thres Blob response treshold
00209  * @param doubleImageSize true to double the image size, false to keep original
00210  * @param initLobe Initial lobe size, default 3 and 5 (with double image size)
00211  * @param upright rotation invariance (fasle) or upright (true)
00212  * @param extended true to use the extended descriptor (SURF 128)
00213  * @param indexSize Spatial size of the descriptor window (default 4)
00214 
00215  */
00216 SurfClassifier::SurfClassifier( std::string keypoints_dir, unsigned int min_match, float min_match_ratio,
00217                                 int samplingStep, int octaves, double thres,
00218                                 bool doubleImageSize, int initLobe,
00219                                 bool upright, bool extended, int indexSize ): Classifier("SurfClassifier")
00220 {
00221   __obj_features.clear();
00222   __obj_features.reserve(1000);
00223   // matching constraints
00224   __min_match = min_match;
00225   __min_match_ratio = min_match_ratio;
00226   // params for FastHessian
00227   __samplingStep = samplingStep;
00228   __octaves = octaves;
00229   __thres = thres;
00230   __doubleImageSize = doubleImageSize;
00231   __initLobe = initLobe;
00232   // params for Descriptors
00233   __upright = upright;
00234   __extended = extended;
00235   __indexSize = indexSize;
00236 
00237   // descriptor vector length
00238   __vlen = 0;
00239 
00240   //#ifdef SURF_TIMETRACKER
00241   __tt = new fawkes::TimeTracker();
00242   __loop_count = 0;
00243   __ttc_objconv = __tt->add_class("ObjectConvert");
00244   __ttc_objfeat = __tt->add_class("ObjectFeatures");
00245   __ttc_imgconv = __tt->add_class("ImageConvert");
00246   __ttc_imgfeat = __tt->add_class("ImageFeatures");
00247   __ttc_matchin = __tt->add_class("Matching");
00248   __ttc_roimerg = __tt->add_class("MergeROIs");
00249   //#endif
00250 
00251   //#ifdef SURF_TIMETRACKER
00252   __tt->ping_start(__ttc_objconv);
00253   //#endif
00254 
00255   DIR *dir = 0;
00256 
00257   if( (dir = opendir( keypoints_dir.c_str() ) ) == NULL ) {
00258           char* buffer = new char[256];
00259       sprintf(buffer, "The directory %s does not exist!", keypoints_dir.c_str() );
00260       fawkes::LibLogger::log_error("SurfClassifier",buffer);
00261   }
00262 
00263   struct dirent* ent;
00264   std::string object_file;
00265   int num_obj_index = 0;
00266 
00267 
00268   while( (ent = readdir(dir)) != NULL ) {
00269 
00270       if ( strcmp( ent->d_name, ".") == 0 || strcmp( ent->d_name,"..") == 0 || strcmp( ent->d_name,".svn") == 0 )
00271           continue;
00272 
00273       object_file = keypoints_dir + ent->d_name;
00274       std:: cout<<"SurfClassifier: reading the following descriptor file" << object_file << std::endl;
00275 
00276       __obj_names.push_back(object_file);
00277 
00278 
00279       bool b_verbose = BVERBOSE;
00280       loadIpoints( object_file, __obj_features[num_obj_index], b_verbose, __vlen);
00281       num_obj_index++;
00282 
00283     }
00284 
00285   closedir(dir);
00286   delete ent;
00287 
00288   __num_obj = num_obj_index;
00289 
00290   if( num_obj_index != 0 ) {
00291           std::cout<< "SurfClassifier: Reading successful"<< std::endl;
00292           //#ifdef SURF_TIMETRACKER
00293           __tt->ping_end(__ttc_objconv);
00294           //#endif
00295   }
00296   else {
00297 // if no objects were read, then the descriptor files were probably not created still. We can create them now!
00298           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;
00299           return new SurfClassifier( "../res/opx/objects/", 5 );
00300   }
00301 
00302 
00303   // save object image for debugging
00304   ///surf::ImLoad::saveImage( "obj.pgm", __obj_img);
00305 
00306   //#ifdef SURF_TIMETRACKER
00307   __tt->ping_start(__ttc_objfeat);
00308   //#endif
00309  //#ifdef SURF_TIMETRACKER
00310   __tt->ping_end(__ttc_objfeat);
00311   //#endif
00312 
00313 
00314 }
00315 
00316 
00317 
00318 
00319 
00320 /** Constructor.
00321  * @param object_dir file that contains an image of the object to detect
00322  * @param samplingStep Initial sampling step
00323  * @param min_match minimum number of features that have to be matched per ROI
00324  * @param min_match_ratio  minimum ratio of features matched per object to be matched per ROI
00325  * @param octaves Number of analysed octaves
00326  * @param thres Blob response treshold
00327  * @param doubleImageSize true to double the image size, false to keep original
00328  * @param initLobe Initial lobe size, default 3 and 5 (with double image size)
00329  * @param upright rotation invariance (fasle) or upright (true)
00330  * @param extended true to use the extended descriptor (SURF 128)
00331  * @param indexSize Spatial size of the descriptor window (default 4)
00332  */
00333 
00334 
00335 SurfClassifier::SurfClassifier( const char * object_dir,
00336                                 unsigned int min_match, float min_match_ratio,
00337                                 int samplingStep, int octaves, double thres,
00338                                 bool doubleImageSize, int initLobe,
00339                                 bool upright, bool extended, int indexSize)
00340   : Classifier("SurfClassifier")
00341 {
00342 
00343   __obj_features.clear();
00344   __obj_features.reserve(1000);
00345   // matching constraints
00346   __min_match = min_match;
00347   __min_match_ratio = min_match_ratio;
00348   // params for FastHessian
00349   __samplingStep = samplingStep;
00350   __octaves = octaves;
00351   __thres = thres;
00352   __doubleImageSize = doubleImageSize;
00353   __initLobe = initLobe;
00354   // params for Descriptors
00355   __upright = upright;
00356   __extended = extended;
00357   __indexSize = indexSize;
00358 
00359   // descriptor vector length
00360   __vlen = 0;
00361 
00362 
00363   //#ifdef SURF_TIMETRACKER
00364   __tt = new fawkes::TimeTracker();
00365   __loop_count = 0;
00366   __ttc_objconv = __tt->add_class("ObjectConvert");
00367   __ttc_objfeat = __tt->add_class("ObjectFeatures");
00368   __ttc_imgconv = __tt->add_class("ImageConvert");
00369   __ttc_imgfeat = __tt->add_class("ImageFeatures");
00370   __ttc_matchin = __tt->add_class("Matching");
00371   __ttc_roimerg = __tt->add_class("MergeROIs");
00372   //#endif
00373 
00374   //#ifdef SURF_TIMETRACKER
00375   __tt->ping_start(__ttc_objconv);
00376   //#endif
00377 
00378 
00379   DIR *dir = 0;
00380 
00381   std::string dir_path = object_dir;
00382 
00383   if( (dir = opendir( dir_path.c_str() ) ) == NULL )
00384     {
00385       char* buffer = new char[256];
00386       sprintf(buffer, "The directory %s does not exist!", dir_path.c_str() );
00387 
00388       fawkes::LibLogger::log_error("SurfClassifier",buffer);
00389     }
00390 
00391   struct dirent* ent;
00392   std::string object_file;
00393   int num_obj_index = 0;
00394 
00395   while( (ent = readdir(dir)) != NULL ) {
00396 
00397           if ( strcmp( ent->d_name, ".") == 0 || strcmp( ent->d_name,"..") == 0 || strcmp( ent->d_name,".svn") == 0)
00398                   continue;
00399 
00400           object_file = dir_path + ent->d_name;
00401 
00402 //       if( !object_file && strcmp( object_file, "" ) == 0 ) {
00403 //     throw fawkes::Exception("empty object file");
00404 //   }
00405 
00406   std::cout << "SurfClassifier(classify): opening object image file '" << object_file << "'" << std::endl;
00407 
00408   PNGReader pngr( object_file.c_str() );
00409   unsigned char* buf = malloc_buffer( pngr.colorspace(), pngr.pixel_width(), pngr.pixel_height() );
00410   pngr.set_buffer( buf );
00411   pngr.read();
00412 
00413   unsigned int lwidth = pngr.pixel_width();
00414   unsigned int lheight = pngr.pixel_height();
00415   surf::Image * __simage = new surf::Image( lwidth, lheight );
00416   for (unsigned int h = 0; h < lheight; ++h) {
00417     for (unsigned int w = 0; w < lwidth ; ++w) {
00418       __simage->setPix(w, h, (double)buf[h * lwidth + w] / 255.f);
00419     }
00420   }
00421   // make integral image
00422   __obj_img = new surf::Image(__simage, __doubleImageSize);
00423 
00424   // NOT WORKING
00425   //__obj_img = new surf::Image( pngr.pixel_width(), pngr.pixel_height());
00426   //__obj_img->setFrame( buf );
00427 
00428   if ( ! __obj_img ) {
00429     throw fawkes::Exception("Could not load object file '%s'", object_file.c_str());
00430   }
00431 
00432   //#ifdef SURF_TIMETRACKER
00433   __tt->ping_end(__ttc_objconv);
00434   //#endif
00435 
00436   // save object image for debugging
00437   ///surf::ImLoad::saveImage( "obj.pgm", __obj_img);
00438 
00439   //#ifdef SURF_TIMETRACKER
00440   __tt->ping_start(__ttc_objfeat);
00441   //#endif
00442 
00443   // COMPUTE OBJECT FEATURES
00444 
00445   std::vector<surf::Ipoint> obj_feature;
00446   __obj_features.push_back( obj_feature );
00447   __obj_features[num_obj_index].clear();
00448   __obj_features[num_obj_index].reserve(1000);
00449   __obj_num_features = 0;
00450   // Extract interest points with Fast-Hessian
00451   surf::FastHessian fh(__obj_img, /* pointer to integral image */
00452                        __obj_features[num_obj_index],
00453                        __thres, /* blob response threshold */
00454                        __doubleImageSize, /* double image size flag */
00455                        __initLobe * 3 /* 3 times lobe size equals the mask size */,
00456                        __samplingStep, /* subsample the blob response map */
00457                        __octaves /* number of octaves to be analysed */);
00458   // Extract them and get their pointer
00459   fh.getInterestPoints();
00460   // Initialise the SURF descriptor
00461   surf::Surf des(__obj_img, /* pointer to integral image */
00462                  __doubleImageSize, /* double image size flag */
00463                  __upright, /* rotation invariance or upright */
00464                  __extended, /* use the extended descriptor */
00465                  __indexSize /* square size of the descriptor window (default 4x4)*/);
00466   // Get the length of the descriptor vector
00467   // resulting from the parameters
00468   __vlen = des.getVectLength();
00469 
00470   //printf("vlen=%i\n", __vlen);
00471 
00472   // Compute the orientation and the descriptor for every interest point
00473   for (unsigned n=0; n < __obj_features[num_obj_index].size(); n++){
00474     // set the current interest point
00475     des.setIpoint(&(__obj_features.at(num_obj_index).at(n)));
00476     // assign reproducible orientation
00477     des.assignOrientation();
00478     // make the SURF descriptor
00479     des.makeDescriptor();
00480 
00481   }
00482 
00483 
00484   __obj_num_features = __obj_features[num_obj_index].size();
00485   if ( ! __obj_num_features > 0 ) {
00486     throw fawkes::Exception("Could not compute object features");
00487   }
00488   std::cout << "SurfClassifier(classify): computed '" << __obj_num_features << "' features from object" << std::endl;
00489 
00490   char buffer[256];
00491   sprintf( buffer, "descriptors/%s-%d.surf", ent->d_name, num_obj_index );
00492   std::string des_file_name = buffer;
00493 
00494   bool b_verbose = BVERBOSE;
00495   bool b_laplacian = true;
00496 
00497   __obj_names.push_back( des_file_name );
00498 
00499 
00500   // save descriptor
00501   saveIpoints( des_file_name, __obj_features[num_obj_index], b_verbose, b_laplacian, __vlen );
00502 
00503 
00504   // CleanUp
00505   delete __simage;
00506 
00507   //#ifdef SURF_TIMETRACKER
00508   __tt->ping_end(__ttc_objfeat);
00509   //#endif
00510 
00511   num_obj_index++;
00512     }
00513 
00514   __num_obj = num_obj_index;
00515 
00516 }
00517 
00518 
00519 /** Destructor. */
00520 SurfClassifier::~SurfClassifier()
00521 {
00522   //
00523 }
00524 
00525 
00526 std::list< ROI > *
00527 SurfClassifier::classify()
00528 {
00529 
00530   //  std::cout<<"SurfClassifier: Entering classification:-"<< std::endl;
00531   //#ifdef SURF_TIMETRACKER
00532   __tt->ping_start(0);
00533   //#endif
00534 
00535   // list of ROIs to return
00536 
00537   std::list<ROI> rv[__num_obj];
00538   float match_ratios[__num_obj];
00539 
00540 
00541   //  std::list< ROI > *rv = new std::list< ROI >();
00542 
00543   // for ROI calculation
00544   int x_min = _width;
00545   int y_min = _height;
00546   int x_max = 0;
00547   int y_max = 0;
00548 
00549   //#ifdef SURF_TIMETRACKER
00550   __tt->ping_start(__ttc_imgconv);
00551   //#endif
00552   std::cout << "SurfClassifier(classify): copy imgdat to SURF Image" << std::endl;
00553 
00554   /*
00555     // NOT WOKRING ALTERNATIVE
00556   double *tmpb = (double *)malloc(_width * _height * sizeof(double));
00557   for (unsigned int h = 0; h < _height; ++h) {
00558     for (unsigned int w = 0; w < _width; ++w) {
00559       tmpb[h * _width + w] = (double)_src[h * _width + w] / 255;
00560     }
00561   }
00562   __simage->setFrame( (unsigned char*)tmpb );
00563   //surf::ImLoad::saveImage( "stst.pgm", __simage);
00564   __image = new surf::Image(__simage, __doubleImageSize);
00565   //__image = new surf::Image( _width, _height);
00566   //__image->setFrame( (unsigned char *)tmpb );
00567   */
00568 
00569   surf::Image * __simage = new surf::Image( _width, _height);
00570   for (unsigned int h = 0; h < _height; ++h) {
00571     for (unsigned int w = 0; w < _width; ++w) {
00572       __simage->setPix(w, h, (double)_src[h * _width + w] / 255.f);
00573     }
00574   }
00575   // create integral image
00576   __image = new surf::Image(__simage, __doubleImageSize);
00577 
00578   //#ifdef SURF_TIMETRACKER
00579   __tt->ping_end(__ttc_imgconv);
00580   //#endif
00581 
00582 
00583   /*
00584     /// write pnm (with surf-routine) for debugging
00585     //surf::ImLoad::saveImage( "tst.pgm", __simage);
00586     /// write integral pnm (with surf-routine) for debugging
00587     //surf::ImLoad::saveImage( "tst.pgm", __image);
00588     /// write pgm (with fv-routine) for debugging
00589     PNMWriter pnm(PNM_PGM, "fvimg.pgm", _width, _height);
00590     pnm.set_buffer(YUV422_PLANAR, _src );
00591     pnm.write();
00592     /// write png (with fv-routine) for debugging
00593     PNGWriter pngw("fvimg.png", _width, _height);
00594     pngw.set_buffer(YUV422_PLANAR, _src );
00595     pngw.write();
00596   */
00597 
00598   //#ifdef SURF_TIMETRACKER
00599   __tt->ping_start(__ttc_imgfeat);
00600   //#endif
00601 
00602   // COMPUTE OBJECT FEATURES
00603   __img_features.clear();
00604   __img_features.reserve(1000);
00605   __img_num_features = 0;
00606   // Extract interest points with Fast-Hessian
00607   surf::FastHessian fh(__image, /* pointer to integral image */
00608                        __img_features,
00609                        __thres, /* blob response threshold */
00610                        __doubleImageSize, /* double image size flag */
00611                        __initLobe * 3 /* 3 times lobe size equals the mask size */,
00612                        __samplingStep, /* subsample the blob response map */
00613                        __octaves /* number of octaves to be analysed */);
00614   // Extract them and get their pointer
00615   std::cout<<"surfclassifer/classify : getting interest points"<<std::endl;
00616   fh.getInterestPoints();
00617   // Initialise the SURF descriptor
00618   surf::Surf des(__image, /* pointer to integral image */
00619                  __doubleImageSize, /* double image size flag */
00620                  __upright, /* rotation invariance or upright */
00621                  __extended, /* use the extended descriptor */
00622                  __indexSize /* square size of the descriptor window (default 4x4)*/);
00623   // Get the length of the descriptor vector
00624   // resulting from the parameters
00625   // NOT NEEDED HERE!
00626   //__vlen = des.getVectLength();
00627   //printf("img vlen=%i\n", __vlen);
00628 
00629   // Compute the orientation and the descriptor for every interest point
00630   for (unsigned n=0; n < __img_features.size(); n++){
00631     //for (Ipoint *k = ipts; k != NULL; k = k->next){
00632     // set the current interest point
00633     des.setIpoint(&__img_features[n]);
00634     // assign reproducible orientation
00635     des.assignOrientation();
00636     // make the SURF descriptor
00637     des.makeDescriptor();
00638   }
00639   __img_num_features = __img_features.size();
00640   //#ifdef SURF_TIMETRACKER
00641   __tt->ping_end(__ttc_imgfeat);
00642   //#endif
00643 
00644   std::cout << "Extracted '" << __img_num_features << "' image features" << std::endl;
00645 
00646 
00647   //#ifdef SURF_TIMETRACKER
00648   __tt->ping_start(__ttc_matchin);
00649   //#endif
00650   std::cout << "SurfClassifier(classify): matching ..." << std::endl;
00651 
00652   for( unsigned j = 0; j < __num_obj; j++ )
00653     {
00654       std::vector< int > matches(__obj_features[j].size());
00655       //      std::cout<< "SurfClassifier; _debug_ : " << __obj_features[j].size()  << "and" << __img_features.size() << std::endl;
00656       int c = 0;
00657       for (unsigned i = 0; i < __obj_features[j].size(); i++) {
00658         int match = findMatch((__obj_features[j])[i], __img_features);
00659         matches[i] = match;
00660         if (match != -1) {
00661           // std::cout << " Matched feature " << i << " in object image with feature " << match << " in image." << std::endl;
00662           /// adding feature-ROI
00663           ROI r( (int)(__img_features[matches[i]].x)-5, (int)(__img_features[matches[i]].y )-5, 11, 11, _width, _height);
00664           r.num_hint_points = 0;
00665           rv[j].push_back(r);
00666           /// increment feature-match-count
00667           ++c;
00668         }
00669       }
00670       //#ifdef SURF_TIMETRACKER
00671   __tt->ping_end(__ttc_matchin);
00672   //#endif
00673   if( c == 0 )
00674   std::cout << "SurfClassifier(classify) matched '" << c << fawkes::cnormal <<"' of '" << __obj_features[j].size() << "' features in scene. (for supplied object = " << j << std::endl ;
00675   else
00676   std::cout << "SurfClassifier(classify) matched '" << fawkes::cblue << c << fawkes::cnormal <<"' of '" << __obj_features[j].size() << "' features in scene. (for supplied object = " << j << std::endl ;
00677 
00678 
00679   float match_ratio = ((float)c / (float)__obj_features[j].size());
00680   match_ratios[j] = match_ratio;
00681 
00682   std::cout << "SurfClassifier(classify): match_ratio is '" << match_ratio << "' and min_match_ratio is" << __min_match_ratio << std::endl;
00683 
00684   std::cout << "SurfClassifier(classify): computing ROI" << std::endl;
00685   //#ifdef SURF_TIMETRACKER
00686   __tt->ping_start(__ttc_roimerg);
00687   //#endif
00688   for (unsigned i = 0; i < matches.size(); i++) {
00689     if (matches[i] != -1) {
00690       // //(int)__obj_features[i].x, (int)__obj_features[i].y
00691       //(int)__img_features[matches[i]].x, (int)(__img_features[matches[i]].y );
00692       if( (int)__img_features[matches[i]].x < x_min )
00693         x_min = (int)__img_features[matches[i]].x;
00694       if( (int)__img_features[matches[i]].y < y_min )
00695         y_min = (int)__img_features[matches[i]].y;
00696       if( (int)__img_features[matches[i]].x > x_max )
00697         x_max = (int)__img_features[matches[i]].x;
00698       if( (int)__img_features[matches[i]].y > y_max )
00699         y_max = (int)__img_features[matches[i]].y;
00700     }
00701   }
00702   if( (c != 0) && ((unsigned)c > __min_match) &&
00703       (match_ratio > __min_match_ratio) &&
00704       (x_max - x_min != 0 ) && (y_max - y_min != 0) ) {
00705 
00706     std::cout << "SurfClassifier(classify): c='" << c << "' __min_match='" << __min_match << "'." << std::endl;
00707 
00708     ROI r(x_min, y_min, x_max-x_min, y_max-y_min, _width, _height);
00709     r.num_hint_points = c;
00710     rv[j].push_back(r);
00711    } else {
00712     std::cout << " clearing ROI-list (no or too few matches or [0,0]-roi!)" << std::endl;
00713     rv[j].clear();
00714   }
00715     }
00716   //#ifdef SURF_TIMETRACKER
00717   __tt->ping_end(__ttc_roimerg);
00718   //#endif
00719 
00720   // CleanUp
00721   delete __image;
00722   delete __simage;
00723 
00724   //#ifdef SURF_TIMETRACKER
00725   __tt->ping_end(0);
00726   //#endif
00727 
00728   //#ifdef SURF_TIMETRACKER
00729   // print timetracker statistics
00730   //__tt->print_to_stdout();
00731   //#endif
00732 
00733 
00734   // histogram comparison of all rois and features detected
00735   float min_ratio_tmp = -1.0;
00736   int min_ratio_index = -1;
00737   for( unsigned int i = 0; i < __num_obj; i++ )
00738     {
00739       if( match_ratios[i] > min_ratio_tmp )
00740         {
00741           min_ratio_tmp = match_ratios[i];
00742           min_ratio_index = i;
00743         }
00744     }
00745 
00746   std::list<ROI> *final_rv = new std::list<ROI>;
00747 
00748   final_rv->assign( rv[min_ratio_index].begin(), rv[min_ratio_index].end() );
00749 
00750 
00751   std::string first_not(".-");
00752   int first_not_index = __obj_names[ min_ratio_index ].find_first_of( first_not );
00753   std::string obj_name_tmp( __obj_names[ min_ratio_index ] );
00754   obj_name_tmp.erase( first_not_index );
00755 
00756 
00757   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;
00758   return final_rv;
00759 }
00760 
00761 int
00762 SurfClassifier::findMatch(const surf::Ipoint& ip1, const std::vector< surf::Ipoint >& ipts) {
00763   double mind = 1e100, second = 1e100;
00764   int match = -1;
00765 
00766   //  std::cout<< "SurfClassifier/findMatch: " << ipts.size() <<" " << __vlen << std::endl;
00767 
00768   for (unsigned i = 0; i < ipts.size(); i++) {
00769     // Take advantage of Laplacian to speed up matching
00770     if (ipts[i].laplace != ip1.laplace)
00771       continue;
00772 
00773     double d = distSquare(ipts[i].ivec, ip1.ivec, __vlen);
00774 
00775     if (d < mind) {
00776       second = mind;
00777       mind = d;
00778       match = i;
00779     } else if (d < second) {
00780       second = d;
00781     }
00782   }
00783 
00784   if (mind < 0.5 * second)
00785     return match;
00786 
00787   return -1;
00788 }
00789 
00790 
00791 double
00792 SurfClassifier::distSquare(double *v1, double *v2, int n) {
00793   double dsq = 0.;
00794   //  std::cout<< fawkes::cblue << (*v1) << fawkes::cred << (*v2);
00795 
00796   while (n--) {
00797 
00798     dsq += (*v1 - *v2) * (*v1 - *v2);
00799     v1++;
00800     v2++;
00801   }
00802 
00803   //  std::cout << fawkes::cgreen << " "<<dsq << std::endl;
00804 
00805   return dsq;
00806 }
00807 
00808 } // end namespace firevision

Generated on Tue Feb 22 13:31:16 2011 for Fawkes API by  doxygen 1.4.7