00001
00007
00008
00009
00010
00011
00012
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
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
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 ;
00072 int const BP = 4 ;
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
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
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
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
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
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
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
00356 for (; i < nkeys ; ++i) {
00357 double angles [4] ;
00358 int nangles ;
00359 VlSiftKeypoint ik ;
00360 VlSiftKeypoint const *k ;
00361
00362
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
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
00390 for (q = 0 ; q < nangles ; ++q) {
00391 vl_sift_pix buf [128] ;
00392 vl_sift_pix rbuf [128] ;
00393
00394
00395 if (nout > 1) {
00396 vl_sift_calc_keypoint_descriptor (filt, buf, k, angles [q]) ;
00397 transpose_descriptor (rbuf, buf) ;
00398 }
00399
00400
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
00414
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 }
00437 }
00438 }
00439
00440 if (verbose) {
00441 mexPrintf ("vl_sift: found %d keypoints\n", nframes) ;
00442 }
00443
00444
00445
00446
00447
00448 {
00449 mwSize dims [2] ;
00450
00451
00452 dims [0] = 0 ;
00453 dims [1] = 0 ;
00454 out[OUT_FRAMES] = mxCreateNumericArray
00455 (2, dims, mxDOUBLE_CLASS, mxREAL) ;
00456
00457
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
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
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
00482 vl_sift_delete (filt) ;
00483
00484 if (ikeys_array)
00485 mxDestroyArray(ikeys_array) ;
00486
00487 }
00488 }