Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

sift-driver.cc

Go to the documentation of this file.
00001 // file:        sift-driver.cpp
00002 // author:      Andrea Vedaldi
00003 // description: SIFT command line utility implementation
00004 
00005 // AUTORIGTHS
00006 
00007 #include "sift.hpp"
00008 #include "sift-driver.hpp"
00009 
00010 #include<string>
00011 #include<iostream>
00012 #include<iomanip>
00013 #include<fstream>
00014 #include<sstream>
00015 #include<algorithm>
00016 #include <memory>
00017 #include <stdint.h>
00018 
00019 extern "C" {
00020 #include<getopt.h>
00021 #if defined (VL_MAC)
00022 #include<libgen.h>
00023 #else
00024 #include<string.h>
00025 #endif
00026 #include<assert.h>
00027 }
00028 
00029 #include "libgen_emu.h"
00030 
00031 #ifndef no_argument
00032 #define no_argument NO_ARG
00033 #endif
00034 #ifndef required_argument
00035 #define required_argument REQUIRED_ARG
00036 #endif
00037 
00038 using namespace std ;
00039 
00040 size_t const not_found = numeric_limits<size_t>::max() - 1 ;
00041 
00042 /** @brief Case insensitive character comparison
00043  **
00044  ** This predicate returns @c true if @a a and @a b are equal up to
00045  ** case.
00046  **
00047  ** @return predicate value.
00048  **/
00049 inline
00050 bool ciIsEqual(char a, char b)
00051 {
00052   return 
00053     tolower((char unsigned)a) == 
00054     tolower((char unsigned)b) ;
00055 }
00056 
00057 /** @brief Case insensitive extension removal
00058  **
00059  ** The function returns @a name with the suffix $a ext removed.  The
00060  ** suffix is matched case-insensitve.
00061  **
00062  ** @return @a name without @a ext.
00063  **/
00064 string
00065 removeExtension(string name, string ext)
00066 {
00067   string::iterator pos = 
00068     find_end(name.begin(),name.end(),ext.begin(),ext.end(),ciIsEqual) ;
00069 
00070   // make sure the occurence is at the end
00071   if(pos+ext.size() == name.end()) {
00072     return name.substr(0, pos-name.begin()) ;
00073   } else {
00074     return name ;
00075   }
00076 }
00077 
00078 
00079 /** @brief Insert descriptor into stream
00080  **
00081  ** The function writes a descriptor in ASCII/binary format
00082  ** and in integer/floating point format into the stream.
00083  **
00084  ** @param os output stream.
00085  ** @param descr_pt descriptor (floating point)
00086  ** @param binary write binary descriptor?
00087  ** @param fp write floating point data?
00088  **/
00089 std::ostream&
00090 insertDescriptor(std::ostream& os,
00091                  VL::float_t const * descr_pt,
00092                  bool binary,
00093                  bool fp,
00094                  int* numKeypoints,
00095                  vector<double>* keyValues,
00096                  bool outGood)
00097 {
00098         (*numKeypoints)++;
00099 
00100 #define RAW_CONST_PT(x) reinterpret_cast<char const*>(x)
00101 #define RAW_PT(x)       reinterpret_cast<char*>(x)
00102 
00103   if( fp ) {
00104 
00105     /* convert to 32 bits floats (single precision) */
00106     VL::float32_t fdescr_pt [128] ;
00107     for(int i = 0 ; i < 128 ; ++i){
00108       fdescr_pt[i] = VL::float32_t( descr_pt[i]) ;
00109       keyValues->push_back((double)(fdescr_pt[i]));
00110     }
00111 
00112     if( binary ) {
00113       /* 
00114          Test for endianess. Recall: big_endian = the most significant
00115          byte at lower memory address.
00116       */
00117       short int const word = 0x0001 ;
00118       bool little_endian = RAW_CONST_PT(&word)[0] ;
00119       
00120       /* 
00121          We save in big-endian (network) order. So if this machine is
00122          little endiand do the appropriate conversion.
00123       */
00124       if( little_endian ) {
00125         for(int i = 0 ; i < 128 ; ++i) {
00126           VL::float32_t tmp = fdescr_pt[ i ] ;        
00127           char* pt  = RAW_PT(fdescr_pt + i) ;
00128           char* spt = RAW_PT(&tmp) ;
00129           pt[0] = spt[3] ;
00130           pt[1] = spt[2] ;
00131           pt[2] = spt[1] ;
00132           pt[3] = spt[0] ;
00133         }
00134       }            
00135       if (outGood) os.write( RAW_PT(fdescr_pt), 128 * sizeof(VL::float32_t) ) ;
00136 
00137     } else {
00138 
00139       if (outGood)
00140       for(int i = 0 ; i < 128 ; ++i) 
00141         os << ' ' 
00142            << fdescr_pt[i] ;
00143     }
00144 
00145   } else {
00146 
00147     VL::uint8_t idescr_pt [128] ;
00148 
00149     for(int i = 0 ; i < 128 ; ++i){
00150       idescr_pt[i] = uint8_t(float_t(512) * descr_pt[i]) ;
00151       keyValues->push_back((double)(idescr_pt[i]));
00152     }
00153     
00154     if( binary ) {
00155 
00156       if (outGood) os.write( RAW_PT(idescr_pt), 128) ;        
00157 
00158     } else { 
00159       if (outGood)
00160       for(int i = 0 ; i < 128 ; ++i) 
00161         os << ' ' 
00162            << uint32_t( idescr_pt[i] ) ;
00163     }
00164   }
00165   return os ;
00166 }
00167 
00168 std::ostream&
00169 insertDescriptor(std::ostream& os,
00170                  VL::float_t const * descr_pt,
00171                  bool binary,
00172                  bool fp,
00173                  int* numKeypoints,
00174                  vector<double>* keyValues)
00175 {
00176   return insertDescriptor(os, descr_pt, binary, fp, numKeypoints, keyValues, true);
00177 }
00178 
00179 /* keypoint list */
00180 typedef vector<pair<VL::Sift::Keypoint,VL::float_t> > Keypoints ;
00181 
00182 /* predicate used to order keypoints by increasing scale */
00183 bool cmpKeypoints (Keypoints::value_type const&a,
00184                    Keypoints::value_type const&b) {
00185   return a.first.sigma < b.first.sigma ;
00186 }
00187 
00188 // -------------------------------------------------------------------
00189 //                                                                main
00190 // -------------------------------------------------------------------
00191 VL::Sift*
00192 siftdriver(int argc, char** argv, int* numKeypoints, vector<double>* keyValues, vector< vector< vector<int> > >& gaussianSpace)
00193 {
00194   return siftdriver(argc, argv, numKeypoints, keyValues, gaussianSpace, NULL, 0, 0);
00195 }
00196 
00197 VL::Sift*
00198 siftdriver(int argc, char** argv, int* numKeypoints, vector<double>* keyValues, vector< vector< vector<int> > >& gaussianSpace, VL::pixel_t* data, int width, int height)
00199 {
00200 //   for (int i = 0; i < argc; i++){
00201 //     cout << "SIFT++ input: " << argv[i] << endl;
00202 //   }
00203         if (numKeypoints) *numKeypoints = 0;
00204 
00205         VL::Sift* sift = NULL;
00206 
00207   int    first          = -1 ;
00208   int    octaves        = -1 ;
00209   int    levels         = 3 ;
00210   float  threshold      = 0.04f / levels / 2.0f ;
00211   float  edgeThreshold  = 10.0f;
00212   float  magnif         = 1.5f ;
00213   int    nodescr        = 0 ;
00214   int    noorient       = 0 ;
00215   int    stableorder    = 0 ;
00216   int    savegss        = 0 ;
00217   int    verbose        = 0 ;
00218   int    binary         = 0 ;
00219   int    haveKeypoints  = 0 ;
00220   int    unnormalized   = 0 ;
00221   int    fp             = 0 ;
00222   /** Added new variable and argument flag to indicate to read from pixel_t array instead of file
00223       By Xinghao Pan on 14 Aug 08
00224   **/
00225   int imageProvided     = 0;
00226   string outputFilenamePrefix ;
00227   string outputFilename ;
00228   string descriptorsFilename ;
00229   string keypointsFilename ;
00230 
00231   struct option longopts[] = {
00232     { "verbose",         no_argument,            NULL,              'v' },
00233     { "help",            no_argument,            NULL,              'h' },
00234     { "output",          required_argument,      NULL,              'o' },
00235     { "prefix",          required_argument,      NULL,              'p' },
00236     { "first-octave",    required_argument,      NULL,              'f' },
00237     { "keypoints",       required_argument,      NULL,              'k' },
00238     { "octaves",         required_argument,      NULL,              'O' },
00239     { "levels",          required_argument,      NULL,              'S' },
00240     { "threshold",       required_argument,      NULL,              't' },
00241     { "edge-threshold",  required_argument,      NULL,              'e' },
00242     { "magnif",          required_argument,      NULL,              'm' },
00243     { "binary",          no_argument,            NULL,              'b' }, 
00244     { "no-descriptors",  no_argument,            &nodescr,          1   },
00245     { "no-orientations", no_argument,            &noorient,         1   },
00246     { "stable-order",    no_argument,            &stableorder,      1   },
00247     { "save-gss",        no_argument,            &savegss,          1   },
00248     { "unnormalized",    no_argument,            &unnormalized,     1   },
00249     { "floating-point",  no_argument,            &fp,               1   },
00250     { "image-provided",  no_argument,            &imageProvided,    1   },
00251     { NULL,              0,                      NULL,              0   }
00252   };
00253   
00254   int ch ;
00255 
00256   try {
00257     optind = 0;
00258     opterr = 1;
00259     while ( (ch = getopt_long(argc, argv, "vho:p:f:k:O:S:t:e:b", longopts, NULL)) != -1 ) {
00260       switch (ch) {
00261 
00262       case '?' :
00263         VL_THROW("Invalid option '"<<argv[optind-1]<<"'.") ;
00264         std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
00265         break;
00266         
00267       case ':' :
00268         VL_THROW("Missing argument of option '"<<argv[optind-1]<<"'.") ;
00269         break;
00270         
00271       case 'h' :
00272         std::cout
00273           << argv[0] << " [--verbose|=v] [--help|-h]" << endl
00274           << "     [--output|-o NAME] [--prefix|-p PREFIX] [--binary|-b] [--save-gss] " << endl
00275           << "     [--no-descriptors] [--no-orientations] " << endl
00276           << "     [--levels|-S NUMBER] [--octaves|-O NUMBER] [--first-octave|-f NUMBER] " << endl
00277           << "     [--threshold|-t NUMBER] [--edge-threshold|-e NUMBER] " << endl
00278           << "     [--floating-point] [--unnormalized] " << endl
00279           << "     IMAGE [IMAGE2 ...]" << endl
00280           << endl
00281           << "* Options *" << endl
00282           << " --verbose             Be verbose"<< endl
00283           << " --help                Print this message"<<endl
00284           << " --output=NAME         Write to this file"<<endl
00285           << " --prefix=PREFIX       Derive output filename prefixing this string to the input file"<<endl
00286           << " --binary              Write descriptors to a separate file in binary format"<<endl
00287           << " --keypoints=FILE      Reads keypoint frames from here; do not run SIFT detector" << endl
00288           << " --save-gss            Save Gaussian scale space on disk" << endl
00289           << " --octaves=O           Number of octaves" << endl
00290           << " --levels=S            Number of levels per octave" << endl
00291           << " --first-octave=MINO   Index of the first octave" << endl
00292           << " --threshold=THR       Keypoint strength threhsold" << endl
00293           << " --magnif=MAG          Keypoint magnification" << endl
00294           << " --edge-threshold=THR  On-edge threshold" << endl 
00295           << " --no-descriptors      Do not compute descriptors" << endl
00296           << " --no-orientations     Do not compute orientations" << endl
00297           << " --stable-order        Do not reorder keypoints" << endl
00298           << " --unnormalzied        Do not normalize descriptors" << endl
00299           << " --floating-point      Save floating point descriptors" << endl
00300           << endl
00301           << " * Examples *" << endl
00302           << argv[0] << " [OPTS...] image.pgm" << endl
00303           << argv[0] << " [OPTS...] image.pgm --output=file.key" << endl
00304           << argv[0] << " [OPTS...] image.pgm --keypoints=frames.key" << endl
00305           << argv[0] << " [OPTS...] *.pgm --prefix=/tmp/" << endl
00306           << argv[0] << " [OPTS...] *.pgm --prefix=/tmp/ --binary" << endl
00307           << endl
00308           << " * This build: " ;
00309 #if defined VL_USEFASTMATH
00310         std::cout << "has fast approximate math" ;
00311 #else
00312         std::cout << "has slow accurate math" ;
00313 #endif
00314         std::cout << " (fp datatype is '"
00315                   << VL_EXPAND_AND_STRINGIFY(VL_FASTFLOAT)
00316                   << "') *"<<endl ;
00317         return NULL ;
00318         
00319       case 'v' : // verbose
00320         verbose = 1 ;
00321         break ;
00322         
00323       case 'f': // first octave
00324         {
00325           std::istringstream iss(optarg) ;
00326           iss >> first ;
00327           if( iss.fail() )
00328             VL_THROW("Invalid argument '" << optarg << "'.") ;
00329         }
00330         break ;
00331         
00332       case 'O' : // octaves
00333         {
00334           std::istringstream iss(optarg) ;
00335           iss >> octaves ;
00336           if( iss.fail() )
00337             VL_THROW("Invalid argument '" << optarg << "'.") ;
00338           if( octaves < 1 ) {
00339             VL_THROW("The number of octaves cannot be smaller than one."); 
00340           }
00341         }
00342         break ;
00343         
00344       case 'S' : // levels
00345         {
00346           std::istringstream iss(optarg) ;
00347           iss >> levels ;
00348           if( iss.fail() )
00349             VL_THROW("Invalid argument '" << optarg << "'.") ;
00350           if( levels < 1 ) {
00351             VL_THROW("The number of levels cannot be smaller than one.") ;
00352           }
00353         }      
00354         break ;
00355 
00356       case 't' : // threshold
00357         {
00358           std::istringstream iss(optarg) ;
00359           iss >> threshold ;
00360           if( iss.fail() )
00361             VL_THROW("Invalid argument '" << optarg << "'.") ;
00362         }
00363         break ;
00364 
00365       case 'e' : // edge-threshold
00366         {
00367           std::istringstream iss(optarg) ;
00368           iss >> edgeThreshold ;
00369           if( iss.fail() )
00370             VL_THROW("Invalid argument '" << optarg << "'.") ;
00371         }
00372         break ;
00373 
00374       case 'm' : // magnification
00375         {
00376           std::istringstream iss(optarg) ;
00377           iss >> magnif ;
00378           if( iss.fail() )
00379             VL_THROW("Invalid argument '" << optarg << "'.") ;
00380         }
00381         break ;
00382 
00383 
00384       case 'o' : // output filename
00385         {
00386           outputFilename = std::string(optarg) ;
00387           break ;
00388         }
00389 
00390       case 'p' : // output prefix
00391         {
00392           outputFilenamePrefix = std::string(optarg) ;
00393           break ;
00394         }
00395 
00396       case 'k' : // keypoint file
00397         {
00398           keypointsFilename = std::string(optarg) ;
00399           haveKeypoints = 1 ;
00400           break ;
00401         }
00402 
00403       case 'b' : // write descriptors to a binary file
00404         {
00405           binary = 1 ;
00406           break ;
00407         }
00408 
00409       case 0 : // all other options
00410         break ;
00411         
00412       default:
00413         assert(false) ;
00414       }
00415     }
00416     
00417     argc -= optind;
00418     argv += optind;
00419 
00420     // check for argument consistency
00421     if(argc == 0) VL_THROW("No input image specfied.") ;
00422     if(outputFilename.size() != 0 && ((argc > 1) | binary)) {
00423       VL_THROW("--output cannot be used with multiple images or --binary.") ;
00424     }
00425 
00426     if(outputFilename.size() !=0 && 
00427        outputFilenamePrefix.size() !=0) {
00428       VL_THROW("--output cannot be used in combination with --prefix.") ;
00429     }
00430 
00431     /* end option try-catch block */
00432   }  
00433   catch( VL::Exception const & e ) {
00434     cerr << "siftpp: error: "
00435          << e.msg 
00436          << endl ;
00437     return NULL ;
00438   } 
00439 
00440   // -----------------------------------------------------------------
00441   //                                            Loop over input images
00442   // -----------------------------------------------------------------      
00443   while( (imageProvided == 0 && argc > 0) || imageProvided == 1 ) {
00444 
00445     string name(argv[0]) ;
00446 
00447     try {
00448       VL::PgmBuffer buffer ;
00449       buffer.data = NULL;
00450       
00451       // compute the output filenames:
00452       //
00453       // 1) if --output is specified, then we just use the one provided
00454       //    by the user
00455       //
00456       // 2) if --output is not specified, we derive the output filename
00457       //    from the input filename by
00458       //    - removing the extension part from the output filename
00459       //    - and if outputFilenamePrefix is non void, removing 
00460       //      the directory part and prefixing outputFilenamePrefix.
00461       //
00462       // 3) in any case we derive the binary descriptor filename by
00463       //    removing from the output filename the .key extension (if any)
00464       //    and adding a .desc extension.
00465       
00466       if(outputFilename.size() == 0) {
00467         // case 2) above
00468         outputFilename = name ;
00469         
00470         // if we specify an output directory, then extract
00471         // the basename
00472         if(outputFilenamePrefix.size() != 0) {
00473           outputFilename = outputFilenamePrefix + 
00474              std::string(libgenEmu_basename(outputFilename.c_str())) ;
00475         }
00476         
00477       // remove .pgm extension, add .key
00478         outputFilename = removeExtension(outputFilename, ".pgm") ;
00479         outputFilename += ".key" ;
00480       }
00481       
00482       // remove .key extension, add .desc
00483       descriptorsFilename = removeExtension(outputFilename, ".key") ;
00484       descriptorsFilename += ".desc" ;
00485       
00486       // ---------------------------------------------------------------
00487       //                                                  Load PGM image
00488       // ---------------------------------------------------------------    
00489       verbose && cout
00490         << "siftpp: loading PGM image '" << name << "' ..."
00491         << flush;
00492       
00493       /** Start of code modified by Xinghao Pan on 14 Apr 2008
00494           to support the passing of pixel_t arrays directly instead of using files
00495       **/
00496       if (imageProvided == 0){
00497         try {          
00498           ifstream in(name.c_str(), ios::binary) ; 
00499           if(! in.good()) VL_THROW("Could not open '"<<name<<"'.") ;      
00500           extractPgm(in, buffer) ;
00501         }    
00502         catch(VL::Exception const& e) {
00503           throw VL::Exception("PGM read error: "+e.msg) ;
00504         }
00505       }else if (imageProvided == 1){
00506         createPgmBufferFromArray(width, height, data, buffer);
00507         imageProvided = 2;
00508       }
00509       /** End of code modified by Xinghao Pan on 14 Apr 2008
00510       to support the passing of pixel_t arrays directly instead of using files
00511        **/
00512 
00513       
00514       verbose && cout 
00515         << " read "
00516         << buffer.width  <<" x "
00517         << buffer.height <<" pixels" 
00518         << endl ;
00519       
00520       // ---------------------------------------------------------------
00521       //                                            Gaussian scale space
00522       // ---------------------------------------------------------------    
00523       verbose && cout 
00524         << "siftpp: computing Gaussian scale space" 
00525         << endl ;
00526       
00527       int         O      = octaves ;    
00528       int const   S      = levels ;
00529       int const   omin   = first ;
00530       float const sigman = .5f ;
00531       float const sigma0 = 1.6f * powf(2.0f, 1.0f / S) ;
00532       
00533       // optionally autoselect the number number of octaves
00534       // we downsample up to 8x8 patches
00535       if(O < 1) {
00536         O = std::max
00537           (int
00538            (std::floor
00539             (log2
00540              ((float)std::min(buffer.width,buffer.height))) - omin -3), 1) ;
00541       }
00542 
00543       verbose && cout
00544         << "siftpp:   number of octaves     : " << O << endl 
00545         << "siftpp:   first octave          : " << omin << endl 
00546         << "siftpp:   levels per octave     : " << S 
00547         << endl ;
00548       
00549       // initialize scalespace
00550       if (sift) delete sift;
00551       sift = new VL::Sift(buffer.data, buffer.width, buffer.height, 
00552                     sigman, sigma0,
00553                     O, S,
00554                     omin, -1, S+1) ;
00555       
00556       verbose && cout 
00557         << "siftpp: Gaussian scale space completed"
00558         << endl ;
00559       
00560       // ---------------------------------------------------------------
00561       //                                       Save Gaussian scale space
00562       // ---------------------------------------------------------------    
00563       
00564       if(savegss) {
00565         verbose && cout<<"siftpp: saving Gaussian scale space"<<endl ;
00566         
00567         string imageBasename = removeExtension(outputFilename, ".key") ;
00568         
00569         for(int o = omin ; o < omin + O ; ++o) {
00570           for(int s = 0 ; s < S ; ++s) {
00571             
00572             ostringstream suffix ;
00573             suffix<<'.'<<o<<'.'<<s<<".pgm" ;
00574             string imageFilename = imageBasename + suffix.str() ;
00575             
00576             verbose && cout 
00577               << "siftpp:   octave " << setw(3) << o
00578               << " level " << setw(3) << s
00579               << " to '" << imageFilename
00580               << "' ..." << flush ;
00581             
00582             ofstream fout(imageFilename.c_str(), ios::binary) ;
00583             if(!fout.good()) 
00584               VL_THROW("Could not open '"<<imageFilename<<'\'') ;
00585             
00586             VL::insertPgm(fout,
00587                           sift->getLevel(o,s),
00588                           sift->getOctaveWidth(o),
00589                           sift->getOctaveHeight(o)) ;
00590             fout.close() ;
00591             
00592             verbose && cout
00593               << " done." << endl ;
00594           }
00595         }
00596       }
00597       /** Start of code added by Xinghao Pan on 20 Feb 2008
00598        *** Facilitate record of gaussian space
00599        **/
00600       for(int o = omin ; o < omin + O ; ++o) {
00601         vector< vector<int> > octaveGaussianSpace;
00602         int octaveWidth = sift->getOctaveWidth(o);
00603         int octaveHeight = sift->getOctaveHeight(o);
00604         for(int s = 0 ; s < S ; ++s) {
00605           vector<int> levelGaussianSpace;
00606           VL::pixel_t* levelSpace = sift->getLevel(o,s);
00607           levelGaussianSpace.push_back(octaveWidth);
00608           levelGaussianSpace.push_back(octaveHeight);
00609           for (int levelRow = 0; levelRow < octaveHeight; levelRow++){
00610             for (int levelCol = 0; levelCol < octaveWidth; levelCol++){
00611               float tempFloat = (std::max(std::min(*levelSpace++, 1.0f),0.f) * 255.0f);
00612               int tempInt = (int)(tempFloat+0.5);
00613               levelGaussianSpace.push_back(tempInt);
00614             }
00615           }
00616           octaveGaussianSpace.push_back(levelGaussianSpace);
00617         }
00618         gaussianSpace.push_back(octaveGaussianSpace);
00619       }
00620       /** End of code added by Xinghao Pan on 20 Feb 2008
00621        *** Facilitate record of gaussian space
00622        **/
00623       
00624       
00625       
00626       // -------------------------------------------------------------
00627       //                                             Run SIFT detector
00628       // -------------------------------------------------------------    
00629       if( ! haveKeypoints ) {
00630 
00631         verbose && cout 
00632           << "siftpp: running detector  "<< endl
00633           << "siftpp:   threshold             : " << threshold << endl
00634           << "siftpp:   edge-threshold        : " << edgeThreshold
00635           << endl ;
00636         
00637         sift->detectKeypoints(threshold, edgeThreshold) ;
00638         
00639         verbose && cout 
00640           << "siftpp: detector completed with " 
00641           << sift->keypointsEnd() - sift->keypointsBegin() 
00642           << " keypoints" 
00643           << endl ;
00644       }
00645       
00646       // -------------------------------------------------------------
00647       //                  Run SIFT orientation detector and descriptor
00648       // -------------------------------------------------------------    
00649 
00650       /* set descriptor options */
00651       sift->setNormalizeDescriptor( ! unnormalized ) ;
00652       sift->setMagnification( magnif ) ;
00653 
00654       if( verbose ) {
00655         cout << "siftpp: " ;
00656         if( ! noorient &   nodescr) cout << "computing keypoint orientations" ;
00657         if(   noorient & ! nodescr) cout << "computing keypoint descriptors" ;
00658         if( ! noorient & ! nodescr) cout << "computing orientations and descriptors" ;
00659         if(   noorient &   nodescr) cout << "finalizing" ; 
00660         cout << endl ;
00661       }
00662       
00663       {            
00664         // open output file
00665         ofstream out(outputFilename.c_str(), ios::binary) ;
00666       /** Code change by Xinghao Pan on 17 Jul 08, 0121h
00667           Original version throws exception when unable to write to file
00668           Causes problem when user has no write permissions to outputfilename path
00669           Instead, simply print error code and do not write output
00670       **/
00671 /*        // Original version
00672         if( ! out.good() ) 
00673           VL_THROW("Could not open output file '"
00674                    << outputFilename
00675                    << "'.") ;
00676         */
00677         // New version
00678         int outGood = out.good();
00679         if( ! outGood ) {
00680             verbose && cout << "Could not open output file '" << outputFilename << "'.";
00681         }
00682         // End of new version
00683 
00684         verbose && cout
00685           << "siftpp:   write keypoints to    : '" << outputFilename << "'"         << endl
00686           << "siftpp:   floating point descr. : "  << (fp           ? "yes" : "no") << endl
00687           << "siftpp:   binary descr.         : "  << (binary       ? "yes" : "no") << endl
00688           << "siftpp:   unnormalized descr.   : "  << (unnormalized ? "yes" : "no") << endl
00689           << "siftpp:   descr. magnif.        : "  << setprecision(3) << magnif
00690           << endl ;
00691         
00692         if (outGood) out.flags(ios::fixed) ;
00693       
00694         /* If a keypoint file is provided, then open it now */
00695         auto_ptr<ifstream> keypointsIn_pt ;
00696         
00697         if( haveKeypoints ) {
00698           keypointsIn_pt = auto_ptr<ifstream>
00699             (new ifstream(keypointsFilename.c_str(), ios::binary)) ;
00700           
00701           if( ! keypointsIn_pt->good() ) 
00702             VL_THROW("Could not open keypoints file '"
00703                      << keypointsFilename
00704                      << "'.") ;
00705           
00706           verbose && cout
00707             << "siftpp:   read keypoints from   : '" 
00708             << keypointsFilename << "'"
00709             << endl ;
00710         }
00711         
00712         /* If the descriptors are redirected to a binary file, then open it now */
00713         auto_ptr<ofstream> descriptorsOut_pt ;
00714         
00715         if( binary ) {        
00716           descriptorsOut_pt = auto_ptr<ofstream>
00717             (new ofstream(descriptorsFilename.c_str(), ios::binary)) ;
00718           
00719           if( ! descriptorsOut_pt->good() )
00720             VL_THROW("Could not open descriptors file '"
00721                      << descriptorsFilename 
00722                      << "'.") ;
00723           
00724           verbose && cout 
00725             << "siftpp:   write descriptors to  : '" 
00726             << descriptorsFilename << "'"
00727             << endl ;         
00728         }
00729         
00730         if( haveKeypoints ) {
00731           // -------------------------------------------------------------
00732           //                 Reads keypoint from file, compute descriptors
00733           // -------------------------------------------------------------
00734           Keypoints keypoints ;
00735           
00736           while( !keypointsIn_pt->eof() ) {
00737             VL::float_t x,y,sigma,th ;
00738             
00739             /* read x, y, sigma and th from the beginning of the line */
00740             (*keypointsIn_pt) 
00741               >> x
00742               >> y
00743               >> sigma
00744               >> th ;
00745 
00746             /* skip the rest of the line */
00747             (*keypointsIn_pt).ignore(numeric_limits<streamsize>::max(),'\n') ;
00748 
00749             /* break the loop if end of file reached */
00750             if( keypointsIn_pt->eof() ) break ;
00751 
00752             /* trhow an error if something wrong */
00753             if( ! keypointsIn_pt->good() ) 
00754               VL_THROW("Error reading keypoints file.") ;
00755             
00756             /* compute integer components */
00757             VL::Sift::Keypoint key 
00758               = sift->getKeypoint(x,y,sigma) ;
00759             
00760             Keypoints::value_type entry ;
00761             entry.first  = key ;
00762             entry.second = th ;
00763             keypoints.push_back(entry) ;
00764           }
00765           
00766           /* sort keypoints by scale if not required otherwise */
00767           if(! stableorder)
00768             sort(keypoints.begin(), keypoints.end(), cmpKeypoints) ;
00769           
00770           // process in batch
00771           for(Keypoints::const_iterator iter = keypoints.begin() ;
00772               iter != keypoints.end() ;
00773               ++iter) {
00774             VL::Sift::Keypoint const& key = iter->first ;
00775             VL::float_t th = iter->second ;
00776             
00777             /* write keypoint */
00778             if (outGood)
00779             out << setprecision(2) << key.x     << "  "
00780                 << setprecision(2) << key.y     << "  "
00781                 << setprecision(2) << key.sigma << "  "
00782                 << setprecision(3) << th ;
00783             keyValues->push_back(key.x);
00784             keyValues->push_back(key.y);
00785             keyValues->push_back(key.sigma);
00786             keyValues->push_back(th);
00787             keyValues->push_back(key.is);
00788             keyValues->push_back(key.o);
00789             
00790             /* compute descriptor */
00791             VL::float_t descr [128] ;
00792             sift->computeKeypointDescriptor(descr, key, th) ;
00793             
00794             /* save to appropriate file */
00795             if( descriptorsOut_pt.get() ) {
00796               ostream& os = *descriptorsOut_pt.get() ;
00797               insertDescriptor(os, descr, true, fp, numKeypoints, keyValues) ;
00798             } else {
00799               insertDescriptor(out, descr, false, fp, numKeypoints, keyValues, outGood) ;
00800             }
00801             
00802             /* next keypoint */
00803             if (outGood) out << endl ;    
00804           } // next keypoint
00805           
00806         } else {
00807           
00808           // -------------------------------------------------------------
00809           //            Run detector, compute orientations and descriptors
00810           // -------------------------------------------------------------
00811           for( VL::Sift::KeypointsConstIter iter = sift->keypointsBegin() ;
00812                iter != sift->keypointsEnd() ; ++iter ) {
00813             
00814             // detect orientations
00815             VL::float_t angles [4] ;
00816             int nangles ;
00817             if( ! noorient ) {
00818               nangles = sift->computeKeypointOrientations(angles, *iter) ;
00819             } else {
00820             nangles = 1;
00821             angles[0] = VL::float_t(0) ;
00822           }
00823             
00824             // compute descriptors
00825             for(int a = 0 ; a < nangles ; ++a) {
00826 
00827               if (outGood)
00828               out << setprecision(2) << iter->x << ' '
00829                   << setprecision(2) << iter->y << ' '
00830                   << setprecision(2) << iter->sigma << ' ' 
00831                   << setprecision(3) << angles[a] ;
00832               keyValues->push_back(iter->x);
00833               keyValues->push_back(iter->y);
00834               keyValues->push_back(iter->sigma);
00835               keyValues->push_back(angles[a]);
00836               keyValues->push_back(iter->is);
00837               keyValues->push_back(iter->o);
00838 //              cout << "(" << iter->x << "," << iter->y << ") " << keyValues->size() << "\n";
00839 
00840               /* compute descriptor */
00841               VL::float_t descr_pt [128] ;
00842               sift->computeKeypointDescriptor(descr_pt, *iter, angles[a]) ;
00843               
00844 /*              for (int ii = 0; ii < 128; ii++){
00845                 keyValues->push_back(descr_pt[ii]);
00846               }
00847         */
00848               /* save descriptor to to appropriate file */              
00849               if( ! nodescr ) {
00850                 if( descriptorsOut_pt.get() ) {
00851                   ostream& os = *descriptorsOut_pt.get() ;
00852                   insertDescriptor(os, descr_pt, true, fp, numKeypoints, keyValues) ;
00853                 } else {
00854                   insertDescriptor(out, descr_pt, false, fp, numKeypoints, keyValues, outGood) ;
00855                 }
00856               }
00857               /* next line */
00858               if (outGood) out << endl ;
00859             } // next angle
00860           } // next keypoint
00861         }
00862         
00863         if (outGood) out.close() ;
00864         if(descriptorsOut_pt.get()) descriptorsOut_pt->close(); 
00865         if(keypointsIn_pt.get())    keypointsIn_pt->close(); 
00866         verbose && cout 
00867           << "siftpp: job completed"<<endl ;
00868       }
00869       
00870       argc-- ;
00871       argv++ ;
00872       outputFilename = string("") ;
00873       
00874       delete [] buffer.data;
00875     }
00876     catch(VL::Exception &e) {
00877       cerr<<endl<<"Error processing '"<<name<<"': "<<e.msg<<endl ;
00878                         if (sift) delete sift;
00879                         sift = NULL;
00880       return sift ;
00881     }    
00882   } // next image
00883   
00884   return sift ;
00885 }
00886 
00887 VL::Sift*
00888     siftdriver(int argc, char** argv, int* numKeypoints, vector<double>* keyvals)
00889 {
00890   vector< vector< vector<int> > > gaussianSpace;
00891   return siftdriver(argc, argv, numKeypoints, keyvals, gaussianSpace);
00892 }
00893 
00894 VL::Sift*
00895     siftdriver(int argc, char** argv, int* numKeypoints)
00896 {
00897   vector<double> temp;
00898   return siftdriver(argc, argv, numKeypoints, &temp);
00899 }
00900 

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:51 2016 by Doxygen 1.6.3