sift-driver.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. // file: sift-driver.cpp
  2. // author: Andrea Vedaldi
  3. // description: SIFT command line utility implementation
  4. // AUTORIGTHS
  5. #include <vislearning/features/localfeatures/sift.h>
  6. #include<string>
  7. #include <stdlib.h>
  8. #include <memory>
  9. #include <string.h>
  10. #include<iostream>
  11. #include<iomanip>
  12. #include<fstream>
  13. #include<sstream>
  14. #include<algorithm>
  15. extern "C" {
  16. #include<getopt.h>
  17. #if defined(__clang__) || defined(__llvm__)
  18. #include<libgen.h>
  19. #else
  20. #include<string.h>
  21. #endif
  22. #include<assert.h>
  23. }
  24. using namespace std ;
  25. typedef unsigned char uint8_t;
  26. typedef unsigned int uint32_t;
  27. size_t const not_found = numeric_limits<size_t>::max() - 1 ;
  28. /** @brief Case insensitive character comparison
  29. **
  30. ** This predicate returns @c true if @a a and @a b are equal up to
  31. ** case.
  32. **
  33. ** @return predicate value.
  34. **/
  35. inline
  36. bool ciIsEqual(char a, char b)
  37. {
  38. return
  39. tolower((char unsigned)a) ==
  40. tolower((char unsigned)b) ;
  41. }
  42. /** @brief Case insensitive extension removal
  43. **
  44. ** The function returns @a name with the suffix $a ext removed. The
  45. ** suffix is matched case-insensitve.
  46. **
  47. ** @return @a name without @a ext.
  48. **/
  49. string
  50. // refactor-nice.pl: check this substitution
  51. // old: removeExtension(string name, string ext)
  52. removeExtension(string name, std::string ext)
  53. {
  54. string::iterator pos =
  55. find_end(name.begin(),name.end(),ext.begin(),ext.end(),ciIsEqual) ;
  56. // make sure the occurence is at the end
  57. if(pos+ext.size() == name.end()) {
  58. return name.substr(0, pos-name.begin()) ;
  59. } else {
  60. return name ;
  61. }
  62. }
  63. /** @brief Insert descriptor into stream
  64. **
  65. ** The function writes a descriptor in ASCII/binary format
  66. ** and in integer/floating point format into the stream.
  67. **
  68. ** @param os output stream.
  69. ** @param descr_pt descriptor (floating point)
  70. ** @param binary write binary descriptor?
  71. ** @param fp write floating point data?
  72. **/
  73. std::ostream&
  74. insertDescriptor(std::ostream& os,
  75. VL::float_t const * descr_pt,
  76. bool binary,
  77. bool fp )
  78. {
  79. #define RAW_CONST_PT(x) reinterpret_cast<char const*>(x)
  80. #define RAW_PT(x) reinterpret_cast<char*>(x)
  81. if( fp ) {
  82. /* convert to 32 bits floats (single precision) */
  83. VL::float32_t fdescr_pt [128] ;
  84. for(int i = 0 ; i < 128 ; ++i)
  85. fdescr_pt[i] = VL::float32_t( descr_pt[i]) ;
  86. if( binary ) {
  87. /*
  88. Test for endianess. Recall: big_endian = the most significant
  89. byte at lower memory address.
  90. */
  91. short int const word = 0x0001 ;
  92. bool little_endian = RAW_CONST_PT(&word)[0] ;
  93. /*
  94. We save in big-endian (network) order. So if this machine is
  95. little endiand do the appropriate conversion.
  96. */
  97. if( little_endian ) {
  98. for(int i = 0 ; i < 128 ; ++i) {
  99. VL::float32_t tmp = fdescr_pt[ i ] ;
  100. char* pt = RAW_PT(fdescr_pt + i) ;
  101. char* spt = RAW_PT(&tmp) ;
  102. pt[0] = spt[3] ;
  103. pt[1] = spt[2] ;
  104. pt[2] = spt[1] ;
  105. pt[3] = spt[0] ;
  106. }
  107. }
  108. os.write( RAW_PT(fdescr_pt), 128 * sizeof(VL::float32_t) ) ;
  109. } else {
  110. for(int i = 0 ; i < 128 ; ++i)
  111. os << ' '
  112. << fdescr_pt[i] ;
  113. }
  114. } else {
  115. VL::uint8_t idescr_pt [128] ;
  116. for(int i = 0 ; i < 128 ; ++i)
  117. idescr_pt[i] = uint8_t(float_t(512) * descr_pt[i]) ;
  118. if( binary ) {
  119. os.write( RAW_PT(idescr_pt), 128) ;
  120. } else {
  121. for(int i = 0 ; i < 128 ; ++i)
  122. os << ' '
  123. << uint32_t( idescr_pt[i] ) ;
  124. }
  125. }
  126. return os ;
  127. }
  128. /* keypoint list */
  129. typedef vector<pair<VL::Sift::Keypoint,VL::float_t> > Keypoints ;
  130. /* predicate used to order keypoints by increasing scale */
  131. bool cmpKeypoints (Keypoints::value_type const&a,
  132. Keypoints::value_type const&b) {
  133. return a.first.sigma < b.first.sigma ;
  134. }
  135. // -------------------------------------------------------------------
  136. // main
  137. // -------------------------------------------------------------------
  138. int
  139. main(int argc, char** argv)
  140. {
  141. int first = -1 ;
  142. int octaves = -1 ;
  143. int levels = 3 ;
  144. float threshold = 0.04f / levels / 2.0f ;
  145. float edgeThreshold = 10.0f;
  146. float magnif = 1.5 ;
  147. int nodescr = 0 ;
  148. int noorient = 0 ;
  149. int stableorder = 0 ;
  150. int savegss = 0 ;
  151. int verbose = 0 ;
  152. int binary = 0 ;
  153. int haveKeypoints = 0 ;
  154. int unnormalized = 0 ;
  155. int fp = 0 ;
  156. // refactor-nice.pl: check this substitution
  157. // old: string outputFilenamePrefix ;
  158. std::string outputFilenamePrefix ;
  159. // refactor-nice.pl: check this substitution
  160. // old: string outputFilename ;
  161. std::string outputFilename ;
  162. // refactor-nice.pl: check this substitution
  163. // old: string descriptorsFilename ;
  164. std::string descriptorsFilename ;
  165. // refactor-nice.pl: check this substitution
  166. // old: string keypointsFilename ;
  167. std::string keypointsFilename ;
  168. static struct option longopts[] = {
  169. { "verbose", no_argument, NULL, 'v' },
  170. { "help", no_argument, NULL, 'h' },
  171. { "output", required_argument, NULL, 'o' },
  172. { "prefix", required_argument, NULL, 'p' },
  173. { "first-octave", required_argument, NULL, 'f' },
  174. { "keypoints", required_argument, NULL, 'k' },
  175. { "octaves", required_argument, NULL, 'O' },
  176. { "levels", required_argument, NULL, 'S' },
  177. { "threshold", required_argument, NULL, 't' },
  178. { "edge-threshold", required_argument, NULL, 'e' },
  179. { "magnif", required_argument, NULL, 'm' },
  180. { "binary", no_argument, NULL, 'b' },
  181. { "no-descriptors", no_argument, &nodescr, 1 },
  182. { "no-orientations", no_argument, &noorient, 1 },
  183. { "stable-order", no_argument, &stableorder, 1 },
  184. { "save-gss", no_argument, &savegss, 1 },
  185. { "unnormalized", no_argument, &unnormalized, 1 },
  186. { "floating-point", no_argument, &fp, 1 },
  187. { NULL, 0, NULL, 0 }
  188. };
  189. int ch ;
  190. try {
  191. while ( (ch = getopt_long(argc, argv, "vho:p:f:k:O:S:t:e:b", longopts, NULL)) != -1) {
  192. switch (ch) {
  193. case '?' :
  194. VL_THROW("Invalid option '"<<argv[optind-1]<<"'.") ;
  195. break;
  196. case ':' :
  197. VL_THROW("Missing argument of option '"<<argv[optind-1]<<"'.") ;
  198. break;
  199. case 'h' :
  200. std::cout
  201. << argv[0] << " [--verbose|=v] [--help|-h]" << endl
  202. << " [--output|-o NAME] [--prefix|-p PREFIX] [--binary|-b] [--save-gss] " << endl
  203. << " [--no-descriptors] [--no-orientations] " << endl
  204. << " [--levels|-S NUMBER] [--octaves|-O NUMBER] [--first-octave|-f NUMBER] " << endl
  205. << " [--threshold|-t NUMBER] [--edge-threshold|-e NUMBER] " << endl
  206. << " [--floating-point] [--unnormalized] " << endl
  207. << " IMAGE [IMAGE2 ...]" << endl
  208. << endl
  209. << "* Options *" << endl
  210. << " --verbose Be verbose"<< endl
  211. << " --help Print this message"<<endl
  212. << " --output=NAME Write to this file"<<endl
  213. // refactor-nice.pl: check this substitution
  214. // old: << " --prefix=PREFIX Derive output filename prefixing this string to the input file"<<endl
  215. << " --prefix=PREFIX Derive output filename prefixing this std::string to the input file"<<endl
  216. << " --binary Write descriptors to a separate file in binary format"<<endl
  217. << " --keypoints=FILE Reads keypoint frames from here; do not run SIFT detector" << endl
  218. << " --save-gss Save Gaussian scale space on disk" << endl
  219. << " --octaves=O Number of octaves" << endl
  220. << " --levels=S Number of levels per octave" << endl
  221. << " --first-octave=MINO Index of the first octave" << endl
  222. << " --threshold=THR Keypoint strength threhsold" << endl
  223. << " --magnif=MAG Keypoint magnification" << endl
  224. << " --edge-threshold=THR On-edge threshold" << endl
  225. << " --no-descriptors Do not compute descriptors" << endl
  226. << " --no-orientations Do not compute orientations" << endl
  227. << " --stable-order Do not reorder keypoints" << endl
  228. << " --unnormalzied Do not normalize descriptors" << endl
  229. << " --floating-point Save floating point descriptors" << endl
  230. << endl
  231. << " * Examples *" << endl
  232. << argv[0] << " [OPTS...] image.pgm" << endl
  233. << argv[0] << " [OPTS...] image.pgm --output=file.key" << endl
  234. << argv[0] << " [OPTS...] image.pgm --keypoints=frames.key" << endl
  235. << argv[0] << " [OPTS...] *.pgm --prefix=/tmp/" << endl
  236. << argv[0] << " [OPTS...] *.pgm --prefix=/tmp/ --binary" << endl
  237. << endl
  238. << " * This build: " ;
  239. #if defined VL_USEFASTMATH
  240. std::cout << "has fast approximate math" ;
  241. #else
  242. std::cout << "has slow accurate math" ;
  243. #endif
  244. std::cout << " (fp datatype is '"
  245. << VL_EXPAND_AND_STRINGIFY(VL_FASTFLOAT)
  246. << "') *"<<endl ;
  247. return 0 ;
  248. case 'v' : // verbose
  249. verbose = 1 ;
  250. break ;
  251. case 'f': // first octave
  252. {
  253. std::istringstream iss(optarg) ;
  254. iss >> first ;
  255. if( iss.fail() )
  256. VL_THROW("Invalid argument '" << optarg << "'.") ;
  257. }
  258. break ;
  259. case 'O' : // octaves
  260. {
  261. std::istringstream iss(optarg) ;
  262. iss >> octaves ;
  263. if( iss.fail() )
  264. VL_THROW("Invalid argument '" << optarg << "'.") ;
  265. if( octaves < 1 ) {
  266. VL_THROW("The number of octaves cannot be smaller than one.");
  267. }
  268. }
  269. break ;
  270. case 'S' : // levels
  271. {
  272. std::istringstream iss(optarg) ;
  273. iss >> levels ;
  274. if( iss.fail() )
  275. VL_THROW("Invalid argument '" << optarg << "'.") ;
  276. if( levels < 1 ) {
  277. VL_THROW("The number of levels cannot be smaller than one.") ;
  278. }
  279. }
  280. break ;
  281. case 't' : // threshold
  282. {
  283. std::istringstream iss(optarg) ;
  284. iss >> threshold ;
  285. if( iss.fail() )
  286. VL_THROW("Invalid argument '" << optarg << "'.") ;
  287. }
  288. break ;
  289. case 'e' : // edge-threshold
  290. {
  291. std::istringstream iss(optarg) ;
  292. iss >> edgeThreshold ;
  293. if( iss.fail() )
  294. VL_THROW("Invalid argument '" << optarg << "'.") ;
  295. }
  296. break ;
  297. case 'm' : // magnification
  298. {
  299. std::istringstream iss(optarg) ;
  300. iss >> magnif ;
  301. if( iss.fail() )
  302. VL_THROW("Invalid argument '" << optarg << "'.") ;
  303. }
  304. break ;
  305. case 'o' : // output filename
  306. {
  307. outputFilename = std::string(optarg) ;
  308. break ;
  309. }
  310. case 'p' : // output prefix
  311. {
  312. outputFilenamePrefix = std::string(optarg) ;
  313. break ;
  314. }
  315. case 'k' : // keypoint file
  316. {
  317. keypointsFilename = std::string(optarg) ;
  318. haveKeypoints = 1 ;
  319. break ;
  320. }
  321. case 'b' : // write descriptors to a binary file
  322. {
  323. binary = 1 ;
  324. break ;
  325. }
  326. case 0 : // all other options
  327. break ;
  328. default:
  329. assert(false) ;
  330. }
  331. }
  332. argc -= optind;
  333. argv += optind;
  334. // check for argument consistency
  335. if(argc == 0) VL_THROW("No input image specfied.") ;
  336. if(outputFilename.size() != 0 && ((argc > 1) | binary)) {
  337. VL_THROW("--output cannot be used with multiple images or --binary.") ;
  338. }
  339. if(outputFilename.size() !=0 &&
  340. outputFilenamePrefix.size() !=0) {
  341. VL_THROW("--output cannot be used in combination with --prefix.") ;
  342. }
  343. /* end option try-catch block */
  344. }
  345. catch( VL::Exception const & e ) {
  346. cerr << "siftpp: error: "
  347. << e.msg
  348. << endl ;
  349. exit(1) ;
  350. }
  351. // -----------------------------------------------------------------
  352. // Loop over input images
  353. // -----------------------------------------------------------------
  354. while( argc > 0 ) {
  355. // refactor-nice.pl: check this substitution
  356. // old: string name(argv[0]) ;
  357. std::string name(argv[0]) ;
  358. try {
  359. VL::PgmBuffer buffer ;
  360. // compute the output filenames:
  361. //
  362. // 1) if --output is specified, then we just use the one provided
  363. // by the user
  364. //
  365. // 2) if --output is not specified, we derive the output filename
  366. // from the input filename by
  367. // - removing the extension part from the output filename
  368. // - and if outputFilenamePrefix is non void, removing
  369. // the directory part and prefixing outputFilenamePrefix.
  370. //
  371. // 3) in any case we derive the binary descriptor filename by
  372. // removing from the output filename the .key extension (if any)
  373. // and adding a .desc extension.
  374. if(outputFilename.size() == 0) {
  375. // case 2) above
  376. outputFilename = name ;
  377. // if we specify an output directory, then extract
  378. // the basename
  379. if(outputFilenamePrefix.size() != 0) {
  380. outputFilename = outputFilenamePrefix +
  381. std::string(basename((char*)outputFilename.c_str())) ;
  382. }
  383. // remove .pgm extension, add .key
  384. outputFilename = removeExtension(outputFilename, ".pgm") ;
  385. outputFilename += ".key" ;
  386. }
  387. // remove .key extension, add .desc
  388. descriptorsFilename = removeExtension(outputFilename, ".key") ;
  389. descriptorsFilename += ".desc" ;
  390. // ---------------------------------------------------------------
  391. // Load PGM image
  392. // ---------------------------------------------------------------
  393. verbose && cout
  394. << "siftpp: lodaing PGM image '" << name << "' ..."
  395. << flush;
  396. try {
  397. ifstream in(name.c_str(), ios::binary) ;
  398. if(! in.good()) VL_THROW("Could not open '"<<name<<"'.") ;
  399. extractPgm(in, buffer) ;
  400. }
  401. catch(VL::Exception const& e) {
  402. throw VL::Exception("PGM read error: "+e.msg) ;
  403. }
  404. verbose && cout
  405. << " read "
  406. << buffer.width <<" x "
  407. << buffer.height <<" pixels"
  408. << endl ;
  409. // ---------------------------------------------------------------
  410. // Gaussian scale space
  411. // ---------------------------------------------------------------
  412. verbose && cout
  413. << "siftpp: computing Gaussian scale space"
  414. << endl ;
  415. int O = octaves ;
  416. int const S = levels ;
  417. int const omin = first ;
  418. float const sigman = .5 ;
  419. float const sigma0 = 1.6 * powf(2.0f, 1.0f / S) ;
  420. // optionally autoselect the number number of octaves
  421. // we downsample up to 8x8 patches
  422. if(O < 1) {
  423. O = std::max
  424. (int
  425. (std::floor
  426. (log2
  427. (std::min(buffer.width,buffer.height))) - omin -3), 1) ;
  428. }
  429. verbose && cout
  430. << "siftpp: number of octaves : " << O << endl
  431. << "siftpp: first octave : " << omin << endl
  432. << "siftpp: levels per octave : " << S
  433. << endl ;
  434. // initialize scalespace
  435. VL::Sift sift(buffer.data, buffer.width, buffer.height,
  436. sigman, sigma0,
  437. O, S,
  438. omin, -1, S+1) ;
  439. verbose && cout
  440. << "siftpp: Gaussian scale space completed"
  441. << endl ;
  442. // ---------------------------------------------------------------
  443. // Save Gaussian scale space
  444. // ---------------------------------------------------------------
  445. if(savegss) {
  446. verbose && cout<<"siftpp: saving Gaussian scale space"<<endl ;
  447. // refactor-nice.pl: check this substitution
  448. // old: string imageBasename = removeExtension(outputFilename, ".key") ;
  449. std::string imageBasename = removeExtension(outputFilename, ".key") ;
  450. for(int o = omin ; o < omin + O ; ++o) {
  451. for(int s = 0 ; s < S ; ++s) {
  452. // refactor-nice.pl: check this substitution
  453. // old: ostringstream suffix ;
  454. std::ostringstream suffix ;
  455. suffix<<'.'<<o<<'.'<<s<<".pgm" ;
  456. // refactor-nice.pl: check this substitution
  457. // old: string imageFilename = imageBasename + suffix.str() ;
  458. std::string imageFilename = imageBasename + suffix.str() ;
  459. verbose && cout
  460. << "siftpp: octave " << setw(3) << o
  461. << " level " << setw(3) << s
  462. << " to '" << imageFilename
  463. << "' ..." << flush ;
  464. ofstream fout(imageFilename.c_str(), ios::binary) ;
  465. if(!fout.good())
  466. VL_THROW("Could not open '"<<imageFilename<<'\'') ;
  467. VL::insertPgm(fout,
  468. sift.getLevel(o,s),
  469. sift.getOctaveWidth(o),
  470. sift.getOctaveHeight(o)) ;
  471. fout.close() ;
  472. verbose && cout
  473. << " done." << endl ;
  474. }
  475. }
  476. }
  477. // -------------------------------------------------------------
  478. // Run SIFT detector
  479. // -------------------------------------------------------------
  480. if( ! haveKeypoints ) {
  481. verbose && cout
  482. << "siftpp: running detector "<< endl
  483. << "siftpp: threshold : " << threshold << endl
  484. << "siftpp: edge-threshold : " << edgeThreshold
  485. << endl ;
  486. sift.detectKeypoints(threshold, edgeThreshold) ;
  487. verbose && cout
  488. << "siftpp: detector completed with "
  489. << sift.keypointsEnd() - sift.keypointsBegin()
  490. << " keypoints"
  491. << endl ;
  492. }
  493. // -------------------------------------------------------------
  494. // Run SIFT orientation detector and descriptor
  495. // -------------------------------------------------------------
  496. /* set descriptor options */
  497. sift.setNormalizeDescriptor( ! unnormalized ) ;
  498. sift.setMagnification( magnif ) ;
  499. if( verbose ) {
  500. cout << "siftpp: " ;
  501. if( ! noorient & nodescr) cout << "computing keypoint orientations" ;
  502. if( noorient & ! nodescr) cout << "computing keypoint descriptors" ;
  503. if( ! noorient & ! nodescr) cout << "computing orientations and descriptors" ;
  504. if( noorient & nodescr) cout << "finalizing" ;
  505. cout << endl ;
  506. }
  507. {
  508. // open output file
  509. ofstream out(outputFilename.c_str(), ios::binary) ;
  510. if( ! out.good() )
  511. VL_THROW("Could not open output file '"
  512. << outputFilename
  513. << "'.") ;
  514. verbose && cout
  515. << "siftpp: write keypoints to : '" << outputFilename << "'" << endl
  516. << "siftpp: floating point descr. : " << (fp ? "yes" : "no") << endl
  517. << "siftpp: binary descr. : " << (binary ? "yes" : "no") << endl
  518. << "siftpp: unnormalized descr. : " << (unnormalized ? "yes" : "no") << endl
  519. << "siftpp: descr. magnif. : " << setprecision(3) << magnif
  520. << endl ;
  521. out.flags(ios::fixed) ;
  522. /* If a keypoint file is provided, then open it now */
  523. auto_ptr<ifstream> keypointsIn_pt ;
  524. if( haveKeypoints ) {
  525. keypointsIn_pt = auto_ptr<ifstream>
  526. (new ifstream(keypointsFilename.c_str(), ios::binary)) ;
  527. if( ! keypointsIn_pt->good() )
  528. VL_THROW("Could not open keypoints file '"
  529. << keypointsFilename
  530. << "'.") ;
  531. verbose && cout
  532. << "siftpp: read keypoints from : '"
  533. << keypointsFilename << "'"
  534. << endl ;
  535. }
  536. /* If the descriptors are redirected to a binary file, then open it now */
  537. auto_ptr<ofstream> descriptorsOut_pt ;
  538. if( binary ) {
  539. descriptorsOut_pt = auto_ptr<ofstream>
  540. (new ofstream(descriptorsFilename.c_str(), ios::binary)) ;
  541. if( ! descriptorsOut_pt->good() )
  542. VL_THROW("Could not open descriptors file '"
  543. << descriptorsFilename
  544. << "'.") ;
  545. verbose && cout
  546. << "siftpp: write descriptors to : '"
  547. << descriptorsFilename << "'"
  548. << endl ;
  549. }
  550. if( haveKeypoints ) {
  551. // -------------------------------------------------------------
  552. // Reads keypoint from file, compute descriptors
  553. // -------------------------------------------------------------
  554. Keypoints keypoints ;
  555. while( !keypointsIn_pt->eof() ) {
  556. VL::float_t x,y,sigma,th ;
  557. /* read x, y, sigma and th from the beginning of the line */
  558. (*keypointsIn_pt)
  559. >> x
  560. >> y
  561. >> sigma
  562. >> th ;
  563. /* skip the rest of the line */
  564. (*keypointsIn_pt).ignore(numeric_limits<streamsize>::max(),'\n') ;
  565. /* break the loop if end of file reached */
  566. if( keypointsIn_pt->eof() ) break ;
  567. /* trhow an error if something wrong */
  568. if( ! keypointsIn_pt->good() )
  569. VL_THROW("Error reading keypoints file.") ;
  570. /* compute integer components */
  571. VL::Sift::Keypoint key
  572. = sift.getKeypoint(x,y,sigma) ;
  573. Keypoints::value_type entry ;
  574. entry.first = key ;
  575. entry.second = th ;
  576. keypoints.push_back(entry) ;
  577. }
  578. /* sort keypoints by scale if not required otherwise */
  579. if(! stableorder)
  580. sort(keypoints.begin(), keypoints.end(), cmpKeypoints) ;
  581. // process in batch
  582. for(Keypoints::const_iterator iter = keypoints.begin() ;
  583. iter != keypoints.end() ;
  584. ++iter) {
  585. VL::Sift::Keypoint const& key = iter->first ;
  586. VL::float_t th = iter->second ;
  587. /* write keypoint */
  588. out << setprecision(2) << key.x << " "
  589. << setprecision(2) << key.y << " "
  590. << setprecision(2) << key.sigma << " "
  591. << setprecision(3) << th ;
  592. /* compute descriptor */
  593. VL::float_t descr [128] ;
  594. sift.computeKeypointDescriptor(descr, key, th) ;
  595. /* save to appropriate file */
  596. if( descriptorsOut_pt.get() ) {
  597. ostream& os = *descriptorsOut_pt.get() ;
  598. insertDescriptor(os, descr, true, fp) ;
  599. } else {
  600. insertDescriptor(out, descr, false, fp) ;
  601. }
  602. /* next keypoint */
  603. out << endl ;
  604. } // next keypoint
  605. } else {
  606. // -------------------------------------------------------------
  607. // Run detector, compute orientations and descriptors
  608. // -------------------------------------------------------------
  609. for( VL::Sift::KeypointsConstIter iter = sift.keypointsBegin() ;
  610. iter != sift.keypointsEnd() ; ++iter ) {
  611. // detect orientations
  612. VL::float_t angles [4] ;
  613. int nangles ;
  614. if( ! noorient ) {
  615. nangles = sift.computeKeypointOrientations(angles, *iter) ;
  616. } else {
  617. nangles = 1;
  618. angles[0] = VL::float_t(0) ;
  619. }
  620. // compute descriptors
  621. for(int a = 0 ; a < nangles ; ++a) {
  622. out << setprecision(2) << iter->x << ' '
  623. << setprecision(2) << iter->y << ' '
  624. << setprecision(2) << iter->sigma << ' '
  625. << setprecision(3) << angles[a] ;
  626. /* compute descriptor */
  627. VL::float_t descr_pt [128] ;
  628. sift.computeKeypointDescriptor(descr_pt, *iter, angles[a]) ;
  629. /* save descriptor to to appropriate file */
  630. if( ! nodescr ) {
  631. if( descriptorsOut_pt.get() ) {
  632. ostream& os = *descriptorsOut_pt.get() ;
  633. insertDescriptor(os, descr_pt, true, fp) ;
  634. } else {
  635. insertDescriptor(out, descr_pt, false, fp) ;
  636. }
  637. }
  638. /* next line */
  639. out << endl ;
  640. } // next angle
  641. } // next keypoint
  642. }
  643. out.close() ;
  644. if(descriptorsOut_pt.get()) descriptorsOut_pt->close();
  645. if(keypointsIn_pt.get()) keypointsIn_pt->close();
  646. verbose && cout
  647. << "siftpp: job completed"<<endl ;
  648. }
  649. argc-- ;
  650. argv++ ;
  651. outputFilename = string("") ;
  652. }
  653. catch(VL::Exception &e) {
  654. cerr<<endl<<"Error processing '"<<name<<"': "<<e.msg<<endl ;
  655. return 1 ;
  656. }
  657. } // next image
  658. return 0 ;
  659. }