00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <iostream>
00025 #include <vector>
00026
00027 #include <classifiers/surf.h>
00028 #include <math.h>
00029
00030 #include <utils/time/clock.h>
00031 #include <utils/time/tracker.h>
00032
00033 #include <fstream>
00034
00035 #include <string>
00036
00037 #include <surf/surflib.h>
00038
00039
00040
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
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 void saveIpoints(std::string sFileName, const std::vector< surf::Ipoint >& ipts, bool bVerbose, bool bLaplacian, int VLength)
00079 {
00080 std::cout<<"Attempting to save interest points" << std::endl;
00081
00082 std::ofstream ipfile(sFileName.c_str());
00083 if( !ipfile ) {
00084 std::cerr << "ERROR in loadIpoints(): "
00085 << "Couldn't open file '" << sFileName.c_str() << "'!" << std::endl;
00086 return;
00087 }
00088
00089 double sc;
00090 unsigned count = ipts.size();
00091
00092
00093 if (bLaplacian)
00094 ipfile << VLength + 1 << std::endl << count << std::endl;
00095 else
00096 ipfile << VLength << std::endl << count << std::endl;
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 for (unsigned n=0; n<ipts.size(); n++){
00108
00109 sc = 2.5 * ipts[n].scale; sc*=sc;
00110 ipfile << ipts[n].x
00111 << " " << ipts[n].y
00112 << " " << 1.0/sc
00113 << " " << 0.0
00114 << " " << 1.0/sc;
00115
00116 if (bLaplacian)
00117 ipfile << " " << ipts[n].laplace;
00118
00119
00120 for (int i = 0; i < VLength; i++) {
00121 ipfile << " " << ipts[n].ivec[i];
00122 }
00123 ipfile << std::endl;
00124 }
00125
00126
00127 if( bVerbose )
00128 std::cout << count << " interest points found" << std::endl;
00129 }
00130
00131
00132
00133
00134
00135
00136
00137 void loadIpoints( std::string sFileName, std::vector< surf::Ipoint >& ipts, bool bVerbose, int& __vlen )
00138 {
00139 std::ifstream ipfile(sFileName.c_str());
00140
00141 if( !ipfile ) {
00142 std::cerr << "ERROR in loadIpoints(): "
00143 << "Couldn't open file '" << sFileName.c_str() << "'!" << std::endl;
00144 return;
00145 }
00146
00147
00148
00149 unsigned count;
00150 ipfile >> __vlen >> count;
00151
00152 __vlen--;
00153
00154
00155 ipts.clear();
00156 ipts.resize(count);
00157
00158
00159 for (unsigned n=0; n<count; n++){
00160
00161 float x, y, a, b, c;
00162 ipfile >> x >> y >> a >> b >> c;
00163
00164 float det = sqrt((a-c)*(a-c) + 4.0*b*b);
00165 float e1 = 0.5*(a+c + det);
00166 float e2 = 0.5*(a+c - det);
00167 float l1 = (1.0/sqrt(e1));
00168 float l2 = (1.0/sqrt(e2));
00169 float sc = sqrt( l1*l2 );
00170
00171 ipts[n].x = x;
00172 ipts[n].y = y;
00173 ipts[n].scale = sc/2.5;
00174 ipfile >> ipts[n].laplace;
00175
00176
00177 ipts[n].ivec = new double[ __vlen];
00178
00179 for( int j = 0 ; j < __vlen; j++ )
00180 {
00181
00182 ipfile >> ipts[n].ivec[j];
00183
00184
00185 }
00186
00187 }
00188
00189
00190 ipfile.close();
00191
00192
00193 if( bVerbose )
00194 std::cout << "read in " << count << " interest points." << std::endl;
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 SurfClassifier::SurfClassifier( std::string keypoints_dir, unsigned int min_match, float min_match_ratio,
00212 int samplingStep, int octaves, double thres,
00213 bool doubleImageSize, int initLobe,
00214 bool upright, bool extended, int indexSize ): Classifier("SurfClassifier")
00215 {
00216 __obj_features.clear();
00217 __obj_features.reserve(1000);
00218
00219 __min_match = min_match;
00220 __min_match_ratio = min_match_ratio;
00221
00222 __samplingStep = samplingStep;
00223 __octaves = octaves;
00224 __thres = thres;
00225 __doubleImageSize = doubleImageSize;
00226 __initLobe = initLobe;
00227
00228 __upright = upright;
00229 __extended = extended;
00230 __indexSize = indexSize;
00231
00232
00233 __vlen = 0;
00234
00235
00236 __tt = new fawkes::TimeTracker();
00237 __loop_count = 0;
00238 __ttc_objconv = __tt->add_class("ObjectConvert");
00239 __ttc_objfeat = __tt->add_class("ObjectFeatures");
00240 __ttc_imgconv = __tt->add_class("ImageConvert");
00241 __ttc_imgfeat = __tt->add_class("ImageFeatures");
00242 __ttc_matchin = __tt->add_class("Matching");
00243 __ttc_roimerg = __tt->add_class("MergeROIs");
00244
00245
00246
00247 __tt->ping_start(__ttc_objconv);
00248
00249
00250 DIR *dir = 0;
00251
00252 if( (dir = opendir( keypoints_dir.c_str() ) ) == NULL ) {
00253 char* buffer = new char[256];
00254 sprintf(buffer, "The directory %s does not exist!", keypoints_dir.c_str() );
00255 fawkes::LibLogger::log_error("SurfClassifier",buffer);
00256 }
00257
00258 struct dirent* ent;
00259 std::string object_file;
00260 int num_obj_index = 0;
00261
00262
00263 while( (ent = readdir(dir)) != NULL ) {
00264
00265 if ( strcmp( ent->d_name, ".") == 0 || strcmp( ent->d_name,"..") == 0 || strcmp( ent->d_name,".svn") == 0 )
00266 continue;
00267
00268 object_file = keypoints_dir + ent->d_name;
00269 std:: cout<<"SurfClassifier: reading the following descriptor file" << object_file << std::endl;
00270
00271 __obj_names.push_back(object_file);
00272
00273
00274 bool b_verbose = BVERBOSE;
00275 loadIpoints( object_file, __obj_features[num_obj_index], b_verbose, __vlen);
00276 num_obj_index++;
00277
00278 }
00279
00280 closedir(dir);
00281 delete ent;
00282
00283 __num_obj = num_obj_index;
00284
00285 if( num_obj_index != 0 ) {
00286 std::cout<< "SurfClassifier: Reading successful"<< std::endl;
00287
00288 __tt->ping_end(__ttc_objconv);
00289
00290 }
00291 else {
00292
00293 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;
00294 return new SurfClassifier( "../res/opx/objects/", 5 );
00295 }
00296
00297
00298
00299
00300
00301
00302 __tt->ping_start(__ttc_objfeat);
00303
00304
00305 __tt->ping_end(__ttc_objfeat);
00306
00307
00308
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 SurfClassifier::SurfClassifier( const char * object_dir,
00331 unsigned int min_match, float min_match_ratio,
00332 int samplingStep, int octaves, double thres,
00333 bool doubleImageSize, int initLobe,
00334 bool upright, bool extended, int indexSize)
00335 : Classifier("SurfClassifier")
00336 {
00337
00338 __obj_features.clear();
00339 __obj_features.reserve(1000);
00340
00341 __min_match = min_match;
00342 __min_match_ratio = min_match_ratio;
00343
00344 __samplingStep = samplingStep;
00345 __octaves = octaves;
00346 __thres = thres;
00347 __doubleImageSize = doubleImageSize;
00348 __initLobe = initLobe;
00349
00350 __upright = upright;
00351 __extended = extended;
00352 __indexSize = indexSize;
00353
00354
00355 __vlen = 0;
00356
00357
00358
00359 __tt = new fawkes::TimeTracker();
00360 __loop_count = 0;
00361 __ttc_objconv = __tt->add_class("ObjectConvert");
00362 __ttc_objfeat = __tt->add_class("ObjectFeatures");
00363 __ttc_imgconv = __tt->add_class("ImageConvert");
00364 __ttc_imgfeat = __tt->add_class("ImageFeatures");
00365 __ttc_matchin = __tt->add_class("Matching");
00366 __ttc_roimerg = __tt->add_class("MergeROIs");
00367
00368
00369
00370 __tt->ping_start(__ttc_objconv);
00371
00372
00373
00374 DIR *dir = 0;
00375
00376 std::string dir_path = object_dir;
00377
00378 if( (dir = opendir( dir_path.c_str() ) ) == NULL )
00379 {
00380 char* buffer = new char[256];
00381 sprintf(buffer, "The directory %s does not exist!", dir_path.c_str() );
00382
00383 fawkes::LibLogger::log_error("SurfClassifier",buffer);
00384 }
00385
00386 struct dirent* ent;
00387 std::string object_file;
00388 int num_obj_index = 0;
00389
00390 while( (ent = readdir(dir)) != NULL ) {
00391
00392 if ( strcmp( ent->d_name, ".") == 0 || strcmp( ent->d_name,"..") == 0 || strcmp( ent->d_name,".svn") == 0)
00393 continue;
00394
00395 object_file = dir_path + ent->d_name;
00396
00397
00398
00399
00400
00401 std::cout << "SurfClassifier(classify): opening object image file '" << object_file << "'" << std::endl;
00402
00403 PNGReader pngr( object_file.c_str() );
00404 unsigned char* buf = malloc_buffer( pngr.colorspace(), pngr.pixel_width(), pngr.pixel_height() );
00405 pngr.set_buffer( buf );
00406 pngr.read();
00407
00408 unsigned int lwidth = pngr.pixel_width();
00409 unsigned int lheight = pngr.pixel_height();
00410 surf::Image * __simage = new surf::Image( lwidth, lheight );
00411 for (unsigned int h = 0; h < lheight; ++h) {
00412 for (unsigned int w = 0; w < lwidth ; ++w) {
00413 __simage->setPix(w, h, (double)buf[h * lwidth + w] / 255.f);
00414 }
00415 }
00416
00417 __obj_img = new surf::Image(__simage, __doubleImageSize);
00418
00419
00420
00421
00422
00423 if ( ! __obj_img ) {
00424 throw fawkes::Exception("Could not load object file '%s'", object_file.c_str());
00425 }
00426
00427
00428 __tt->ping_end(__ttc_objconv);
00429
00430
00431
00432
00433
00434
00435 __tt->ping_start(__ttc_objfeat);
00436
00437
00438
00439
00440 std::vector<surf::Ipoint> obj_feature;
00441 __obj_features.push_back( obj_feature );
00442 __obj_features[num_obj_index].clear();
00443 __obj_features[num_obj_index].reserve(1000);
00444 __obj_num_features = 0;
00445
00446 surf::FastHessian fh(__obj_img,
00447 __obj_features[num_obj_index],
00448 __thres,
00449 __doubleImageSize,
00450 __initLobe * 3 ,
00451 __samplingStep,
00452 __octaves );
00453
00454 fh.getInterestPoints();
00455
00456 surf::Surf des(__obj_img,
00457 __doubleImageSize,
00458 __upright,
00459 __extended,
00460 __indexSize );
00461
00462
00463 __vlen = des.getVectLength();
00464
00465
00466
00467
00468 for (unsigned n=0; n < __obj_features[num_obj_index].size(); n++){
00469
00470 des.setIpoint(&(__obj_features.at(num_obj_index).at(n)));
00471
00472 des.assignOrientation();
00473
00474 des.makeDescriptor();
00475
00476 }
00477
00478
00479 __obj_num_features = __obj_features[num_obj_index].size();
00480 if ( ! __obj_num_features > 0 ) {
00481 throw fawkes::Exception("Could not compute object features");
00482 }
00483 std::cout << "SurfClassifier(classify): computed '" << __obj_num_features << "' features from object" << std::endl;
00484
00485 char buffer[256];
00486 sprintf( buffer, "descriptors/%s-%d.surf", ent->d_name, num_obj_index );
00487 std::string des_file_name = buffer;
00488
00489 bool b_verbose = BVERBOSE;
00490 bool b_laplacian = true;
00491
00492 __obj_names.push_back( des_file_name );
00493
00494
00495
00496 saveIpoints( des_file_name, __obj_features[num_obj_index], b_verbose, b_laplacian, __vlen );
00497
00498
00499
00500 delete __simage;
00501
00502
00503 __tt->ping_end(__ttc_objfeat);
00504
00505
00506 num_obj_index++;
00507 }
00508
00509 __num_obj = num_obj_index;
00510
00511 }
00512
00513
00514
00515 SurfClassifier::~SurfClassifier()
00516 {
00517
00518 }
00519
00520
00521 std::list< ROI > *
00522 SurfClassifier::classify()
00523 {
00524
00525
00526
00527 __tt->ping_start(0);
00528
00529
00530
00531
00532 std::list<ROI> rv[__num_obj];
00533 float match_ratios[__num_obj];
00534
00535
00536
00537
00538
00539 int x_min = _width;
00540 int y_min = _height;
00541 int x_max = 0;
00542 int y_max = 0;
00543
00544
00545 __tt->ping_start(__ttc_imgconv);
00546
00547 std::cout << "SurfClassifier(classify): copy imgdat to SURF Image" << std::endl;
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 surf::Image * __simage = new surf::Image( _width, _height);
00565 for (unsigned int h = 0; h < _height; ++h) {
00566 for (unsigned int w = 0; w < _width; ++w) {
00567 __simage->setPix(w, h, (double)_src[h * _width + w] / 255.f);
00568 }
00569 }
00570
00571 __image = new surf::Image(__simage, __doubleImageSize);
00572
00573
00574 __tt->ping_end(__ttc_imgconv);
00575
00576
00577
00578
00579
00580 //surf::ImLoad::saveImage( "tst.pgm", __simage);
00581
00582 //surf::ImLoad::saveImage( "tst.pgm", __image);
00583
00584 PNMWriter pnm(PNM_PGM, "fvimg.pgm", _width, _height);
00585 pnm.set_buffer(YUV422_PLANAR, _src );
00586 pnm.write();
00587
00588 PNGWriter pngw("fvimg.png", _width, _height);
00589 pngw.set_buffer(YUV422_PLANAR, _src );
00590 pngw.write();
00591 */
00592
00593
00594 __tt->ping_start(__ttc_imgfeat);
00595
00596
00597
00598 __img_features.clear();
00599 __img_features.reserve(1000);
00600 __img_num_features = 0;
00601
00602 surf::FastHessian fh(__image,
00603 __img_features,
00604 __thres,
00605 __doubleImageSize,
00606 __initLobe * 3 ,
00607 __samplingStep,
00608 __octaves );
00609
00610 std::cout<<"surfclassifer/classify : getting interest points"<<std::endl;
00611 fh.getInterestPoints();
00612
00613 surf::Surf des(__image,
00614 __doubleImageSize,
00615 __upright,
00616 __extended,
00617 __indexSize );
00618
00619
00620
00621
00622
00623
00624
00625 for (unsigned n=0; n < __img_features.size(); n++){
00626
00627
00628 des.setIpoint(&__img_features[n]);
00629
00630 des.assignOrientation();
00631
00632 des.makeDescriptor();
00633 }
00634 __img_num_features = __img_features.size();
00635
00636 __tt->ping_end(__ttc_imgfeat);
00637
00638
00639 std::cout << "Extracted '" << __img_num_features << "' image features" << std::endl;
00640
00641
00642
00643 __tt->ping_start(__ttc_matchin);
00644
00645 std::cout << "SurfClassifier(classify): matching ..." << std::endl;
00646
00647 for( unsigned j = 0; j < __num_obj; j++ )
00648 {
00649 std::vector< int > matches(__obj_features[j].size());
00650
00651 int c = 0;
00652 for (unsigned i = 0; i < __obj_features[j].size(); i++) {
00653 int match = findMatch((__obj_features[j])[i], __img_features);
00654 matches[i] = match;
00655 if (match != -1) {
00656
00657
00658 ROI r( (int)(__img_features[matches[i]].x)-5, (int)(__img_features[matches[i]].y )-5, 11, 11, _width, _height);
00659 r.num_hint_points = 0;
00660 rv[j].push_back(r);
00661
00662 ++c;
00663 }
00664 }
00665
00666 __tt->ping_end(__ttc_matchin);
00667
00668 if( c == 0 )
00669 std::cout << "SurfClassifier(classify) matched '" << c << fawkes::cnormal <<"' of '" << __obj_features[j].size() << "' features in scene. (for supplied object = " << j << std::endl ;
00670 else
00671 std::cout << "SurfClassifier(classify) matched '" << fawkes::cblue << c << fawkes::cnormal <<"' of '" << __obj_features[j].size() << "' features in scene. (for supplied object = " << j << std::endl ;
00672
00673
00674 float match_ratio = ((float)c / (float)__obj_features[j].size());
00675 match_ratios[j] = match_ratio;
00676
00677 std::cout << "SurfClassifier(classify): match_ratio is '" << match_ratio << "' and min_match_ratio is" << __min_match_ratio << std::endl;
00678
00679 std::cout << "SurfClassifier(classify): computing ROI" << std::endl;
00680
00681 __tt->ping_start(__ttc_roimerg);
00682
00683 for (unsigned i = 0; i < matches.size(); i++) {
00684 if (matches[i] != -1) {
00685
00686
00687 if( (int)__img_features[matches[i]].x < x_min )
00688 x_min = (int)__img_features[matches[i]].x;
00689 if( (int)__img_features[matches[i]].y < y_min )
00690 y_min = (int)__img_features[matches[i]].y;
00691 if( (int)__img_features[matches[i]].x > x_max )
00692 x_max = (int)__img_features[matches[i]].x;
00693 if( (int)__img_features[matches[i]].y > y_max )
00694 y_max = (int)__img_features[matches[i]].y;
00695 }
00696 }
00697 if( (c != 0) && ((unsigned)c > __min_match) &&
00698 (match_ratio > __min_match_ratio) &&
00699 (x_max - x_min != 0 ) && (y_max - y_min != 0) ) {
00700
00701 std::cout << "SurfClassifier(classify): c='" << c << "' __min_match='" << __min_match << "'." << std::endl;
00702
00703 ROI r(x_min, y_min, x_max-x_min, y_max-y_min, _width, _height);
00704 r.num_hint_points = c;
00705 rv[j].push_back(r);
00706 } else {
00707 std::cout << " clearing ROI-list (no or too few matches or [0,0]-roi!)" << std::endl;
00708 rv[j].clear();
00709 }
00710 }
00711
00712 __tt->ping_end(__ttc_roimerg);
00713
00714
00715
00716 delete __image;
00717 delete __simage;
00718
00719
00720 __tt->ping_end(0);
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730 float min_ratio_tmp = -1.0;
00731 int min_ratio_index = -1;
00732 for( unsigned int i = 0; i < __num_obj; i++ )
00733 {
00734 if( match_ratios[i] > min_ratio_tmp )
00735 {
00736 min_ratio_tmp = match_ratios[i];
00737 min_ratio_index = i;
00738 }
00739 }
00740
00741 std::list<ROI> *final_rv = new std::list<ROI>;
00742
00743 final_rv->assign( rv[min_ratio_index].begin(), rv[min_ratio_index].end() );
00744
00745
00746 std::string first_not(".-");
00747 int first_not_index = __obj_names[ min_ratio_index ].find_first_of( first_not );
00748 std::string obj_name_tmp( __obj_names[ min_ratio_index ] );
00749 obj_name_tmp.erase( first_not_index );
00750
00751
00752 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;
00753 return final_rv;
00754 }
00755
00756 int
00757 SurfClassifier::findMatch(const surf::Ipoint& ip1, const std::vector< surf::Ipoint >& ipts) {
00758 double mind = 1e100, second = 1e100;
00759 int match = -1;
00760
00761
00762
00763 for (unsigned i = 0; i < ipts.size(); i++) {
00764
00765 if (ipts[i].laplace != ip1.laplace)
00766 continue;
00767
00768 double d = distSquare(ipts[i].ivec, ip1.ivec, __vlen);
00769
00770 if (d < mind) {
00771 second = mind;
00772 mind = d;
00773 match = i;
00774 } else if (d < second) {
00775 second = d;
00776 }
00777 }
00778
00779 if (mind < 0.5 * second)
00780 return match;
00781
00782 return -1;
00783 }
00784
00785
00786 double
00787 SurfClassifier::distSquare(double *v1, double *v2, int n) {
00788 double dsq = 0.;
00789
00790
00791 while (n--) {
00792
00793 dsq += (*v1 - *v2) * (*v1 - *v2);
00794 v1++;
00795 v2++;
00796 }
00797
00798
00799
00800 return dsq;
00801 }