Fawkes API
Fawkes Development Version
|
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