PARP Research Group University of Murcia, Spain


examples/OpenCV/siftDetector/hess/imgfeatures.cpp

00001 /*
00002   Functions and structures for dealing with image features
00003 
00004   Copyright (C) 2006-2007  Rob Hess <hess@eecs.oregonstate.edu>
00005 
00006   @version 1.1.1-20070913
00007 */
00008 
00009 #include "utils.h"
00010 #include "imgfeatures.h"
00011 
00012 #include <cxcore.h>
00013 
00014 int import_oxfd_features( char*, struct feature** );
00015 int export_oxfd_features( char*, struct feature*, int );
00016 void draw_oxfd_features( IplImage*, struct feature*, int );
00017 void draw_oxfd_feature( IplImage*, struct feature*, CvScalar );
00018 
00019 int import_lowe_features( char*, struct feature** );
00020 int export_lowe_features( char*, struct feature*, int );
00021 void draw_lowe_features( IplImage*, struct feature*, int );
00022 void draw_lowe_feature( IplImage*, struct feature*, CvScalar );
00023 
00024 
00025 /*
00026   Reads image features from file.  The file should be formatted as from
00027   the code provided by the Visual Geometry Group at Oxford:
00028   
00029   
00030   @param filename location of a file containing image features
00031   @param type determines how features are input.  If \a type is FEATURE_OXFD,
00032     the input file is treated as if it is from the code provided by the VGG
00033     at Oxford:
00034 
00035     http://www.robots.ox.ac.uk:5000/~vgg/research/affine/index.html
00036 
00037     If \a type is FEATURE_LOWE, the input file is treated as if it is from
00038     David Lowe's SIFT code:
00039     
00040     http://www.cs.ubc.ca/~lowe/keypoints  
00041   @param features pointer to an array in which to store features
00042   
00043   @return Returns the number of features imported from filename or -1 on error
00044 */
00045 int import_features( char* filename, int type, struct feature** feat )
00046 {
00047   int n;
00048 
00049   switch( type )
00050     {
00051     case FEATURE_OXFD:
00052       n = import_oxfd_features( filename, feat );
00053       break;
00054     case FEATURE_LOWE:
00055       n = import_lowe_features( filename, feat );
00056       break;
00057     default:
00058       fprintf( stderr, "Warning: import_features(): unrecognized feature" \
00059                "type, %s, line %d\n", __FILE__, __LINE__ );
00060       return -1;
00061     }
00062 
00063   if( n == -1 )
00064     fprintf( stderr, "Warning: unable to import features from %s,"      \
00065              " %s, line %d\n", filename, __FILE__, __LINE__ );
00066   return n;
00067 }
00068 
00069 
00070 
00071 /*
00072   Exports a feature set to a file formatted depending on the type of
00073   features, as specified in the feature struct's type field.
00074   
00075   @param filename name of file to which to export features
00076   @param feat feature array
00077   @param n number of features 
00078     
00079   @return Returns 0 on success or 1 on error
00080 */
00081 int export_features( char* filename, struct feature* feat, int n )
00082 {
00083   int r, type;
00084 
00085   if( n <= 0  ||  ! feat )
00086     {
00087       fprintf( stderr, "Warning: no features to export, %s line %d\n",
00088                __FILE__, __LINE__ );
00089       return 1;
00090     }
00091   type = feat[0].type;
00092   switch( type )
00093     {
00094     case FEATURE_OXFD:
00095       r = export_oxfd_features( filename, feat, n );
00096       break;
00097     case FEATURE_LOWE:
00098       r = export_lowe_features( filename, feat, n );
00099       break;
00100     default:
00101       fprintf( stderr, "Warning: export_features(): unrecognized feature" \
00102                "type, %s, line %d\n", __FILE__, __LINE__ );
00103       return -1;
00104     }
00105 
00106   if( r )
00107     fprintf( stderr, "Warning: unable to export features to %s,"        \
00108              " %s, line %d\n", filename, __FILE__, __LINE__ );
00109   return r;
00110 }
00111 
00112 
00113 /*
00114   Draws a set of features on an image
00115   
00116   @param img image on which to draw features
00117   @param feat array of Oxford-type features
00118   @param n number of features
00119 */
00120 void draw_features( IplImage* img, struct feature* feat, int n )
00121 {
00122   int type;
00123 
00124   if( n <= 0  ||  ! feat )
00125     {
00126       fprintf( stderr, "Warning: no features to draw, %s line %d\n",
00127                __FILE__, __LINE__ );
00128       return;
00129     }
00130   type = feat[0].type;
00131   switch( type )
00132     {
00133     case FEATURE_OXFD:
00134       draw_oxfd_features( img, feat, n );
00135       break;
00136     case FEATURE_LOWE:
00137       draw_lowe_features( img, feat, n );
00138       break;
00139     default:
00140       fprintf( stderr, "Warning: draw_features(): unrecognized feature" \
00141                " type, %s, line %d\n", __FILE__, __LINE__ );
00142       break;
00143     }
00144 }
00145 
00146 
00147 
00148 /*
00149   Calculates the squared Euclidian distance between two feature descriptors.
00150   
00151   @param f1 first feature
00152   @param f2 second feature
00153   
00154   @return Returns the squared Euclidian distance between the descriptors of
00155     f1 and f2.
00156 */
00157 double descr_dist_sq( struct feature* f1, struct feature* f2 )
00158 {
00159   double diff, dsq = 0;
00160   double* descr1, * descr2;
00161   int i, d;
00162 
00163   d = f1->d;
00164   if( f2->d != d )
00165     return DBL_MAX;
00166   descr1 = f1->descr;
00167   descr2 = f2->descr;
00168 
00169   for( i = 0; i < d; i++ )
00170     {
00171       diff = descr1[i] - descr2[i];
00172       dsq += diff*diff;
00173     }
00174   return dsq;
00175 }
00176 
00177 
00178 
00179 /***************************** Local Functions *******************************/
00180 
00181 
00182 /*
00183   Reads image features from file.  The file should be formatted as from
00184   the code provided by the Visual Geometry Group at Oxford:
00185   
00186   http://www.robots.ox.ac.uk:5000/~vgg/research/affine/index.html
00187   
00188   @param filename location of a file containing image features
00189   @param features pointer to an array in which to store features
00190   
00191   @return Returns the number of features imported from filename or -1 on error
00192 */
00193 int import_oxfd_features( char* filename, struct feature** features )
00194 {
00195   struct feature* f;
00196   int i, j, n, d;
00197   double x, y, a, b, c, dv;
00198   FILE* file;
00199 
00200   if( ! features )
00201     fatal_error( "NULL pointer error, %s, line %d",  __FILE__, __LINE__ );
00202   if( ! ( file = fopen( filename, "r" ) ) )
00203     {
00204       fprintf( stderr, "Warning: error opening %s, %s, line %d\n",
00205                filename, __FILE__, __LINE__ );
00206       return -1;
00207     }
00208 
00209   /* read dimension and number of features */
00210   if( fscanf( file, " %d %d ", &d, &n ) != 2 )
00211     {
00212       fprintf( stderr, "Warning: file read error, %s, line %d\n",
00213                __FILE__, __LINE__ );
00214       return -1;
00215     }
00216   if( d > FEATURE_MAX_D )
00217     {
00218       fprintf( stderr, "Warning: descriptor too long, %s, line %d\n",
00219                __FILE__, __LINE__ );
00220       return -1;
00221     }
00222   
00223 
00224   f = (struct feature *) calloc( n, sizeof(struct feature) );
00225   for( i = 0; i < n; i++ )
00226     {
00227       /* read affine region parameters */
00228       if( fscanf( file, " %lf %lf %lf %lf %lf ", &x, &y, &a, &b, &c ) != 5 )
00229         {
00230           fprintf( stderr, "Warning: error reading feature #%d, %s, line %d\n",
00231                    i+1, __FILE__, __LINE__ );
00232           free( f );
00233           return -1;
00234         }
00235       f[i].img_pt.x = f[i].x = x;
00236       f[i].img_pt.y = f[i].y = y;
00237       f[i].a = a;
00238       f[i].b = b;
00239       f[i].c = c;
00240       f[i].d = d;
00241       f[i].type = FEATURE_OXFD;
00242       
00243       /* read descriptor */
00244       for( j = 0; j < d; j++ )
00245         {
00246           if( ! fscanf( file, " %lf ", &dv ) )
00247             {
00248               fprintf( stderr, "Warning: error reading feature descriptor" \
00249                        " #%d, %s, line %d\n", i+1, __FILE__, __LINE__ );
00250               free( f );
00251               return -1;
00252             }
00253           f[i].descr[j] = dv;
00254         }
00255 
00256       f[i].scl = f[i].ori = 0;
00257       f[i].category = 0;
00258       f[i].fwd_match = f[i].bck_match = f[i].mdl_match = NULL;
00259       f[i].mdl_pt.x = f[i].mdl_pt.y = -1;
00260       f[i].feature_data = NULL;
00261     }
00262 
00263   if( fclose(file) )
00264     {
00265       fprintf( stderr, "Warning: file close error, %s, line %d\n",
00266                __FILE__, __LINE__ );
00267       free( f );
00268       return -1;
00269     }
00270 
00271   *features = f;
00272   return n;
00273 }
00274 
00275 
00276 
00277 
00278 /*
00279   Exports a feature set to a file formatted as one from the code provided
00280   by the Visual Geometry Group at Oxford:
00281   
00282   http://www.robots.ox.ac.uk:5000/~vgg/research/affine/index.html
00283   
00284   @param filename name of file to which to export features
00285   @param feat feature array
00286   @param n number of features
00287   
00288   @return Returns 0 on success or 1 on error
00289 */
00290 int export_oxfd_features( char* filename, struct feature* feat, int n )
00291 {
00292   FILE* file;
00293   int i, j, d;
00294 
00295   if( n <= 0 )
00296     {
00297       fprintf( stderr, "Warning: feature count %d, %s, line %s\n",
00298                n, __FILE__, __LINE__ );
00299       return 1;
00300     }
00301   if( ! ( file = fopen( filename, "w" ) ) )
00302     {
00303       fprintf( stderr, "Warning: error opening %s, %s, line %d\n",
00304                filename, __FILE__, __LINE__ );
00305       return 1;
00306     }
00307 
00308   d = feat[0].d;
00309   fprintf( file, "%d\n%d\n", d, n );
00310   for( i = 0; i < n; i++ )
00311     {
00312       fprintf( file, "%f %f %f %f %f", feat[i].x, feat[i].y, feat[i].a,
00313                feat[i].b, feat[i].c );
00314       for( j = 0; j < d; j++ )
00315         fprintf( file, " %f", feat[i].descr[j] );
00316       fprintf( file, "\n" );
00317     }
00318 
00319   if( fclose(file) )
00320     {
00321       fprintf( stderr, "Warning: file close error, %s, line %d\n",
00322                __FILE__, __LINE__ );
00323       return 1;
00324     }
00325   return 0;
00326 }
00327 
00328 
00329 
00330 /*
00331   Draws Oxford-type affine features
00332   
00333   @param img image on which to draw features
00334   @param feat array of Oxford-type features
00335   @param n number of features
00336 */
00337 void draw_oxfd_features( IplImage* img, struct feature* feat, int n )
00338 {
00339   CvScalar color = CV_RGB( 255, 255, 255 );
00340   int i;
00341 
00342   if( img-> nChannels > 1 )
00343     color = FEATURE_OXFD_COLOR;
00344   for( i = 0; i < n; i++ )
00345     draw_oxfd_feature( img, feat + i, color );
00346 }
00347 
00348 
00349 
00350 /*
00351   Draws a single Oxford-type feature
00352 
00353   @param img image on which to draw
00354   @param feat feature to be drawn
00355   @param color color in which to draw
00356 */
00357 void draw_oxfd_feature( IplImage* img, struct feature* feat, CvScalar color )
00358 {
00359   double m[4] = { feat->a, feat->b, feat->b, feat->c };
00360   double v[4] = { 0 };
00361   double e[2] = { 0 };
00362   CvMat M, V, E;
00363   double alpha, l1, l2;
00364 
00365   /* compute axes and orientation of ellipse surrounding affine region */
00366   cvInitMatHeader( &M, 2, 2, CV_64FC1, m, CV_AUTOSTEP );
00367   cvInitMatHeader( &V, 2, 2, CV_64FC1, v, CV_AUTOSTEP );
00368   cvInitMatHeader( &E, 2, 1, CV_64FC1, e, CV_AUTOSTEP );
00369   cvEigenVV( &M, &V, &E, DBL_EPSILON );
00370   l1 = 1 / sqrt( e[1] );
00371   l2 = 1 / sqrt( e[0] );
00372   alpha = -atan2( v[1], v[0] );
00373   alpha *= 180 / M_PI;
00374 
00375   cvEllipse( img, cvPoint( feat->x, feat->y ), cvSize( l2, l1 ), alpha,
00376              0, 360, CV_RGB(0,0,0), 3, 8, 0 );
00377   cvEllipse( img, cvPoint( feat->x, feat->y ), cvSize( l2, l1 ), alpha,
00378              0, 360, color, 1, 8, 0 );
00379   cvLine( img, cvPoint( feat->x+2, feat->y ), cvPoint( feat->x-2, feat->y ),
00380           color, 1, 8, 0 );
00381   cvLine( img, cvPoint( feat->x, feat->y+2 ), cvPoint( feat->x, feat->y-2 ),
00382           color, 1, 8, 0 );
00383 }
00384 
00385 
00386 
00387 /*
00388   Reads image features from file.  The file should be formatted as from
00389   the code provided by David Lowe:
00390   
00391   http://www.cs.ubc.ca/~lowe/keypoints/
00392   
00393   @param filename location of a file containing image features
00394   @param features pointer to an array in which to store features
00395   
00396   @return Returns the number of features imported from filename or -1 on error
00397 */
00398 int import_lowe_features( char* filename, struct feature** features )
00399 {
00400   struct feature* f;
00401   int i, j, n, d;
00402   double x, y, s, o, dv;
00403   FILE* file;
00404 
00405   if( ! features )
00406     fatal_error( "NULL pointer error, %s, line %d",  __FILE__, __LINE__ );
00407   if( ! ( file = fopen( filename, "r" ) ) )
00408     {
00409       fprintf( stderr, "Warning: error opening %s, %s, line %d\n",
00410                filename, __FILE__, __LINE__ );
00411       return -1;
00412     }
00413 
00414   /* read number of features and dimension */
00415   if( fscanf( file, " %d %d ", &n, &d ) != 2 )
00416     {
00417       fprintf( stderr, "Warning: file read error, %s, line %d\n",
00418                __FILE__, __LINE__ );
00419       return -1;
00420     }
00421   if( d > FEATURE_MAX_D )
00422     {
00423       fprintf( stderr, "Warning: descriptor too long, %s, line %d\n",
00424                __FILE__, __LINE__ );
00425       return -1;
00426     }
00427 
00428   f = (struct feature *) calloc( n, sizeof(struct feature) );
00429   for( i = 0; i < n; i++ )
00430     {
00431       /* read affine region parameters */
00432       if( fscanf( file, " %lf %lf %lf %lf ", &y, &x, &s, &o ) != 4 )
00433         {
00434           fprintf( stderr, "Warning: error reading feature #%d, %s, line %d\n",
00435                    i+1, __FILE__, __LINE__ );
00436           free( f );
00437           return -1;
00438         }
00439       f[i].img_pt.x = f[i].x = x;
00440       f[i].img_pt.y = f[i].y = y;
00441       f[i].scl = s;
00442       f[i].ori = o;
00443       f[i].d = d;
00444       f[i].type = FEATURE_LOWE;
00445 
00446       /* read descriptor */
00447       for( j = 0; j < d; j++ )
00448         {
00449           if( ! fscanf( file, " %lf ", &dv ) )
00450             {
00451               fprintf( stderr, "Warning: error reading feature descriptor" \
00452                        " #%d, %s, line %d\n", i+1, __FILE__, __LINE__ );
00453               free( f );
00454               return -1;
00455             }
00456           f[i].descr[j] = dv;
00457         }
00458 
00459       f[i].a = f[i].b = f[i].c = 0;
00460       f[i].category = 0;
00461       f[i].fwd_match = f[i].bck_match = f[i].mdl_match = NULL;
00462       f[i].mdl_pt.x = f[i].mdl_pt.y = -1;
00463       f[i].feature_data = NULL;
00464     }
00465 
00466   if( fclose(file) )
00467     {
00468       fprintf( stderr, "Warning: file close error, %s, line %d\n",
00469                __FILE__, __LINE__ );
00470       free( f );
00471       return -1;
00472     }
00473 
00474   *features = f;
00475   return n;
00476 }
00477 
00478 
00479 
00480 /*
00481   Exports a feature set to a file formatted as one from the code provided
00482   by David Lowe:
00483   
00484   http://www.cs.ubc.ca/~lowe/keypoints/
00485   
00486   @param filename name of file to which to export features
00487   @param feat feature array
00488   @param n number of features
00489   
00490   @return Returns 0 on success or 1 on error
00491 */
00492 int export_lowe_features( char* filename, struct feature* feat, int n )
00493 {
00494   FILE* file;
00495   int i, j, d;
00496 
00497   if( n <= 0 )
00498     {
00499       fprintf( stderr, "Warning: feature count %d, %s, line %s\n",
00500                n, __FILE__, __LINE__ );
00501       return 1;
00502     }
00503   if( ! ( file = fopen( filename, "w" ) ) )
00504     {
00505       fprintf( stderr, "Warning: error opening %s, %s, line %d\n",
00506                filename, __FILE__, __LINE__ );
00507       return 1;
00508     }
00509 
00510   d = feat[0].d;
00511   fprintf( file, "%d %d\n", n, d );
00512   for( i = 0; i < n; i++ )
00513     {
00514       fprintf( file, "%f %f %f %f", feat[i].y, feat[i].x,
00515                feat[i].scl, feat[i].ori );
00516       for( j = 0; j < d; j++ )
00517         {
00518           /* write 20 descriptor values per line */
00519           if( j % 20 == 0 )
00520             fprintf( file, "\n" );
00521           fprintf( file, " %d", (int)(feat[i].descr[j]) );
00522         }
00523       fprintf( file, "\n" );
00524     }
00525 
00526   if( fclose(file) )
00527     {
00528       fprintf( stderr, "Warning: file close error, %s, line %d\n",
00529                __FILE__, __LINE__ );
00530       return 1;
00531     }
00532   return 0;
00533 }
00534 
00535 
00536 /*
00537   Draws Lowe-type features
00538   
00539   @param img image on which to draw features
00540   @param feat array of Oxford-type features
00541   @param n number of features
00542 */
00543 void draw_lowe_features( IplImage* img, struct feature* feat, int n )
00544 {
00545   CvScalar color = CV_RGB( 255, 255, 255 );
00546   int i;
00547 
00548   if( img-> nChannels > 1 )
00549     color = FEATURE_LOWE_COLOR;
00550   for( i = 0; i < n; i++ )
00551     draw_lowe_feature( img, feat + i, color );
00552 }
00553 
00554 
00555 
00556 /*
00557   Draws a single Lowe-type feature
00558 
00559   @param img image on which to draw
00560   @param feat feature to be drawn
00561   @param color color in which to draw
00562 */
00563 void draw_lowe_feature( IplImage* img, struct feature* feat, CvScalar color )
00564 {
00565   int len, hlen, blen, start_x, start_y, end_x, end_y, h1_x, h1_y, h2_x, h2_y;
00566   double scl, ori;
00567   double scale = 5.0;
00568   double hscale = 0.75;
00569   CvPoint start, end, h1, h2;
00570 
00571   /* compute points for an arrow scaled and rotated by feat's scl and ori */
00572   start_x = cvRound( feat->x );
00573   start_y = cvRound( feat->y );
00574   scl = feat->scl;
00575   ori = feat->ori;
00576   len = cvRound( scl * scale );
00577   hlen = cvRound( scl * hscale );
00578   blen = len - hlen;
00579   end_x = cvRound( len *  cos( ori ) ) + start_x;
00580   end_y = cvRound( len * -sin( ori ) ) + start_y;
00581   h1_x = cvRound( blen *  cos( ori + CV_PI / 18.0 ) ) + start_x;
00582   h1_y = cvRound( blen * -sin( ori + CV_PI / 18.0 ) ) + start_y;
00583   h2_x = cvRound( blen *  cos( ori - CV_PI / 18.0 ) ) + start_x;
00584   h2_y = cvRound( blen * -sin( ori - CV_PI / 18.0 ) ) + start_y;
00585   start = cvPoint( start_x, start_y );
00586   end = cvPoint( end_x, end_y );
00587   h1 = cvPoint( h1_x, h1_y );
00588   h2 = cvPoint( h2_x, h2_y );
00589 
00590   cvLine( img, start, end, color, 1, 8, 0 );
00591   cvLine( img, end, h1, color, 1, 8, 0 );
00592   cvLine( img, end, h2, color, 1, 8, 0 );
00593 }
00594 
00595 



QVision framework. PARP research group, copyright 2007, 2008.