vl_sift.c
Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
00009 All rights reserved.
00010 
00011 This file is part of the VLFeat library and is made available under
00012 the terms of the BSD license (see the COPYING file).
00013 */
00014 
00015 #include <mexutils.h>
00016 #include <vl/mathop.h>
00017 #include <vl/sift.h>
00018 
00019 #include <math.h>
00020 #include <assert.h>
00021 
00022 /* option codes */
00023 enum {
00024   opt_octaves = 0,
00025   opt_levels,
00026   opt_first_octave,
00027   opt_frames,
00028   opt_edge_thresh,
00029   opt_peak_thresh,
00030   opt_norm_thresh,
00031   opt_magnif,
00032   opt_window_size,
00033   opt_orientations,
00034   opt_float_descriptors,
00035   opt_verbose
00036 } ;
00037 
00038 /* options */
00039 vlmxOption  options [] = {
00040   {"Octaves",          1,   opt_octaves           },
00041   {"Levels",           1,   opt_levels            },
00042   {"FirstOctave",      1,   opt_first_octave      },
00043   {"Frames",           1,   opt_frames            },
00044   {"PeakThresh",       1,   opt_peak_thresh       },
00045   {"EdgeThresh",       1,   opt_edge_thresh       },
00046   {"NormThresh",       1,   opt_norm_thresh       },
00047   {"Magnif",           1,   opt_magnif            },
00048   {"WindowSize",       1,   opt_window_size       },
00049   {"Orientations",     0,   opt_orientations      },
00050   {"FloatDescriptors", 0,   opt_float_descriptors },
00051   {"Verbose",          0,   opt_verbose           },
00052   {0,                  0,   0                     }
00053 } ;
00054 
00068 VL_INLINE void
00069 transpose_descriptor (vl_sift_pix* dst, vl_sift_pix* src)
00070 {
00071   int const BO = 8 ;  /* number of orientation bins */
00072   int const BP = 4 ;  /* number of spatial bins     */
00073   int i, j, t ;
00074 
00075   for (j = 0 ; j < BP ; ++j) {
00076     int jp = BP - 1 - j ;
00077     for (i = 0 ; i < BP ; ++i) {
00078       int o  = BO * i + BP*BO * j  ;
00079       int op = BO * i + BP*BO * jp ;
00080       dst [op] = src[o] ;
00081       for (t = 1 ; t < BO ; ++t)
00082         dst [BO - t + op] = src [t + o] ;
00083     }
00084   }
00085 }
00086 
00097 static int
00098 korder (void const* a, void const* b) {
00099   double x = ((double*) a) [2] - ((double*) b) [2] ;
00100   if (x < 0) return -1 ;
00101   if (x > 0) return +1 ;
00102   return 0 ;
00103 }
00104 
00115 vl_bool
00116 check_sorted (double const * keys, vl_size nkeys)
00117 {
00118   vl_uindex k ;
00119   for (k = 0 ; k + 1 < nkeys ; ++ k) {
00120     if (korder(keys, keys + 4) > 0) {
00121       return VL_FALSE ;
00122     }
00123     keys += 4 ;
00124   }
00125   return VL_TRUE ;
00126 }
00127 
00132 void
00133 mexFunction(int nout, mxArray *out[],
00134             int nin, const mxArray *in[])
00135 {
00136   enum {IN_I=0,IN_END} ;
00137   enum {OUT_FRAMES=0, OUT_DESCRIPTORS} ;
00138 
00139   int                verbose = 0 ;
00140   int                opt ;
00141   int                next = IN_END ;
00142   mxArray const     *optarg ;
00143 
00144   vl_sift_pix const *data ;
00145   int                M, N ;
00146 
00147   int                O     = - 1 ;
00148   int                S     =   3 ;
00149   int                o_min =   0 ;
00150 
00151   double             edge_thresh = -1 ;
00152   double             peak_thresh = -1 ;
00153   double             norm_thresh = -1 ;
00154   double             magnif      = -1 ;
00155   double             window_size = -1 ;
00156 
00157   mxArray           *ikeys_array = 0 ;
00158   double            *ikeys = 0 ;
00159   int                nikeys = -1 ;
00160   vl_bool            force_orientations = 0 ;
00161   vl_bool            floatDescriptors = 0 ;
00162 
00163   VL_USE_MATLAB_ENV ;
00164 
00165   /* -----------------------------------------------------------------
00166    *                                               Check the arguments
00167    * -------------------------------------------------------------- */
00168 
00169   if (nin < 1) {
00170     mexErrMsgTxt("One argument required.") ;
00171   } else if (nout > 2) {
00172     mexErrMsgTxt("Too many output arguments.");
00173   }
00174 
00175   if (mxGetNumberOfDimensions (in[IN_I]) != 2              ||
00176       mxGetClassID            (in[IN_I]) != mxSINGLE_CLASS  ) {
00177     mexErrMsgTxt("I must be a matrix of class SINGLE") ;
00178   }
00179 
00180   data = (vl_sift_pix*) mxGetData (in[IN_I]) ;
00181   M    = mxGetM (in[IN_I]) ;
00182   N    = mxGetN (in[IN_I]) ;
00183 
00184   while ((opt = vlmxNextOption (in, nin, options, &next, &optarg)) >= 0) {
00185     switch (opt) {
00186 
00187     case opt_verbose :
00188       ++ verbose ;
00189       break ;
00190 
00191     case opt_octaves :
00192       if (!vlmxIsPlainScalar(optarg) || (O = (int) *mxGetPr(optarg)) < 0) {
00193         mexErrMsgTxt("'Octaves' must be a positive integer.") ;
00194       }
00195       break ;
00196 
00197     case opt_levels :
00198       if (! vlmxIsPlainScalar(optarg) || (S = (int) *mxGetPr(optarg)) < 1) {
00199         mexErrMsgTxt("'Levels' must be a positive integer.") ;
00200       }
00201       break ;
00202 
00203     case opt_first_octave :
00204       if (!vlmxIsPlainScalar(optarg)) {
00205         mexErrMsgTxt("'FirstOctave' must be an integer") ;
00206       }
00207       o_min = (int) *mxGetPr(optarg) ;
00208       break ;
00209 
00210     case opt_edge_thresh :
00211       if (!vlmxIsPlainScalar(optarg) || (edge_thresh = *mxGetPr(optarg)) < 1) {
00212         mexErrMsgTxt("'EdgeThresh' must be not smaller than 1.") ;
00213       }
00214       break ;
00215 
00216     case opt_peak_thresh :
00217       if (!vlmxIsPlainScalar(optarg) || (peak_thresh = *mxGetPr(optarg)) < 0) {
00218         mexErrMsgTxt("'PeakThresh' must be a non-negative real.") ;
00219       }
00220       break ;
00221 
00222     case opt_norm_thresh :
00223       if (!vlmxIsPlainScalar(optarg) || (norm_thresh = *mxGetPr(optarg)) < 0) {
00224         mexErrMsgTxt("'NormThresh' must be a non-negative real.") ;
00225       }
00226       break ;
00227 
00228     case opt_magnif :
00229       if (!vlmxIsPlainScalar(optarg) || (magnif = *mxGetPr(optarg)) < 0) {
00230         mexErrMsgTxt("'Magnif' must be a non-negative real.") ;
00231       }
00232       break ;
00233 
00234     case opt_window_size :
00235       if (!vlmxIsPlainScalar(optarg) || (window_size = *mxGetPr(optarg)) < 0) {
00236         mexErrMsgTxt("'WindowSize' must be a non-negative real.") ;
00237       }
00238       break ;
00239 
00240     case opt_frames :
00241       if (!vlmxIsMatrix(optarg, 4, -1)) {
00242         mexErrMsgTxt("'Frames' must be a 4 x N matrix.") ;
00243       }
00244       ikeys_array = mxDuplicateArray (optarg) ;
00245       nikeys      = mxGetN (optarg) ;
00246       ikeys       = mxGetPr (ikeys_array) ;
00247       if (! check_sorted (ikeys, nikeys)) {
00248         qsort (ikeys, nikeys, 4 * sizeof(double), korder) ;
00249       }
00250       break ;
00251 
00252     case opt_orientations :
00253       force_orientations = 1 ;
00254       break ;
00255 
00256     case opt_float_descriptors :
00257       floatDescriptors = 1 ;
00258       break ;
00259 
00260     default :
00261       abort() ;
00262     }
00263   }
00264 
00265   /* -----------------------------------------------------------------
00266    *                                                            Do job
00267    * -------------------------------------------------------------- */
00268   {
00269     VlSiftFilt        *filt ;
00270     vl_bool            first ;
00271     double            *frames = 0 ;
00272     void              *descr  = 0 ;
00273     int                nframes = 0, reserved = 0, i,j,q ;
00274 
00275     /* create a filter to process the image */
00276     filt = vl_sift_new (M, N, O, S, o_min) ;
00277 
00278     if (peak_thresh >= 0) vl_sift_set_peak_thresh (filt, peak_thresh) ;
00279     if (edge_thresh >= 0) vl_sift_set_edge_thresh (filt, edge_thresh) ;
00280     if (norm_thresh >= 0) vl_sift_set_norm_thresh (filt, norm_thresh) ;
00281     if (magnif      >= 0) vl_sift_set_magnif      (filt, magnif) ;
00282     if (window_size >= 0) vl_sift_set_window_size (filt, window_size) ;
00283 
00284     if (verbose) {
00285       mexPrintf("vl_sift: filter settings:\n") ;
00286       mexPrintf("vl_sift:   octaves      (O)      = %d\n",
00287                 vl_sift_get_noctaves      (filt)) ;
00288       mexPrintf("vl_sift:   levels       (S)      = %d\n",
00289                 vl_sift_get_nlevels       (filt)) ;
00290       mexPrintf("vl_sift:   first octave (o_min)  = %d\n",
00291                 vl_sift_get_octave_first  (filt)) ;
00292       mexPrintf("vl_sift:   edge thresh           = %g\n",
00293                 vl_sift_get_edge_thresh   (filt)) ;
00294       mexPrintf("vl_sift:   peak thresh           = %g\n",
00295                 vl_sift_get_peak_thresh   (filt)) ;
00296       mexPrintf("vl_sift:   norm thresh           = %g\n",
00297                 vl_sift_get_norm_thresh   (filt)) ;
00298       mexPrintf("vl_sift:   window size           = %g\n",
00299                 vl_sift_get_window_size   (filt)) ;
00300       mexPrintf("vl_sift:   float descriptor      = %d\n",
00301                 floatDescriptors) ;
00302 
00303       mexPrintf((nikeys >= 0) ?
00304                 "vl_sift: will source frames? yes (%d read)\n" :
00305                 "vl_sift: will source frames? no\n", nikeys) ;
00306       mexPrintf("vl_sift: will force orientations? %s\n",
00307                 force_orientations ? "yes" : "no") ;
00308     }
00309 
00310     /* ...............................................................
00311      *                                             Process each octave
00312      * ............................................................ */
00313     i     = 0 ;
00314     first = 1 ;
00315     while (1) {
00316       int                   err ;
00317       VlSiftKeypoint const *keys  = 0 ;
00318       int                   nkeys = 0 ;
00319 
00320       if (verbose) {
00321         mexPrintf ("vl_sift: processing octave %d\n",
00322                    vl_sift_get_octave_index (filt)) ;
00323       }
00324 
00325       /* Calculate the GSS for the next octave .................... */
00326       if (first) {
00327         err   = vl_sift_process_first_octave (filt, data) ;
00328         first = 0 ;
00329       } else {
00330         err   = vl_sift_process_next_octave  (filt) ;
00331       }
00332 
00333       if (err) break ;
00334 
00335       if (verbose > 1) {
00336         mexPrintf("vl_sift: GSS octave %d computed\n",
00337                   vl_sift_get_octave_index (filt));
00338       }
00339 
00340       /* Run detector ............................................. */
00341       if (nikeys < 0) {
00342         vl_sift_detect (filt) ;
00343 
00344         keys  = vl_sift_get_keypoints  (filt) ;
00345         nkeys = vl_sift_get_nkeypoints (filt) ;
00346         i     = 0 ;
00347 
00348         if (verbose > 1) {
00349           printf ("vl_sift: detected %d (unoriented) keypoints\n", nkeys) ;
00350         }
00351       } else {
00352         nkeys = nikeys ;
00353       }
00354 
00355       /* For each keypoint ........................................ */
00356       for (; i < nkeys ; ++i) {
00357         double                angles [4] ;
00358         int                   nangles ;
00359         VlSiftKeypoint        ik ;
00360         VlSiftKeypoint const *k ;
00361 
00362         /* Obtain keypoint orientations ........................... */
00363         if (nikeys >= 0) {
00364           vl_sift_keypoint_init (filt, &ik,
00365                                  ikeys [4 * i + 1] - 1,
00366                                  ikeys [4 * i + 0] - 1,
00367                                  ikeys [4 * i + 2]) ;
00368 
00369           if (ik.o != vl_sift_get_octave_index (filt)) {
00370             break ;
00371           }
00372 
00373           k = &ik ;
00374 
00375           /* optionally compute orientations too */
00376           if (force_orientations) {
00377             nangles = vl_sift_calc_keypoint_orientations
00378               (filt, angles, k) ;
00379           } else {
00380             angles [0] = VL_PI / 2 - ikeys [4 * i + 3] ;
00381             nangles    = 1 ;
00382           }
00383         } else {
00384           k = keys + i ;
00385           nangles = vl_sift_calc_keypoint_orientations
00386             (filt, angles, k) ;
00387         }
00388 
00389         /* For each orientation ................................... */
00390         for (q = 0 ; q < nangles ; ++q) {
00391           vl_sift_pix  buf [128] ;
00392           vl_sift_pix rbuf [128] ;
00393 
00394           /* compute descriptor (if necessary) */
00395           if (nout > 1) {
00396             vl_sift_calc_keypoint_descriptor (filt, buf, k, angles [q]) ;
00397             transpose_descriptor (rbuf, buf) ;
00398           }
00399 
00400           /* make enough room for all these keypoints and more */
00401           if (reserved < nframes + 1) {
00402             reserved += 2 * nkeys ;
00403             frames = mxRealloc (frames, 4 * sizeof(double) * reserved) ;
00404             if (nout > 1) {
00405               if (! floatDescriptors) {
00406                 descr  = mxRealloc (descr,  128 * sizeof(vl_uint8) * reserved) ;
00407               } else {
00408                 descr  = mxRealloc (descr,  128 * sizeof(float) * reserved) ;
00409               }
00410             }
00411           }
00412 
00413           /* Save back with MATLAB conventions. Notice tha the input
00414            * image was the transpose of the actual image. */
00415           frames [4 * nframes + 0] = k -> y + 1 ;
00416           frames [4 * nframes + 1] = k -> x + 1 ;
00417           frames [4 * nframes + 2] = k -> sigma ;
00418           frames [4 * nframes + 3] = VL_PI / 2 - angles [q] ;
00419 
00420           if (nout > 1) {
00421             if (! floatDescriptors) {
00422               for (j = 0 ; j < 128 ; ++j) {
00423                 float x = 512.0F * rbuf [j] ;
00424                 x = (x < 255.0F) ? x : 255.0F ;
00425                 ((vl_uint8*)descr) [128 * nframes + j] = (vl_uint8) x ;
00426               }
00427             } else {
00428               for (j = 0 ; j < 128 ; ++j) {
00429                 float x = 512.0F * rbuf [j] ;
00430                 ((float*)descr) [128 * nframes + j] = x ;
00431               }
00432             }
00433           }
00434 
00435           ++ nframes ;
00436         } /* next orientation */
00437       } /* next keypoint */
00438     } /* next octave */
00439 
00440     if (verbose) {
00441       mexPrintf ("vl_sift: found %d keypoints\n", nframes) ;
00442     }
00443 
00444     /* ...............................................................
00445      *                                                       Save back
00446      * ............................................................ */
00447 
00448     {
00449       mwSize dims [2] ;
00450 
00451       /* create an empty array */
00452       dims [0] = 0 ;
00453       dims [1] = 0 ;
00454       out[OUT_FRAMES] = mxCreateNumericArray
00455         (2, dims, mxDOUBLE_CLASS, mxREAL) ;
00456 
00457       /* set array content to be the frames buffer */
00458       dims [0] = 4 ;
00459       dims [1] = nframes ;
00460       mxSetPr         (out[OUT_FRAMES], frames) ;
00461       mxSetDimensions (out[OUT_FRAMES], dims, 2) ;
00462 
00463       if (nout > 1) {
00464 
00465         /* create an empty array */
00466         dims [0] = 0 ;
00467         dims [1] = 0 ;
00468         out[OUT_DESCRIPTORS]= mxCreateNumericArray
00469           (2, dims,
00470            floatDescriptors ? mxSINGLE_CLASS : mxUINT8_CLASS,
00471            mxREAL) ;
00472 
00473         /* set array content to be the descriptors buffer */
00474         dims [0] = 128 ;
00475         dims [1] = nframes ;
00476         mxSetData       (out[OUT_DESCRIPTORS], descr) ;
00477         mxSetDimensions (out[OUT_DESCRIPTORS], dims, 2) ;
00478       }
00479     }
00480 
00481     /* cleanup */
00482     vl_sift_delete (filt) ;
00483 
00484     if (ikeys_array)
00485       mxDestroyArray(ikeys_array) ;
00486 
00487   } /* end: do job */
00488 }


libvlfeat
Author(s): Andrea Vedaldi
autogenerated on Thu Jun 6 2019 20:25:51